diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ConfirmationCompo.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ConfirmationCompo.tsx index 32e6be0..cf85c96 100644 --- a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ConfirmationCompo.tsx +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ConfirmationCompo.tsx @@ -2,6 +2,7 @@ import { IWorkoutConfirmationPageProps } from '@/types/workoutConfirmation'; import ConfirmationProfile from './ConfirmationProfile'; import ConfirmationCompoObjection from './ConfirmationCompoObjection'; import ConfirmationCompoConfirm from './ConfirmationCompoConfirm'; +import ConfirmationCompoTime from './ConfirmationCompoTime'; interface IConfirmationCompoProps { workoutConfirmationPage: IWorkoutConfirmationPageProps; @@ -30,15 +31,9 @@ export default function ConfirmationCompo({ workspaceId={workspaceId} /> )} -
- - {workoutConfirmationPage.createdAt.substring(11, 16)} - -
+ ); diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ConfirmationCompoTime.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ConfirmationCompoTime.tsx new file mode 100644 index 0000000..10a30c1 --- /dev/null +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ConfirmationCompoTime.tsx @@ -0,0 +1,21 @@ +import { IWorkoutConfirmationPageProps } from '@/types/workoutConfirmation'; + +interface IConfirmationPageProps { + workoutConfirmationPage: IWorkoutConfirmationPageProps; +} + +export default function ConfirmationCompoTime({ + workoutConfirmationPage, +}: IConfirmationPageProps) { + return ( +
+ + {workoutConfirmationPage.createdAt.substring(11, 16)} + +
+ ); +} diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ScrollTop.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ScrollTop.tsx new file mode 100644 index 0000000..9347238 --- /dev/null +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/_components/ScrollTop.tsx @@ -0,0 +1,14 @@ +'use client'; + +import { usePathname } from 'next/navigation'; +import { useEffect } from 'react'; + +export default function ScrollTop() { + const pathName = usePathname(); + + useEffect(() => { + window.scrollTo(0, 0); + }, [pathName]); + + return null; +} diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/page.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/page.tsx index 443a7dd..cab5f6a 100644 --- a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/page.tsx +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/page.tsx @@ -10,64 +10,91 @@ import ObjectionBell from './_components/ObjectionBell'; import IsSameDateAsPrevious from './_components/IsSameDataAsPrevious'; import ConfirmationCompo from './_components/ConfirmationCompo'; import useInfiniteQuerys from '@/hooks/workoutConfirmation/ useInfiniteQuerys'; -import { useEffect, useRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; +import NoDataUI from '../../_components/NoDataUI'; export default function Page() { const workspaceId = useWorkoutIdFromParams(); - const [ref, inView] = useInView({ threshold: 0, delay: 0 }); + const [initialObserve, setInitialObserve] = useState(false); + + const [ref, inView] = useInView({ + threshold: 0.1, + delay: 500, + }); const scrollBottomRef = useRef(null); - const isInitialRender = useRef(true); + const isInitialRender = useRef(true); const workoutConfirmation = useInfiniteQuerys({ queryKey: ['workoutConfirmations', workspaceId], dataReqFn: workoutConfirmations, params: { workspaceId }, - inView, + inView: inView && initialObserve, }); - const workoutConfirmationPages = workoutConfirmation?.pages.flatMap( - (pages) => pages.data.data - ); + const workoutConfirmationPages = workoutConfirmation?.pages + .slice() + .reverse() + .flatMap((pages) => pages.data.data); + const workoutConfirmationVoteInCompletionCount = workoutConfirmation?.pages.flatMap( (pages) => pages.data.voteIncompletionCount ); useEffect(() => { - if (scrollBottomRef.current && isInitialRender) { - scrollBottomRef.current?.scrollIntoView({ behavior: 'auto' }); - isInitialRender.current = false; - } + if ( + isInitialRender.current && + workoutConfirmationPages && + workoutConfirmationPages.length + ) + setTimeout(() => { + scrollBottomRef.current?.scrollIntoView({ + behavior: 'auto', + }); + isInitialRender.current = false; + setTimeout(() => { + setInitialObserve(true); + }, 100); + }, 100); }, [workoutConfirmationPages]); return (
-
- {workoutConfirmationPages?.map( - ( - workoutConfirmationPage: IWorkoutConfirmationPageProps, - index: number - ) => { - return ( -
- - -
- ); - } + {workoutConfirmationPages?.length === 0 ? ( +
+ +
+ ) : ( +
+
+ {workoutConfirmationPages?.map( + ( + workoutConfirmationPage: IWorkoutConfirmationPageProps, + index: number + ) => { + return ( +
+ + +
+ ); + } + )} +
+
)}
-
); } diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfimationDetailImage.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfimationDetailImage.tsx new file mode 100644 index 0000000..ba781e0 --- /dev/null +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfimationDetailImage.tsx @@ -0,0 +1,29 @@ +import Image from 'next/image'; + +import confirmDetailNoImage from '@/../public/svgs/workspace/workspaceConfirmaion/confirmDetailNoImage.svg'; +import { IWorkspaceConfirmationDetailProps } from '@/types/workoutConfirmation'; + +interface IConfirmationDetailImage { + workspaceConfirmationDetail: IWorkspaceConfirmationDetailProps | undefined; +} + +export default function ConfirmationDetailImage({ + workspaceConfirmationDetail, +}: IConfirmationDetailImage) { + return ( +
+ {workspaceConfirmationDetail?.workoutConfirmationImageUrl === '' ? ( + confirmDetailNoImage + ) : ( + Image src} + loading='lazy' + sizes='360px' + fill + /> + )} +
+ ); +} diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailCompo.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailCompo.tsx new file mode 100644 index 0000000..5a3923e --- /dev/null +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailCompo.tsx @@ -0,0 +1,49 @@ +'use client'; + +import { useQuery } from '@tanstack/react-query'; + +import ConfirmationDetailImage from './ConfimationDetailImage'; +import ConfirmationDetailProfile from './ConfirmationDetailProfile'; +import { IWorkspaceConfirmationDetailProps } from '@/types/workoutConfirmation'; +import useWorkoutIdFromParams from '@/hooks/workoutHistory/useWorkoutIdFromParams'; +import { workoutConfirmaionsDetail } from '@/api/workspaceConfirmaion'; + +interface IConfirmationDetailCompoProps { + workoutConfirmationId: number; +} + +export default function ConfirmationDetailCompo({ + workoutConfirmationId, +}: IConfirmationDetailCompoProps) { + const workspaceId = useWorkoutIdFromParams(); + + const { data: workspaceConfirmationDetail } = useQuery<{ + data: IWorkspaceConfirmationDetailProps; + }>({ + queryKey: [ + 'workspaceConfimationDetail', + workspaceId, + workoutConfirmationId, + ], + queryFn: () => + workoutConfirmaionsDetail({ + workspaceId, + workoutConfirmationId, + }), + }); + return ( +
+ +
+ + {workspaceConfirmationDetail?.data.comment} + + +
+
+ ); +} diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailObjectionInput.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailObjectionInput.tsx new file mode 100644 index 0000000..76c49c7 --- /dev/null +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailObjectionInput.tsx @@ -0,0 +1,102 @@ +'use client'; + +import { workoutObjectionReason } from '@/api/workspaceConfirmaion'; +import { + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import useWorkoutIdFromParams from '@/hooks/workoutHistory/useWorkoutIdFromParams'; +import { DialogDescription } from '@radix-ui/react-dialog'; +import { useMutation } from '@tanstack/react-query'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +interface IConfirmationDetailObjectionInputProps { + workoutConfirmationId: number; +} + +export default function ConfirmationDetailObjectionInput({ + workoutConfirmationId, +}: IConfirmationDetailObjectionInputProps) { + const router = useRouter(); + const [reasonInput, setReasonInput] = useState(''); + const workspaceId = useWorkoutIdFromParams(); + + const objectionReason = useMutation({ + mutationFn: workoutObjectionReason, + onSuccess: (data) => { + console.log('Success:', data); + alert('이의 신청이 성공적으로 제출되었습니다.'); + router.push(`/workspace/${workspaceId}/workspaceConfirmation`); + }, + onError: (error) => { + console.error('Error:', error); + alert('이의 신청 제출 중 오류가 발생했습니다.'); + }, + }); + + const handleReasonPost = (event: React.MouseEvent) => { + event.preventDefault(); + + if (reasonInput.length < 10) { + alert('10자 이상 작성하셔야 합니다.'); + } + + if (reasonInput.length >= 10) { + objectionReason.mutate({ + workspaceId, + workoutConfirmationId, + objectionReason: reasonInput, + }); + } + }; + + return ( + + + + + 이의 신청 이유를 입력해주세요. + + +
+ setReasonInput(e.target.value)} + /> + {reasonInput.length <= 10 ? ( + + 이의 신청 이유는 10자 이상 작성해주세요. + + ) : ( + <> + )} +
+ +
+
+
+ + cancel + +
+ +
+
+
+
+ ); +} diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailProfile.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailProfile.tsx new file mode 100644 index 0000000..f1feb5e --- /dev/null +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/ConfirmationDetailProfile.tsx @@ -0,0 +1,26 @@ +import ConfirmationProfileImg from '../../_components/ConfirmationProfileImg'; +import { IWorkspaceConfirmationDetailProps } from '@/types/workoutConfirmation'; + +interface IConfirmationDetailProfileProps { + workspaceConfirmationDetail: IWorkspaceConfirmationDetailProps | undefined; +} + +export default function ConfirmationDetailProfile({ + workspaceConfirmationDetail, +}: IConfirmationDetailProfileProps) { + return ( +
+ +
+ + {workspaceConfirmationDetail?.nickname} + + + {workspaceConfirmationDetail?.loginId} + +
+
+ ); +} diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/confirmationObjection/ConfirmationObjectionCompo.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/confirmationObjection/ConfirmationObjectionCompo.tsx new file mode 100644 index 0000000..e87918e --- /dev/null +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/confirmationObjection/ConfirmationObjectionCompo.tsx @@ -0,0 +1,180 @@ +'use client'; + +import { useState } from 'react'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; + +import Image from 'next/image'; +import { ReadonlyURLSearchParams } from 'next/navigation'; +import { DialogTrigger } from '@/components/ui/dialog'; + +import objectedWorkoutVoteIcon from '@/../public/svgs/workspace/workspaceConfirmaion/objectedWorkoutVoteIcon.svg'; +import RemaineTime from '../RemaineTime'; +import { + workoutObjections, + workoutObjectionsVote, +} from '@/api/workspaceConfirmaion'; +import useWorkoutIdFromParams from '@/hooks/workoutHistory/useWorkoutIdFromParams'; +import ConfirmationObjectionProgressBars from './ConfirmationObjectionProgressBars'; +import { IWorkoutObjectionProps } from '@/types/workoutConfirmation'; + +interface IConfirmationObjectionCompo { + seachParams: ReadonlyURLSearchParams; +} + +export default function ConfirmationObjectionCompo({ + seachParams, +}: IConfirmationObjectionCompo) { + const workspaceId = useWorkoutIdFromParams(); + const [isObjectionVote, setIsObjectionVote] = useState(null); + const objectionId = parseInt(seachParams.get('objectionId') || '0', 10); + + const isObjection = seachParams.get('isObjection') === 'false'; + + const { data: workoutObjection } = useQuery<{ data: IWorkoutObjectionProps }>( + { + queryKey: ['workoutObjection', workspaceId, objectionId], + queryFn: () => + workoutObjections({ + workspaceId, + objectionId, + }), + enabled: !isObjection, + } + ); + + const queryClient = useQueryClient(); + + const OBJECTTIONVOTE_QUERYKEY = { + workoutObjection: (workspaceId: number, objectionId: number) => [ + 'workoutObjection', + workspaceId, + objectionId, + ], + }; + + const objectionVote = useMutation({ + mutationFn: workoutObjectionsVote, + onSuccess: (data) => { + console.log('Success:', data); + alert('이의 신청 투표가 성공적으로 제출되었습니다.'); + + queryClient.invalidateQueries({ + queryKey: OBJECTTIONVOTE_QUERYKEY.workoutObjection( + workspaceId, + objectionId + ), + }); + }, + + onError: (error) => { + console.error('Error:', error); + alert('이의 신청 투표 중 오류가 발생했습니다.'); + }, + }); + + const handleVotePost = (event: React.MouseEvent) => { + event.preventDefault(); + + if (isObjectionVote === null) { + alert('이의신청 투표를 진행해주세요.'); + } + + if (isObjectionVote !== null) { + objectionVote.mutate({ + workspaceId, + objectionId, + objectionVote: isObjectionVote, + }); + } + }; + + return ( +
+ {isObjection ? ( +
+ + + +
+ ) : ( +
+
+ objectedWorkoutVoteIcon + + {!workoutObjection?.data.inInProgress + ? `투표 결과: ${ + workoutObjection?.data.confirmationCompletion + ? '찬성' + : '반대' + }` + : '이의 신청 투표'} + +
+

+ {workoutObjection?.data.reason} +

+
+ + {!workoutObjection?.data.inInProgress ? ( + '투표 종료' + ) : ( + <> + 투표 종료까지{' '} + + + )} + {' * '} + {workoutObjection?.data.voteParticipationCount}명 참여 + +
+ {!workoutObjection?.data.inInProgress ? ( +
+ 투표 종료 +
+ ) : ( +
+ +
+ {workoutObjection?.data.voteCompletion ? ( +
투표완료
+ ) : ( + + )} +
+
+ )} +
+ )} +
+ ); +} diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/confirmationObjection/ConfirmationObjectionProgressBars.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/confirmationObjection/ConfirmationObjectionProgressBars.tsx new file mode 100644 index 0000000..e83252e --- /dev/null +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/_components/confirmationObjection/ConfirmationObjectionProgressBars.tsx @@ -0,0 +1,48 @@ +import { IWorkoutObjectionProps } from '@/types/workoutConfirmation'; +import ProgressBar from '../ProgressBar'; +import { Dispatch, SetStateAction } from 'react'; + +interface IConfirmationObjectionProgressBarsProps { + isObjectionVote: boolean | null; + setIsObjectionVote: Dispatch>; + workoutObjection: IWorkoutObjectionProps; +} + +export default function ConfirmationObjectionProgressBars({ + isObjectionVote, + setIsObjectionVote, + workoutObjection, +}: IConfirmationObjectionProgressBarsProps) { + const handleVote = (isObjection: boolean) => { + setIsObjectionVote((prev) => (prev === isObjection ? null : isObjection)); + }; + + const appovalCount = + (workoutObjection?.approvalCount / workoutObjection?.headCount) * 100; + const rejectionCount = + (workoutObjection?.rejectionCount / workoutObjection?.headCount) * 100; + + if (appovalCount > 100 || rejectionCount > 100) { + appovalCount === 100 || rejectionCount === 100; + } + return ( +
+ { + if (!workoutObjection?.voteCompletion) handleVote(true); + }} + isObjectionVote={isObjectionVote === true} + /> + { + if (!workoutObjection?.voteCompletion) handleVote(false); + }} + isObjectionVote={isObjectionVote === false} + /> +
+ ); +} diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/page.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/page.tsx index fea5dde..78f3197 100644 --- a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/page.tsx +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceConfirmation/workspaceConfirmaionDetail/page.tsx @@ -1,345 +1,33 @@ 'use client'; -import Image from 'next/image'; -import { useState } from 'react'; +import { Dialog } from '@/components/ui/dialog'; -import { - Dialog, - DialogClose, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from '@/components/ui/dialog'; +import { useSearchParams } from 'next/navigation'; -import objectedWorkoutVoteIcon from '@/../public/svgs/workspace/workspaceConfirmaion/objectedWorkoutVoteIcon.svg'; -import confirmDetailNoImage from '@/../public/svgs/workspace/workspaceConfirmaion/confirmDetailNoImage.svg'; - -import { DialogDescription } from '@radix-ui/react-dialog'; -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { useRouter, useSearchParams } from 'next/navigation'; -import useWorkoutIdFromParams from '@/hooks/workoutHistory/useWorkoutIdFromParams'; -import { - workoutConfirmaionsDetail, - workoutObjectionReason, - workoutObjections, - workoutObjectionsVote, -} from '@/api/workspaceConfirmaion'; -import ProgressBar from './_components/ProgressBar'; -import RemaineTime from './_components/RemaineTime'; -import ConfirmationProfileImg from '../_components/ConfirmationProfileImg'; +import ScrollTop from '../_components/ScrollTop'; +import ConfirmationObjectionCompo from './_components/confirmationObjection/ConfirmationObjectionCompo'; +import ConfirmationDetailCompo from './_components/ConfirmationDetailCompo'; +import ConfirmationDetailObjectionInput from './_components/ConfirmationDetailObjectionInput'; export default function Page() { - const [reasonInput, setReasonInput] = useState(''); - const [isObjectionVote, setIsObjection] = useState(null); - const router = useRouter(); - const workspaceId = useWorkoutIdFromParams(); const seachParams = useSearchParams(); const workoutConfirmationId = parseInt( seachParams.get('workoutConfirmationId') || '0', 10 ); - const isObjection = seachParams.get('isObjection') === 'false'; - - const objectionId = parseInt(seachParams.get('objectionId') || '0', 10); - - const { data: workspaceConfirmationDetail } = useQuery({ - queryKey: [ - 'workspaceConfimationDetail', - workspaceId, - workoutConfirmationId, - ], - queryFn: () => - workoutConfirmaionsDetail({ - workspaceId, - workoutConfirmationId, - }), - }); - - const { data: workoutObjection } = useQuery({ - queryKey: ['workoutObjection', workspaceId, objectionId], - queryFn: () => - workoutObjections({ - workspaceId, - objectionId, - }), - enabled: !isObjection, - }); - - const queryClient = useQueryClient(); - - const objectionReason = useMutation({ - mutationFn: workoutObjectionReason, - onSuccess: (data) => { - console.log('Success:', data); - alert('이의 신청이 성공적으로 제출되었습니다.'); - router.push(`/workspace/${workspaceId}/workspaceConfirmation`); - }, - onError: (error) => { - console.error('Error:', error); - alert('이의 신청 제출 중 오류가 발생했습니다.'); - }, - }); - - const handleReasonPost = (event: React.MouseEvent) => { - event.preventDefault(); - - if (reasonInput.length < 10) { - alert('10자 이상 작성하셔야 합니다.'); - } - - if (reasonInput.length >= 10) { - objectionReason.mutate({ - workspaceId, - workoutConfirmationId, - objectionReason: reasonInput, - }); - } - }; - - const handleVote = (isObjection: boolean) => { - setIsObjection((prev) => (prev === isObjection ? null : isObjection)); - }; - - const OBJECTTIONVOTE_QUERYKEY = { - workoutObjection: (workspaceId: number, objectionId: number) => [ - 'workoutObjection', - workspaceId, - objectionId, - ], - }; - - const objectionVote = useMutation({ - mutationFn: workoutObjectionsVote, - onSuccess: (data) => { - console.log('Success:', data); - alert('이의 신청 투표가 성공적으로 제출되었습니다.'); - - queryClient.invalidateQueries({ - queryKey: OBJECTTIONVOTE_QUERYKEY.workoutObjection( - workspaceId, - objectionId - ), - }); - }, - - onError: (error) => { - console.error('Error:', error); - alert('이의 신청 투표 중 오류가 발생했습니다.'); - }, - }); - - const handleVotePost = (event: React.MouseEvent) => { - event.preventDefault(); - - if (isObjectionVote === null) { - alert('이의신청 투표를 진행해주세요.'); - } - - if (isObjectionVote !== null) { - objectionVote.mutate({ - workspaceId, - objectionId, - objectionVote: isObjectionVote, - }); - } - }; - - const appovalCount = - (workoutObjection?.data.approvalCount / workoutObjection?.data.headCount) * - 100; - const rejectionCount = - (workoutObjection?.data.rejectionCount / workoutObjection?.data.headCount) * - 100; - if (appovalCount > 100 || rejectionCount > 100) { - appovalCount === 100 || rejectionCount === 100; - } return (
-
- -
- - {workspaceConfirmationDetail?.data.nickname} - - - {workspaceConfirmationDetail?.data.loginId} - -
-
-
- - {workspaceConfirmationDetail?.data.comment} - -
- {workspaceConfirmationDetail?.data.workoutConfirmationImageUrl === - '' ? ( - confirmDetailNoImage - ) : ( - Image src} - loading='lazy' - sizes='360px' - fill - /> - )} -
-
+ + {/* 이의 신청 팝업창 */} - {isObjection ? ( -
- - - -
- ) : ( -
-
- objectedWorkoutVoteIcon - - {!workoutObjection?.data.inInProgress - ? `투표 결과: ${ - workoutObjection?.data.confirmationCompletion - ? '찬성' - : '반대' - }` - : '이의 신청 투표'} - -
-

- {workoutObjection?.data.reason} -

-
- - {!workoutObjection?.data.inInProgress ? ( - '투표 종료' - ) : ( - <> - 투표 종료까지{' '} - - - )} - {' * '} - {workoutObjection?.data.voteParticipationCount}명 참여 - -
- {!workoutObjection?.data.inInProgress ? ( -
- 투표 종료 -
- ) : ( - <> - { - if (!workoutObjection?.data.voteCompletion) - handleVote(true); - }} - isObjectionVote={isObjectionVote === true} - /> - { - if (!workoutObjection?.data.voteCompletion) - handleVote(false); - }} - isObjectionVote={isObjectionVote === false} - /> -
- {workoutObjection?.data.voteCompletion ? ( -
투표완료
- ) : ( - - )} -
- - )} -
- )} + - - - - - 이의 신청 이유를 입력해주세요. - - -
- setReasonInput(e.target.value)} - /> - {reasonInput.length <= 10 ? ( - - 이의 신청 이유는 10자 이상 작성해주세요. - - ) : ( - <> - )} -
- -
-
-
- - cancel - -
- -
-
-
-
+
); diff --git a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceHistory/page.tsx b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceHistory/page.tsx index 4171dee..195529c 100644 --- a/src/app/(afterLogin)/workspace/[workspaceId]/workspaceHistory/page.tsx +++ b/src/app/(afterLogin)/workspace/[workspaceId]/workspaceHistory/page.tsx @@ -4,8 +4,6 @@ import Image from 'next/image'; import { useQuery } from '@tanstack/react-query'; import { useSearchParams } from 'next/navigation'; -import noGroup from '@/../public/svgs/noGroup.svg'; - import { workspaceHistoryDataConst } from '@/constants/queryKey'; import { workspaceHistorys } from '@/api/workspace'; @@ -17,6 +15,8 @@ import useWorkoutHistoryIds from '@/hooks/workoutHistory/useWorkoutHistoryIds'; import useWorkoutIdFromParams from '@/hooks/workoutHistory/useWorkoutIdFromParams'; import type { THistorys, TQueryTypes } from '@/types/workspaceHistory'; +import NoDataUI from '../../_components/NoDataUI'; +import ScrollTop from '../workspaceConfirmation/_components/ScrollTop'; function useUserInfo(): TQueryTypes { const searchParams = useSearchParams(); @@ -58,6 +58,7 @@ function Page() { return (
+ '} {workspaceHistoryDatas?.data.workoutHistories.length === 0 ? ( -
- noGroup - - 아직 운동 히스토리가 없습니다. - -
+ ) : (
{workspaceHistoryDatas?.data.workoutHistories.map( diff --git a/src/app/(afterLogin)/workspace/_components/NoDataUI.tsx b/src/app/(afterLogin)/workspace/_components/NoDataUI.tsx new file mode 100644 index 0000000..71b795b --- /dev/null +++ b/src/app/(afterLogin)/workspace/_components/NoDataUI.tsx @@ -0,0 +1,16 @@ +import Image from 'next/image'; + +import noGroup from '@/../public/svgs/noGroup.svg'; + +interface INoDataUI { + content: string; +} + +export default function NoDataUI({ content }: INoDataUI) { + return ( +
+ noGroup + {content} +
+ ); +} diff --git a/src/types/workoutConfirmation.ts b/src/types/workoutConfirmation.ts index 37ba7ae..3bad659 100644 --- a/src/types/workoutConfirmation.ts +++ b/src/types/workoutConfirmation.ts @@ -17,3 +17,24 @@ export interface IWorkoutConfirmationObjectionListPageProps { voteCompletion: boolean; workoutConfirmationId: number; } + +export interface IWorkspaceConfirmationDetailProps { + comment: string; + loginId: string; + nickname: string; + objectionId: number | null; + profileImageUrl: any; + workoutConfirmationImageUrl: any; +} + +export interface IWorkoutObjectionProps { + approvalCount: number; + confirmationCompletion: boolean | null; + deadline: string; + headCount: number; + inInProgress: boolean; + reason: string; + rejectionCount: number; + voteCompletion: boolean | null; + voteParticipationCount: number; +}