diff --git a/packages/web-domains/src/about-me/common/apis/mutates/useCreateHandWavings.ts b/packages/web-domains/src/about-me/common/apis/mutates/useCreateHandWavings.ts new file mode 100644 index 00000000..654e0763 --- /dev/null +++ b/packages/web-domains/src/about-me/common/apis/mutates/useCreateHandWavings.ts @@ -0,0 +1,20 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { Http } from '@/common/apis/base.api'; + +import { HAND_WAVINGS_STATUS_QUERY_KEY } from '../queries/useGetHandWavingsStatus'; + +interface Request { + meetingId: number; + receiverMemberId: number; +} + +export const useCreateHandWavings = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ meetingId, receiverMemberId }: Request) => + Http.POST(`/v1/meetings/${meetingId}/hand-wavings`, { receiverMemberId }), + onSuccess: (_, variable) => queryClient.invalidateQueries({ queryKey: [HAND_WAVINGS_STATUS_QUERY_KEY, variable] }), + }); +}; diff --git a/packages/web-domains/src/about-me/common/apis/queries/useGetHandWavingsStatus.ts b/packages/web-domains/src/about-me/common/apis/queries/useGetHandWavingsStatus.ts new file mode 100644 index 00000000..2f17e40c --- /dev/null +++ b/packages/web-domains/src/about-me/common/apis/queries/useGetHandWavingsStatus.ts @@ -0,0 +1,46 @@ +import { QueryClient, useQuery, UseQueryOptions } from '@tanstack/react-query'; + +import { Http } from '@/common/apis/base.api'; + +import { HandWavingStatusResponse } from '../schema/HandWavingStatusResponse'; + +interface Params { + meetingId: number; + receiverMemberId: number; +} + +interface QueryProps extends Params { + options?: UseQueryOptions; +} + +const queryFn = ({ meetingId, receiverMemberId }: Params) => + Http.GET(`/v1/meetings/${meetingId}/hand-wavings/receiver/${receiverMemberId}/status`); + +export const HAND_WAVINGS_STATUS_QUERY_KEY = 'HAND_WAVINGS_STATUS_QUERY_KEY '; + +export const useGetHandWavingsStatus = (props: QueryProps) => { + const { options, ...params } = props; + + return useQuery({ + queryKey: [HAND_WAVINGS_STATUS_QUERY_KEY, params], + queryFn: () => queryFn(params), + enabled: params.meetingId > 0, + staleTime: 1000 * 60 * 10, // 10분 + ...options, + }); +}; + +interface PrefetchProps extends Params { + queryClient: QueryClient; +} + +export const getHandWavingsStatusPrefetch = (props: PrefetchProps) => { + const { queryClient, ...params } = props; + + const prefetch = queryClient.prefetchQuery({ + queryKey: [HAND_WAVINGS_STATUS_QUERY_KEY, params], + queryFn: () => queryFn(params), + }); + + return prefetch; +}; diff --git a/packages/web-domains/src/about-me/common/apis/schema/HandWavingStatusResponse.ts b/packages/web-domains/src/about-me/common/apis/schema/HandWavingStatusResponse.ts new file mode 100644 index 00000000..710bf210 --- /dev/null +++ b/packages/web-domains/src/about-me/common/apis/schema/HandWavingStatusResponse.ts @@ -0,0 +1,4 @@ +export interface HandWavingStatusResponse { + HandWavingId: number; + status: 'REQUESTED' | 'ACCEPTED' | 'REJECTED'; +} diff --git a/packages/web-domains/src/about-me/features/containers/ScreenContainer.tsx b/packages/web-domains/src/about-me/features/containers/ScreenContainer.tsx index c3545d2c..9a419945 100644 --- a/packages/web-domains/src/about-me/features/containers/ScreenContainer.tsx +++ b/packages/web-domains/src/about-me/features/containers/ScreenContainer.tsx @@ -1,22 +1,53 @@ 'use client'; -import { colors, size } from '@sambad/sds/theme'; -import { Fragment } from 'react'; +import { colors, shadow, size } from '@sambad/sds/theme'; +import { Button } from '@sds/components'; +import { useCreateHandWavings } from '@/about-me/common/apis/mutates/useCreateHandWavings'; +import { useGetHandWavingsStatus } from '@/about-me/common/apis/queries/useGetHandWavingsStatus'; import { ActionBar } from '@/common/components/ActionBar/ActionBar'; +import { useGetFirstMeetingId } from '../hooks/useGetFirstMeetingId'; +import { useIsMyByParams } from '../hooks/useIsMyByParams'; + import { ProfileContainer } from './ProfileContainer'; import { SegmentedControlContainer } from './SegmentedControlContainer'; +import { handWavingButtonCss, screenRootCss } from './styles'; export const ScreenContainer = () => { + const { isMy, meetingMemberId } = useIsMyByParams(); + const { meetingId } = useGetFirstMeetingId(); + const { data: wavingStatusData, isSuccess: getWavingStatusSuccess } = useGetHandWavingsStatus({ + meetingId, + receiverMemberId: meetingMemberId, + }); + const { mutate, isSuccess: sendWavingSuccess } = useCreateHandWavings(); + + const isProgressHandWavings = sendWavingSuccess || wavingStatusData?.status === 'REQUESTED'; + + const handleHandWaving = () => { + mutate({ meetingId, receiverMemberId: meetingMemberId }); + }; + return ( - - +
+
- + {!isMy && getWavingStatusSuccess && ( + + )} +
); }; diff --git a/packages/web-domains/src/about-me/features/containers/styles.ts b/packages/web-domains/src/about-me/features/containers/styles.ts index 1cae13f4..df904b49 100644 --- a/packages/web-domains/src/about-me/features/containers/styles.ts +++ b/packages/web-domains/src/about-me/features/containers/styles.ts @@ -43,3 +43,13 @@ export const answerContentCss = css({ marginTop: size['7xs'], }, }); + +export const handWavingButtonCss = css({ + position: 'absolute', + bottom: size['xl'], +}); + +export const screenRootCss = css({ + position: 'relative', + height: '100dvh', +}); diff --git a/packages/web-domains/src/about-me/features/hooks/useGetFirstMeetingId.ts b/packages/web-domains/src/about-me/features/hooks/useGetFirstMeetingId.ts new file mode 100644 index 00000000..b0c07af0 --- /dev/null +++ b/packages/web-domains/src/about-me/features/hooks/useGetFirstMeetingId.ts @@ -0,0 +1,9 @@ +import { useGetMeetings } from '@/about-me/common/apis/queries/useGetMeetings'; + +export const useGetFirstMeetingId = () => { + const { data } = useGetMeetings(); + // NOTE: 하나의 모임에 참여할 수 있는 현재 스펙에서 첫 번째 meetingId를 가져옴 + const meetingId = data?.meetings[0]?.meetingId || -1; + + return { meetingId }; +};