Skip to content

Commit

Permalink
Merge pull request #141 from traPtitech/feat/request_detail
Browse files Browse the repository at this point in the history
申請詳細ページをFigmaに合わせる
  • Loading branch information
mehm8128 authored Jun 23, 2024
2 parents 581e775 + 58def1b commit 87eafe4
Show file tree
Hide file tree
Showing 40 changed files with 804 additions and 687 deletions.
49 changes: 20 additions & 29 deletions src/components/modal/StatusChangeModal.vue
Original file line number Diff line number Diff line change
@@ -1,67 +1,58 @@
<script lang="ts" setup>
import { storeToRefs } from 'pinia'
import { ref } from 'vue'
import { useToast } from 'vue-toastification'
import { useRequestDetailStore } from '/@/stores/requestDetail'
import MarkdownTextarea from '/@/components/shared/MarkdownTextarea.vue'
import SimpleButton from '/@/components/shared/SimpleButton.vue'
import StatusChip from '/@/components/shared/StatusChip.vue'
import { changeStatusUsecase } from '/@/features/request/usecase'
import type { RequestStatus } from '/@/features/requestStatus/model'
import type { RequestDetail } from '/@/features/request/model'
interface Props {
const props = defineProps<{
request: RequestDetail
nextStatus: RequestStatus
}
const props = defineProps<Props>()
}>()
const emit = defineEmits<{
(e: 'closeModal'): void
}>()
const toast = useToast()
const requestDetailStore = useRequestDetailStore()
const { request } = storeToRefs(requestDetailStore)
const comment = ref('')
async function putStatus(nextStatus: RequestStatus, comment: string) {
const putStatus = async (nextStatus: RequestStatus, comment: string) => {
try {
if (request.value === undefined) {
throw new Error('request is undefined')
}
await changeStatusUsecase(request.value.id, nextStatus, comment)
await changeStatusUsecase(props.request.id, nextStatus, comment)
toast.success('申請の状態を変更しました')
emit('closeModal')
} catch (e) {
if (e instanceof Error) {
toast.error(e.message)
}
} catch {
toast.error('変更に失敗しました')
}
}
</script>

<template>
<div
v-if="request"
class="absolute inset-0 m-auto h-3/5 w-1/2 bg-white p-4 shadow-lg">
class="absolute inset-0 m-auto h-3/5 w-1/2 bg-white shadow-lg flex flex-col gap-6 pt-4 px-12">
<h1 class="text-center text-3xl">申請の状態変更</h1>
<div class="mx-12 mt-8 flex flex-col justify-around gap-4">
<div class="mb-4 flex items-center">
申請の状態を
<div class="flex flex-col gap-4">
<div class="flex items-center gap-1">
<span>申請の状態を</span>
<StatusChip class="mx-1" has-text :status="request.status" />
から
<span>から</span>
<StatusChip class="mx-1" has-text :status="props.nextStatus" />
へ変更します
<span>へ変更します</span>
</div>
<MarkdownTextarea v-model="comment" auto-focus placeholder="コメント" />
<div class="mt-4 text-center">
<MarkdownTextarea
v-model="comment"
auto-focus
placeholder="コメントを入力" />
<div class="flex justify-end">
<SimpleButton
class="mb-4 w-60"
font-size="xl"
padding="sm"
type="success"
@click="putStatus(nextStatus, comment)">
申請の状態を変更する
</SimpleButton>
Expand Down
36 changes: 16 additions & 20 deletions src/components/requestDetail/CommentLog.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<script lang="ts" setup>
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { useUserStore } from '/@/stores/user'
Expand All @@ -11,35 +9,33 @@ import MarkdownIt from '/@/components//shared/MarkdownIt.vue'
import UserIcon from '/@/components/shared/UserIcon.vue'
import type { RequestComment } from '/@/features/requestComment/model'
interface Props {
const props = defineProps<{
comment: RequestComment
}
const props = defineProps<Props>()
}>()
const formattedDateAndTime = formatDateAndTime(props.comment.createdAt)
const userStore = useUserStore()
const { userMap } = storeToRefs(userStore)
const route = useRoute()
const hash = computed(() => route.hash.substring(1))
</script>

<template>
<div :id="comment.id" class="flex w-full p-2">
<UserIcon class="w-12" :name="userMap[comment.user]" />
<div class="w-full pl-2">
<div class="flex h-12 items-center justify-between">
{{ userMap[comment.user] }}がコメントしました。
<span>
{{ formattedDateAndTime }}
</span>
<div :id="comment.id" class="w-full flex flex-col gap-3">
<div class="flex w-full items-center">
<div class="flex items-center gap-4 flex-1">
<UserIcon class="w-12" :name="userMap[comment.user]" />
<div>
<span class="font-bold">{{ userMap[comment.user] }}</span>
がコメントしました
</div>
</div>
<time class="text-gray-400" :datetime="comment.createdAt.toISO() ?? ''">
{{ formattedDateAndTime }}
</time>
</div>
<div class="ml-15">
<MarkdownIt
:class="`border border-zinc-300 p-1 ${
hash === comment.id && 'border-3 border border-yellow-300'
}`"
class="border border-zinc-300 px-4 py-3 rounded-lg"
:text="comment.comment" />
</div>
</div>
Expand Down
28 changes: 13 additions & 15 deletions src/components/requestDetail/NewComment.vue
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
<script lang="ts" setup>
import { storeToRefs } from 'pinia'
import { useRequestDetailStore } from '/@/stores/requestDetail'
import { useNewComment } from '/@/components/requestDetail/composables/useNewComment'
import MarkdownTextarea from '/@/components/shared/MarkdownTextarea.vue'
import SimpleButton from '/@/components/shared/SimpleButton.vue'
import type { RequestDetail } from '/@/features/request/model'
const props = defineProps<{
request: RequestDetail
}>()
const requestDetailStore = useRequestDetailStore()
const { request } = storeToRefs(requestDetailStore)
const { comment, isSending, submit } = useNewComment(request.value?.id ?? '')
const { comment, isSending, submit } = useNewComment(props.request.id)
</script>

<template>
<form class="mx-4 w-full">
<MarkdownTextarea v-model="comment" placeholder="コメント" />
<div class="mt-1">
<div class="w-full">
<MarkdownTextarea v-model="comment">
<SimpleButton
class="ml-auto"
:disabled="isSending"
font-size="md"
padding="sm"
@click.prevent="submit">
padding="md"
type="success"
@click="submit">
コメントする
</SimpleButton>
</div>
</form>
</MarkdownTextarea>
</div>
</template>
20 changes: 0 additions & 20 deletions src/components/requestDetail/RequestAmount.vue

This file was deleted.

102 changes: 66 additions & 36 deletions src/components/requestDetail/RequestContent.vue
Original file line number Diff line number Diff line change
@@ -1,58 +1,88 @@
<script lang="ts" setup>
import { storeToRefs } from 'pinia'
import { useRequestDetailStore } from '/@/stores/requestDetail'
import { useUserStore } from '/@/stores/user'
import InputTextarea from '/@/components/shared/InputTextarea.vue'
import MarkdownIt from '/@/components/shared/MarkdownIt.vue'
import SimpleButton from '/@/components/shared/SimpleButton.vue'
import type { EditMode } from '/@/pages/composables/useRequestDetail'
import { formatDateAndTime } from '/@/lib/date'
interface Props {
isEditMode: boolean
}
import MarkdownIt from '/@/components//shared/MarkdownIt.vue'
import UserIcon from '/@/components/shared/UserIcon.vue'
import type { RequestDetail } from '/@/features/request/model'
import { ref } from 'vue'
import { editRequestUsecase } from '/@/features/request/usecase'
import EditButton from '/@/components/shared/EditButton.vue'
import MarkdownTextarea from '/@/components/shared/MarkdownTextarea.vue'
import SimpleButton from '/@/components/shared/SimpleButton.vue'
import { useToast } from 'vue-toastification'
import { useRequest } from '/@/features/request/composables'
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'changeEditMode', value: EditMode): void
const props = defineProps<{
request: RequestDetail
}>()
const formattedDateAndTime = formatDateAndTime(props.request.createdAt)
const userStore = useUserStore()
const requestDetailStore = useRequestDetailStore()
const { isRequestCreator } = requestDetailStore
const { request, editedValue } = storeToRefs(requestDetailStore)
const { userMap } = storeToRefs(userStore)
const toast = useToast()
const { isRequestCreator } = useRequest(props.request)
const { me } = storeToRefs(userStore)
const hasAuthority = isRequestCreator(me.value)
const hasAuthority = isRequestCreator.value(me.value)
const isEditMode = ref(false)
const editedContent = ref(props.request.content)
const toggleEditContent = () => {
if (isEditMode.value) {
editedContent.value = props.request.content
}
isEditMode.value = !isEditMode.value
}
const handleUpdateContent = async () => {
try {
await editRequestUsecase(props.request.id, {
...props.request,
group: props.request.group?.id ?? null, // TODO: 関係ないときでも書かないといけないので、デフォルトの値をどこかに置いておく
content: editedContent.value
})
toast.success('更新しました')
} catch {
toast.error('更新に失敗しました')
}
isEditMode.value = false
}
</script>

<template>
<div class="flex w-3/5">
詳細:
<div v-if="!props.isEditMode && request" class="flex flex-grow items-end">
<div class="w-full flex flex-col gap-3">
<div class="flex w-full items-center">
<div class="flex items-center gap-4 flex-1">
<UserIcon class="w-12" :name="userMap[request.createdBy]" />
<div>
<span class="font-bold">{{ userMap[request.createdBy] }}</span>
がこの申請を作成しました
</div>
</div>
<time class="text-gray-400" :datetime="request.createdAt.toISO() ?? ''">
{{ formattedDateAndTime }}
</time>
</div>
<div class="ml-15 flex items-start gap-2">
<MarkdownIt
class="h-32 flex-grow overflow-y-scroll border border-gray-300 pl-1"
v-if="!isEditMode"
class="border border-zinc-300 px-4 py-3 rounded-lg flex-1"
:text="request.content" />
<SimpleButton
<MarkdownTextarea
v-else
v-model="editedContent"
auto-focus
class="flex-1" />
<EditButton
v-if="hasAuthority"
class="ml-2"
font-size="sm"
padding="sm"
@click="emit('changeEditMode', 'content')">
編集
</SimpleButton>
:is-edit-mode="isEditMode"
@click="toggleEditContent" />
</div>
<div v-else class="flex flex-grow items-end">
<InputTextarea
v-model="editedValue.content"
class="h-30 flex-grow resize-none"
placeholder="詳細" />
<SimpleButton
class="ml-2"
font-size="sm"
padding="sm"
@click.stop="emit('changeEditMode', '')">
<div class="flex justify-end">
<SimpleButton v-if="isEditMode" padding="sm" @click="handleUpdateContent">
完了
</SimpleButton>
</div>
Expand Down
Loading

0 comments on commit 87eafe4

Please sign in to comment.