Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
09d1a34
๐Ÿ› fix: ๋ชจ๋‹ฌ์ด ์—ด๋ฆฌ๊ธฐ ์ „์— api ํŒจ์น˜๊ฐ€ ๋˜๋Š” ์—๋Ÿฌ ์ˆ˜์ •
HaeJungg Nov 20, 2024
7fa546b
๐Ÿ› fix: ์—๋Ÿฌ์ด๋ฆ„ ๋ณ€๊ฒฝ
HaeJungg Nov 20, 2024
b4b5770
๐Ÿ› fix: ๋™์ž‘์ด ์‹คํ–‰๋ ๋•Œ ๋ฆฌํŒจ์น˜ ๋˜๋„๋ก
HaeJungg Nov 20, 2024
e3662c1
๐Ÿ’„ design: ๋””์ž์ธ ์ˆ˜์ •
HaeJungg Nov 20, 2024
0fd0de8
๐Ÿ’„ design: ์•ฝ์† ์ œ๋ชฉ ์ด๋™, ์ถ”๊ฐ€
HaeJungg Nov 20, 2024
6c21c51
๐Ÿ’„ design: ๋””์ž์ธ ๊ฐœ์„ 
HaeJungg Nov 20, 2024
b594996
๐Ÿ’„ design: ๋กœ๋” ์ถ”๊ฐ€
HaeJungg Nov 20, 2024
ff71c77
๐Ÿ“ docs: ์ฃผ์„ ์ถ”๊ฐ€
HaeJungg Nov 20, 2024
84ffc6b
๐Ÿ“ docs: ์ฃผ์„ ์ถ”๊ฐ€
HaeJungg Nov 20, 2024
267b354
๐Ÿ› fix: ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž… ์‚ญ์ œ
HaeJungg Nov 20, 2024
695da8d
โœจ feat: ๊ฐœ์„ค์™„๋ฃŒ๋ฅผ ๋ชจ์ง‘ ์™„๋ฃŒ๋กœ ๋ณ€๊ฒฝ, ๋กœ์ง ์ถ”๊ฐ€
HaeJungg Nov 20, 2024
943b93c
Merge branch 'develop' into Fix/146/GatheringDetail
HaeJungg Nov 20, 2024
ea96284
๐Ÿ› fix: ์Šคํ† ๋ฆฌ๋ถ ์—๋Ÿฌ ์ˆ˜์ •
HaeJungg Nov 20, 2024
a882bc7
๐Ÿš‘ fix: update๊ฐ€ ์žˆ์„๋•Œ๋งŒ ์‹คํ–‰๋˜๋„๋ก ๋ณ€๊ฒฝ
HaeJungg Nov 20, 2024
f356715
Merge branch 'develop' into Fix/146/GatheringDetail
HaeJungg Nov 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/_queries/gathering/gathering-detail-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { GetGatheringDetail, createGathering } from '@/src/_apis/gathering/gathering-detail-apis';
import { CreateGatheringRequestTypes } from '@/src/types/gathering-data';

export function useGetGatheringDetailQuery(crewId: number, gatheringId: number) {
export function useGetGatheringDetailQuery(
crewId: number,
gatheringId: number,
options?: { enabled?: boolean },
) {
return useQuery({
queryKey: ['gatheringDetail', crewId, gatheringId],
queryFn: () => GetGatheringDetail(crewId, gatheringId),
...options,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,13 +287,13 @@ export default function CreateCrewForm({
htmlFor="crew-totalCount"
className="text-base font-semibold text-gray-800 md:text-xl"
>
๋ชจ์ง‘ ์ •์›์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.
ํฌ๋ฃจ ์ตœ๋Œ€ ์ธ์›์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ’ก Codebase verification

์šฉ์–ด ํ†ต์ผ์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์ด ํ™•์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ถˆ์ผ์น˜ ์‚ฌํ•ญ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • src/app/(crew)/crew/create/_components/create-crew-form/index.tsx

    • placeholder์— ์—ฌ์ „ํžˆ "์ž์„ธํ•œ ๋ชจ์ง‘ ์ •์›์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”" ๋ฌธ๊ตฌ๊ฐ€ ๋‚จ์•„์žˆ์Šต๋‹ˆ๋‹ค.
  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx

    • "๋ชจ์ง‘ ์ •์›" ๊ด€๋ จ ๋ฌธ๊ตฌ๊ฐ€ 3๊ณณ์—์„œ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ด๋Š” ๋ชจ์ž„ ์ƒ์„ฑ ํผ์ด๋ฏ€๋กœ, "ํฌ๋ฃจ ์ตœ๋Œ€ ์ธ์›"์ด ์•„๋‹Œ "๋ชจ์ง‘ ์ •์›"์ด๋ผ๋Š” ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ์ ˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํฌ๋ฃจ์™€ ๋ชจ์ž„์€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐœ๋…์ด๋ฏ€๋กœ, ๊ฐ๊ฐ์˜ ์ปจํ…์ŠคํŠธ์— ๋งž๋Š” ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋˜ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค:

  • ํฌ๋ฃจ ์ƒ์„ฑ/์ˆ˜์ • ์‹œ: "ํฌ๋ฃจ ์ตœ๋Œ€ ์ธ์›"
  • ๋ชจ์ž„ ์ƒ์„ฑ/์ˆ˜์ • ์‹œ: "๋ชจ์ง‘ ์ •์›"
๐Ÿ”— Analysis chain

์šฉ์–ด ๋ณ€๊ฒฝ์ด ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋ผ๋ฒจ๊ณผ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€์˜ ์šฉ์–ด๊ฐ€ "๋ชจ์ง‘ ์ •์›"์—์„œ "ํฌ๋ฃจ ์ตœ๋Œ€ ์ธ์›"์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” PR์˜ ๋ชฉ์ ์— ๋ถ€ํ•ฉํ•˜๋Š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด์ง€๋งŒ, ๋‹ค์Œ ์‚ฌํ•ญ๋“ค์„ ํ™•์ธํ•ด์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค:

  1. NumberInput ์ปดํฌ๋„ŒํŠธ์˜ placeholder์—๋„ "์ž์„ธํ•œ ๋ชจ์ง‘ ์ •์›์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”"๋ผ๋Š” ๋ฌธ๊ตฌ๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„๋„ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.
  2. ๋‹ค๋ฅธ ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ๋‚˜ ํŽ˜์ด์ง€์—์„œ๋„ ๋™์ผํ•œ ์šฉ์–ด๋กœ ํ†ต์ผ์ด ๋˜์–ด์žˆ๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 296-296

๐Ÿ Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for inconsistent terminology across the codebase

# Search for any remaining instances of "๋ชจ์ง‘ ์ •์›"
rg "๋ชจ์ง‘\s*์ •์›"

# Search for new terminology "ํฌ๋ฃจ ์ตœ๋Œ€ ์ธ์›"
rg "ํฌ๋ฃจ\s*์ตœ๋Œ€\s*์ธ์›"

Length of output: 744

</label>
<Controller
name="totalCount"
control={control}
rules={{
required: '๋ชจ์ง‘ ์ •์›์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.',
required: 'ํฌ๋ฃจ ์ตœ๋Œ€ ์ธ์›์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.',
}}
render={({ field }) => (
<NumberInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@

import { useRouter } from 'next/navigation';
import { useDisclosure } from '@mantine/hooks';
import { useGetCrewDetailQuery } from '@/src/_queries/crew/crew-detail-queries';
import { useGetGatheringListQuery } from '@/src/_queries/crew/gathering-list-queries';
import { useAuth } from '@/src/hooks/use-auth';
import CreateGatheringModalContainer from '@/src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container';
import Button from '@/src/components/common/input/button';
import { CrewDetail } from '@/src/types/crew-card';
import { CreateGatheringFormTypes } from '@/src/types/gathering-data';

export default function CreateGathering({ crewId }: { crewId: number }) {
const { isAuth } = useAuth();
const router = useRouter();
const [opened, { open, close }] = useDisclosure(false);

const { data: gatheringList, isLoading, error, refetch } = useGetGatheringListQuery(crewId);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ’ก Codebase verification

๋ชจ์ž„ ์ƒ์„ฑ ํ›„ refetch๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ฝ”๋“œ์—์„œ ๋ชจ์ž„์ด ์ƒ์„ฑ๋œ ํ›„ refetch()๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์•„ ๋ชฉ๋ก์ด ์ž๋™์œผ๋กœ ๊ฐฑ์‹ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. CreateGatheringModalContainer์˜ mutate ํ˜ธ์ถœ ์‹œ onSuccess ์ฝœ๋ฐฑ์„ ํ†ตํ•ด refetch()๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์ˆ˜์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container.tsx: mutate ํ˜ธ์ถœ ์‹œ onSuccess ์ฝœ๋ฐฑ ์ถ”๊ฐ€ ํ•„์š”
๐Ÿ”— Analysis chain

refetch ํ•จ์ˆ˜์˜ ์‚ฌ์šฉ์„ฑ ๊ฒ€์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

refetch ํ•จ์ˆ˜๊ฐ€ ๋ชจ์ž„์ด ์ƒ์„ฑ๋œ ํ›„์— ์ ์ ˆํžˆ ํ˜ธ์ถœ๋˜๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if refetch is called after gathering creation
ast-grep --pattern 'CreateGatheringModalContainer {
  $$$
  onSuccess={() => {
    $$$
    refetch();
    $$$
  }}
  $$$
}'

Length of output: 125


Script:

#!/bin/bash
# Search for CreateGatheringModalContainer component and its usage
rg "CreateGatheringModalContainer" -A 10

# Search for any usage of refetch in the file
rg "refetch" "src/app/(crew)/crew/detail/[id]/_components/create-gathering/index.tsx" -A 5

Length of output: 5526


Script:

#!/bin/bash
# Search for the container component implementation to check mutation handling
rg -A 20 "useCreateGatheringQuery" "src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container.tsx"

# Search for any onSuccess handlers in the modal container
rg "onSuccess" "src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container.tsx" -A 5

Length of output: 1366


// totalGatheringCount ์ถ”์ถœ
const totalGatheringCount = gatheringList?.length ?? 0;
Comment on lines +18 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ› ๏ธ Refactor suggestion

๋กœ๋”ฉ ๋ฐ ์—๋Ÿฌ ์ƒํƒœ ์ฒ˜๋ฆฌ ๊ฐœ์„ ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ isLoading๊ณผ error ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์žˆ์ง€๋งŒ ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐœ์„ ์‚ฌํ•ญ์„ ์ œ์•ˆ๋“œ๋ฆฝ๋‹ˆ๋‹ค:

  const { data: gatheringList, isLoading, error, refetch } = useGetGatheringListQuery(crewId);
  const totalGatheringCount = gatheringList?.length ?? 0;

+ if (error) {
+   return <div>๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.</div>;
+ }
+
+ if (isLoading) {
+   return <div>๋กœ๋”ฉ ์ค‘...</div>;
+ }

Committable suggestion skipped: line range outside the PR's diff.


const handleButtonClick = () => {
if (isAuth) {
open(); // ๋กœ๊ทธ์ธ ์ƒํƒœ์ผ ๊ฒฝ์šฐ ๋ชจ๋‹ฌ ์—ด๊ธฐ
Expand All @@ -30,7 +38,13 @@ export default function CreateGathering({ crewId }: { crewId: number }) {
};

return (
<>
<div className="flex items-center justify-between px-3 md:px-7 lg:px-11">
<div className="flex items-end space-x-2">
<h2 className="text-2xl font-semibold text-gray-800">์•ฝ์† ์žก๊ธฐ</h2>
<span className="text-base font-semibold text-blue-500">
ํ˜„์žฌ {totalGatheringCount}๊ฐœ์˜ ์•ฝ์†์ด ๊ฐœ์„ค๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
</span>
</div>
<Button type="button" className="btn-filled px-4" onClick={handleButtonClick}>
์•ฝ์† ๋งŒ๋“ค๊ธฐ
</Button>
Expand All @@ -40,6 +54,6 @@ export default function CreateGathering({ crewId }: { crewId: number }) {
close={close}
data={initialValue}
/>
</>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useEffect, useState } from 'react';
import { toast } from 'react-toastify';
import { useRouter } from 'next/navigation';
import { Loader } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { cancelCrew, joinCrew, leaveCrew } from '@/src/_apis/crew/crew-detail-apis';
import { useUser } from '@/src/_queries/auth/user-queries';
Expand All @@ -20,6 +21,7 @@ export default function DetailCrew({ id }: DetailCrewContainerProps) {
const [isCaptain, setIsCaptain] = useState(false);
const [isMember, setIsMember] = useState(false);
const [isJoining, setIsJoining] = useState(false);
const [isConfirmed, setIsConfirmed] = useState(false);
const [confirmCancelOpened, { open: openConfirmCancel, close: closeConfirmCancel }] =
useDisclosure();
const router = useRouter();
Expand All @@ -35,12 +37,20 @@ export default function DetailCrew({ id }: DetailCrewContainerProps) {
const { data, isLoading, error: fetchError, refetch } = useGetCrewDetailQuery(id);

useEffect(() => {
if (currentUserId && data) {
const captain = data.crewMembers.find((member) => member.captain);
const memberExists = data.crewMembers.some((member) => member.id === currentUserId);
if (data) {
// confirmed ์ƒํƒœ ๊ณ„์‚ฐ
if (data.participantCount !== undefined && data.totalCount !== undefined) {
setIsConfirmed(data.participantCount === data.totalCount);
}

// Captain ๋ฐ ๋ฉค๋ฒ„ ์—ฌ๋ถ€ ํ™•์ธ (currentUserId ํ•„์š”)
if (currentUserId) {
const captain = data.crewMembers.find((member) => member.captain);
const memberExists = data.crewMembers.some((member) => member.id === currentUserId);

setIsCaptain(captain?.id === currentUserId);
setIsMember(memberExists);
setIsCaptain(captain?.id === currentUserId);
setIsMember(memberExists);
}
Comment on lines +40 to +53
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ› ๏ธ Refactor suggestion

๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๊ฐ•ํ™”ํ•ด ์ฃผ์„ธ์š”.

ํ˜„์žฌ ๊ตฌํ˜„์—์„œ ๋ช‡ ๊ฐ€์ง€ ๊ฐœ์„ ์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  1. data.participantCount์™€ data.totalCount๊ฐ€ undefined์ผ ๋•Œ์˜ ๊ธฐ๋ณธ๊ฐ’ ์ฒ˜๋ฆฌ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  2. crewMembers ๋ฐฐ์—ด์ด undefined์ผ ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐœ์„ ํ•ด ๋ณด์„ธ์š”:

  useEffect(() => {
    if (data) {
-     if (data.participantCount !== undefined && data.totalCount !== undefined) {
+     const participantCount = data.participantCount ?? 0;
+     const totalCount = data.totalCount ?? 0;
-       setIsConfirmed(data.participantCount === data.totalCount);
+       setIsConfirmed(participantCount === totalCount);
-     }

      if (currentUserId) {
+       const crewMembers = data.crewMembers ?? [];
-       const captain = data.crewMembers.find((member) => member.captain);
+       const captain = crewMembers.find((member) => member.captain);
-       const memberExists = data.crewMembers.some((member) => member.id === currentUserId);
+       const memberExists = crewMembers.some((member) => member.id === currentUserId);

        setIsCaptain(captain?.id === currentUserId);
        setIsMember(memberExists);
      }
    }
  }, [currentUserId, data]);
๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (data) {
// confirmed ์ƒํƒœ ๊ณ„์‚ฐ
if (data.participantCount !== undefined && data.totalCount !== undefined) {
setIsConfirmed(data.participantCount === data.totalCount);
}
// Captain ๋ฐ ๋ฉค๋ฒ„ ์—ฌ๋ถ€ ํ™•์ธ (currentUserId ํ•„์š”)
if (currentUserId) {
const captain = data.crewMembers.find((member) => member.captain);
const memberExists = data.crewMembers.some((member) => member.id === currentUserId);
setIsCaptain(captain?.id === currentUserId);
setIsMember(memberExists);
setIsCaptain(captain?.id === currentUserId);
setIsMember(memberExists);
}
if (data) {
const participantCount = data.participantCount ?? 0;
const totalCount = data.totalCount ?? 0;
setIsConfirmed(participantCount === totalCount);
if (currentUserId) {
const crewMembers = data.crewMembers ?? [];
const captain = crewMembers.find((member) => member.captain);
const memberExists = crewMembers.some((member) => member.id === currentUserId);
setIsCaptain(captain?.id === currentUserId);
setIsMember(memberExists);
}
}

}
}, [currentUserId, data]);

Expand Down Expand Up @@ -88,7 +98,7 @@ export default function DetailCrew({ id }: DetailCrewContainerProps) {
toast.success('ํฌ๋ฃจ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
router.push('/');
} catch (deleteError) {
toast.error('ํฌ๋ฃจ ์‚ญ์ œ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.');
toast.error('๐Ÿšซ ํฌ๋ฃจ ์‚ญ์ œ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.');
}
};

Expand All @@ -106,9 +116,10 @@ export default function DetailCrew({ id }: DetailCrewContainerProps) {

// TODO: ๋กœ๋”ฉ, ์—๋Ÿฌ์ฒ˜๋ฆฌ ์ถ”ํ›„ ๊ฐœ์„ 
if (isLoading) {
return <p>Loading...</p>;
return <Loader />;
}

// TODO: ์ถ”ํ›„ 404ํŽ˜์ด์ง€๋กœ ์ด๋™์‹œํ‚ค๊ธฐ
if (fetchError) {
if (fetchError instanceof ApiError) {
try {
Expand All @@ -118,7 +129,7 @@ export default function DetailCrew({ id }: DetailCrewContainerProps) {
return <p>ํฌ๋ฃจ ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค</p>;
}
} catch (parseError) {
return <p>{`Error ${fetchError.status}: ${fetchError.message}`}</p>;
return <p>{`Error ${fetchError.message}`}</p>;
}
}
return <p>๋ฐ์ดํ„ฐ ํ†ต์‹ ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.</p>;
Expand All @@ -135,6 +146,7 @@ export default function DetailCrew({ id }: DetailCrewContainerProps) {
isCaptain={isCaptain}
isMember={isMember}
isJoining={isJoining}
isConfirmed={isConfirmed}
handleJoinClick={handleJoinClick}
handleLeaveCrew={handleLeaveCrew}
handleDelete={handleDelete}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface DetailCrewPresenterProps {
isCaptain: boolean;
isMember: boolean;
isJoining: boolean;
isConfirmed: boolean;
handleJoinClick: () => void;
handleLeaveCrew: () => void;
handleDelete: () => void;
Expand All @@ -26,6 +27,7 @@ export default function DetailCrewPresenter({
data,
isCaptain,
isMember,
isConfirmed,
handleJoinClick,
handleLeaveCrew,
handleDelete,
Expand All @@ -42,14 +44,14 @@ export default function DetailCrewPresenter({
totalCount,
imageUrl,
crewMembers,
confirmed,
} = data;

// captain๊ณผ members ๋ถ„๋ฆฌ
const captain = crewMembers.find((member) => member.captain) as CrewDetailMember;
const members = crewMembers.filter((member) => !member.captain);

const getJoinButtonText = () => {
if (isConfirmed) return '๋ชจ์ง‘ ์™„๋ฃŒ';
if (isMember) return '์ฐธ์—ฌ ์™„๋ฃŒ';
if (isJoining) return '์ฐธ์—ฌ ์ค‘...';
return 'ํฌ๋ฃจ ์ฐธ์—ฌํ•˜๊ธฐ';
Expand All @@ -71,23 +73,23 @@ export default function DetailCrewPresenter({
<Button
className={cn('px-4 py-2', isMember ? 'btn-disabled' : 'btn-filled')}
onClick={handleJoinClick}
disabled={isMember || isJoining}
disabled={isMember || isJoining || isConfirmed}
>
{getJoinButtonText()}
</Button>
</div>

{/* ์˜ค๋ฅธ์ชฝ ํ•˜๋‹จ ๊ณต์œ  ๋ฐ ์ผ€๋ฐฅ ๋ฒ„ํŠผ */}
<div className="absolute bottom-6 right-6 flex space-x-2">
<div className="absolute bottom-6 right-6 flex items-center space-x-2">
<button type="button" className="bg-transparent" onClick={onShareClick}>
<Image src={ShareIco} alt="๊ณต์œ ํ•˜๊ธฐ" className="h-6 w-6" />
</button>
{isCaptain || isMember ? (
<Menu trigger="click" position="bottom-end" openDelay={100} closeDelay={400}>
<Menu.Target>
<div className="cursor-pointer">
<button type="button" className="cursor-pointer">
<Image src={KebabIcon} alt="๋”๋ณด๊ธฐ" width={20} height={20} />
</div>
</button>
</Menu.Target>
<Menu.Dropdown>
{isCaptain ? (
Expand Down Expand Up @@ -151,19 +153,20 @@ export default function DetailCrewPresenter({
<div className="mb-2 flex items-center justify-between">
<div className="flex items-center">
<Image src={IcoUser} alt="์œ ์ € ์•„์ด์ฝ˜" width={20} height={20} />
<span className="text-base font-medium text-gray-700">์ฐธ์—ฌ์ธ์›</span>
<span className="text-base font-medium text-gray-700">ํฌ๋ฃจ๋ฉค๋ฒ„</span>
<span className="pl-1 text-base font-medium text-blue-500">{participantCount}</span>
<span className="text-base font-medium text-gray-700">/{totalCount}</span>
</div>
{confirmed && (
{isConfirmed && (
<div className="flex items-center text-blue-600">
<Image src={Check} alt="๊ฐœ์„ค ํ™•์ •" width={24} height={24} />
<span className="text-sm font-medium">๊ฐœ์„คํ™•์ •</span>
<Image src={Check} alt="๋ชจ์ง‘ ์™„๋ฃŒ ์•„์ด์ฝ˜" width={24} height={24} />
<span className="text-sm font-medium">๋ชจ์ง‘ ์™„๋ฃŒ</span>
</div>
)}
</div>
<div className="w-full">
<ProgressBar total={totalCount} current={participantCount} />
<p className="pt-1 text-sm text-gray-500">ํฌ๋ฃจ์žฅ์„ ์ œ์™ธํ•œ ๋ฉค๋ฒ„ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค.</p>
</div>
<div className="mt-4 h-40 space-y-6 overflow-y-auto">
{members.length > 0 ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export const Default: Story = {
subLocation: '์œ ์„ฑ๊ตฌ',
participantCount: 8,
totalCount: 10,
confirmed: true,
imageUrl:
'https://crewcrew.s3.ap-northeast-2.amazonaws.com/crew/4d0c5851-e6e2-4919-897a-b8d4e88a4f72',
totalGatheringCount: 5,
Expand Down Expand Up @@ -117,7 +116,6 @@ export const IsCaptain: Story = {
subLocation: '์œ ์„ฑ๊ตฌ',
participantCount: 1,
totalCount: 10,
confirmed: true,
imageUrl:
'https://crewcrew.s3.ap-northeast-2.amazonaws.com/crew/4d0c5851-e6e2-4919-897a-b8d4e88a4f72',
totalGatheringCount: 1,
Expand Down Expand Up @@ -149,7 +147,6 @@ export const IsMember: Story = {
subLocation: '์œ ์„ฑ๊ตฌ',
participantCount: 2,
totalCount: 10,
confirmed: true,
imageUrl:
'https://crewcrew.s3.ap-northeast-2.amazonaws.com/crew/4d0c5851-e6e2-4919-897a-b8d4e88a4f72',
totalGatheringCount: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ export interface GatheringDetailModalContainerProps {
opened: boolean;
close: () => void;
data: GatheringDetailType;
onUpdate?: () => void;
}

// NOTE: ํ…Œ์ŠคํŠธ๋Š” ๋กœ๊ทธ์ธ ํ›„ ํ† ํฐ์ด ์•ˆ๋‹ด๊ฒจ์„œ ์ถ”ํ›„ ์ง„ํ–‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

export default function GatheringDetailModalContainer({
opened,
close,
data,
onUpdate,
}: GatheringDetailModalContainerProps) {
const showToast = (message: string, type: 'success' | 'error' | 'warning') => {
toast(message, { type });
Expand All @@ -32,6 +32,7 @@ export default function GatheringDetailModalContainer({
await JoinGathering(data.crewId, data.id);
showToast('์•ฝ์†์— ์ฐธ์—ฌํ–ˆ์Šต๋‹ˆ๋‹ค.', 'success');
close();
onUpdate?.();
} catch (error) {
if (error instanceof ApiError) {
showToast(`์ฐธ์—ฌ ์ค‘ ์—๋Ÿฌ ๋ฐœ์ƒ: ${error.message}`, 'error');
Expand All @@ -43,6 +44,7 @@ export default function GatheringDetailModalContainer({
try {
await LeaveGathering(data.crewId, data.id);
close();
onUpdate?.();
} catch (error) {
if (error instanceof ApiError) {
showToast(`์ฐธ์—ฌ ์ทจ์†Œ ์ค‘ ์—๋Ÿฌ ๋ฐœ์ƒ: ${error.message}`, 'error');
Expand All @@ -55,6 +57,7 @@ export default function GatheringDetailModalContainer({
await CancelGathering(data.crewId, data.id);
showToast('์•ฝ์†์„ ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.', 'success');
close();
onUpdate?.();
} catch (error) {
if (error instanceof ApiError) {
showToast(`์•ฝ์† ์‚ญ์ œ ์ค‘ ์—๋Ÿฌ ๋ฐœ์ƒ: ${error.message}`, 'error');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,19 @@ const Template: StoryFn<GatheringDetailModalContainerProps> = function Gathering
setIsOpened(opened);
}, [opened]);

const handleUpdate = () => {
action('Update action performed')();
};

return (
<>
<Button onClick={handleOpen}>Open Modal</Button>
<GatheringDetailModalContainer opened={isOpened} close={handleClose} data={data} />
<GatheringDetailModalContainer
opened={isOpened}
close={handleClose}
data={data}
onUpdate={handleUpdate}
/>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useState } from 'react';
import { toast } from 'react-toastify';
import { useRouter } from 'next/navigation';
import { Loader } from '@mantine/core';
import { addLike, removeLike } from '@/src/_apis/liked/liked-apis';
import { useGetGatheringListQuery } from '@/src/_queries/crew/gathering-list-queries';
import { ApiError } from '@/src/utils/api';
Expand All @@ -14,7 +15,7 @@ interface GatheringListSectionProps {
}

export default function GatheringListSection({ id }: GatheringListSectionProps) {
const { data: gatheringList, isLoading, error } = useGetGatheringListQuery(id);
const { data: gatheringList, isLoading, error, refetch } = useGetGatheringListQuery(id);
const [showLoginModal, setShowLoginModal] = useState(false);
const router = useRouter();

Expand Down Expand Up @@ -43,11 +44,15 @@ export default function GatheringListSection({ id }: GatheringListSectionProps)
router.push(`/login?redirect=${encodeURIComponent(currentPath)}`);
};

const handleModalAction = () => {
refetch();
};

// TODO: ์ถ”ํ›„ ์—๋Ÿฌ, ๋กœ๋”ฉ ์ˆ˜์ •
if (isLoading)
return (
<div className="flex items-center justify-center">
<p>๋กœ๋”ฉ ์ค‘...</p>
<Loader />
</div>
);

Expand All @@ -73,6 +78,7 @@ export default function GatheringListSection({ id }: GatheringListSectionProps)
onLike={handleLike}
onUnlike={handleUnlike}
onShowLoginModal={() => setShowLoginModal(true)}
onModalAction={handleModalAction}
/>
{showLoginModal && (
<ConfirmModal
Expand Down
5 changes: 1 addition & 4 deletions src/app/(crew)/crew/detail/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ export default async function CrewDetailPage({ params }: CrewDetailPageProps) {
{/* Gathering Section */}
<section className="w-full space-y-6">
<article className="space-y-6">
<div className="flex items-center justify-between px-3 md:px-7 lg:px-11">
<h2 className="text-2xl font-semibold">ํฌ๋ฃจ ์•ฝ์†</h2>
<CreateGathering crewId={Number(params.id)} />
</div>
<CreateGathering crewId={Number(params.id)} />
<div className="flex w-full overflow-hidden px-3 md:px-7 lg:px-0">
<div className="relative -mx-3 w-[calc(100%+1.5rem)] px-3 md:-mx-7 md:w-[calc(100%+3.5rem)] md:px-7 lg:-mx-6 lg:w-[calc(100%+3rem)] lg:px-0">
<GatheringListSection id={id} />
Expand Down
Loading
Loading