Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
301244a
โœจ Feat: my-gathering ๋ฒ„ํŠผ ์ถ”๊ฐ€ ๋ฐ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ
minkyung5x5 Nov 5, 2024
cdd2d66
โœจ Feat: ํ•˜์œ„ ํŽ˜์ด์ง€๋กœ ๋ถ„๋ฆฌ
minkyung5x5 Nov 5, 2024
6ac5383
Merge branch 'develop' into Feat/60/my-gathering-page
minkyung5x5 Nov 5, 2024
a8ace8f
โœจ Feat: GatheringList ์ถ”๊ฐ€
minkyung5x5 Nov 6, 2024
e37ca96
Merge branch 'develop' into Feat/60/my-gathering-page
minkyung5x5 Nov 6, 2024
57f9da5
๐Ÿ’„ Style: gatheringlist max-w ์‚ญ์ œ
minkyung5x5 Nov 6, 2024
76df121
๐Ÿ’„ Style: ์ „์ฒด ๋ ˆ์ด์•„์›ƒ์— flex-1 ์ถ”๊ฐ€
minkyung5x5 Nov 6, 2024
b7f92d1
โœจ Feat: gatheringListWithDate ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€
minkyung5x5 Nov 6, 2024
7c9cbf3
๐Ÿ’„ Style: gatheringListWithDate UI ์ˆ˜์ •
minkyung5x5 Nov 6, 2024
706cac6
โœจ Feat: popoverCalendar ์ถ”๊ฐ€, ๐Ÿ› Fix: card ๋ชจ๋ฐ”์ผํ™˜๊ฒฝ ์ด๋ฏธ์ง€ ์‚ฌ์ด์ฆˆ ์ˆ˜์ •
minkyung5x5 Nov 6, 2024
5ecbd76
โœจ Feat: ์ฐธ์—ฌํ•œ ๋ชจ์ž„ ํŽ˜์ด์ง€ ์ถ”๊ฐ€
minkyung5x5 Nov 6, 2024
1d78a85
โœจ Feat: gathering Detail Modal API ์ถ”๊ฐ€
minkyung5x5 Nov 6, 2024
a61c8be
Merge branch 'develop' into Feat/60/my-gathering-page
minkyung5x5 Nov 6, 2024
83bc73c
Merge branch 'develop' into Feat/60/my-gathering-page
minkyung5x5 Nov 6, 2024
46df06f
๐Ÿ› fix: ๊ฒฝ๋กœ์ˆ˜์ •
minkyung5x5 Nov 6, 2024
1fc4c03
๐Ÿ› fix: prettier error ์ˆ˜์ •
minkyung5x5 Nov 6, 2024
eb84994
๐Ÿ› fix: api dummydata๋กœ ์ž„์‹œ ์ˆ˜์ •
minkyung5x5 Nov 6, 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
35 changes: 35 additions & 0 deletions mock.json
Original file line number Diff line number Diff line change
Expand Up @@ -335,5 +335,40 @@
"isConfirmed": true,
"gatheringCount": 5
}
],
"gatheringDetail": [
{
"id": 1,
"title": "์‹ ๋‚˜๋Š” ์šด๋™...์ฆ๊ฑฐ์šด..์ฝ”๋”ฉ..",
"introduce": "๊ณต์ง€์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ๋‹ค๋“ค ์ด๋ฒˆ ์•ฝ์† ์žŠ์ง€ ์•Š์œผ์…จ์ฃ ? ๊ผญ ์ฐธ์—ฌ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค~",
"dateTime": "2024-10-29T00:32:12.306Z",
"location": "์„œ์šธ์‹œ ๊ฐ•๋‚จ๊ตฌ ์—ญ์‚ผ๋™ ์˜คํ”ผ์Šคํƒ€์›Œ 3์ธต",
"currentCount": 3,
"totalCount": 10,
"imageUrl": "https://www.dabur.com/Blogs/Doshas/Importance%20and%20Benefits%20of%20Yoga%201020x450.jpg",
"isLiked": false,
"isGatherCaptain": false,
"isParticipant": true,
"participants": [
{
"id": 1,
"profileImageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQUMrcQB5OJ-ETzPc6wHnjxjC-36__MGw3JcA&s",
"nickname": "๋Ÿฝ์œˆ์ฆˆ์˜ฌ",
"email": "[email protected]"
},
{
"id": 2,
"profileImageUrl": "https://imgcdn.stablediffusionweb.com/2024/5/13/c0541236-e690-4dff-a27e-30a0355e5ea0.jpg",
"nickname": "๋ชจ๋‹๋Ÿฌ๋„ˆ",
"email": "[email protected]"
},
{
"id": 3,
"profileImageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQUMrcQB5OJ-ETzPc6wHnjxjC-36__MGw3JcA&s",
"nickname": "๋™๊ธ€๋™๊ธ€์ด",
"email": "[email protected]"
}
]
}
]
}
11 changes: 11 additions & 0 deletions src/_apis/gathering/gathering-apis.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { fetchApi } from '@/src/utils/api';
import { GatheringDetailType } from '@/src/types/gathering-data';

export function getGathering(): Promise<GatheringDetailType> {
return fetchApi<GatheringDetailType>('/gatheringDetail/1', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then((response) => response); // TODO: data ์ถ”์ถœ
}
11 changes: 11 additions & 0 deletions src/_queries/gathering/gathering-queries.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { getGathering } from '@/src/_apis/gathering/gathering-apis';
import { transformKeysToCamel } from '@/src/utils/transform-keys';
import { GatheringDetailType } from '@/src/types/gathering-data';

export function useGetGatheringQuery() {
return {
queryKey: ['gatheringDetail'],
queryFn: getGathering,
select: (data: GatheringDetailType) => transformKeysToCamel(data),
};
}
2 changes: 1 addition & 1 deletion src/app/(crew)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function RootLayout({
<>
<Header />
<div className="flex min-h-screen flex-col items-center bg-gray-50">
<main className="container flex min-h-screen max-w-pc flex-col md:shadow-bg">
<main className="container flex flex-1 min-h-screen max-w-pc flex-col md:shadow-bg">
{children}
</main>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use client';

import { useMemo } from 'react';
import { formatDate } from '@/src/utils/format-date';
import ScheduledGatheringCard from '@/src/components/common/gathering-card/scheduled-gathering-card/container';
import { GatheringCardProps } from '@/src/types/gathering-data';

interface GatheringListWithDateProps {
gatheringList: GatheringCardProps[];
}

export default function GatheringListWithDate({ gatheringList }: GatheringListWithDateProps) {
const gatheringListWithDateInfo = useMemo(() => {
return gatheringList.map((gathering, index) => {
const isNewDate =
index === 0 ||
formatDate(gathering.dateTime).date !== formatDate(gatheringList[index - 1].dateTime).date;
return { ...gathering, isNewDate };
});
}, [gatheringList]);

return (
<div className="m-4 md:mt-[32.5px]">
{gatheringListWithDateInfo.map((gathering) => (
<div key={gathering.id} className="md:flex">
<div className="relative w-1/6 md:border-r-2 md:border-gray-200">
{gathering.isNewDate && (
<div>
<div className="md:corner-dot" />
<div className="hidden flex-nowrap md:block">
<div className="text-lg font-semibold">{formatDate(gathering.dateTime).date}</div>
<div className="text-base font-medium text-gray-500">์›”์š”์ผ</div>
</div>
</div>
)}
</div>
<div className={`${gathering.isNewDate ? 'pb-' : 'p-'} flex-1 pb-6 md:pl-8`}>
<ScheduledGatheringCard key={gathering.id} data={gathering} />
</div>
</div>
))}
</div>
);
}
78 changes: 78 additions & 0 deletions src/app/(crew)/my-gathering/creation/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
'use client';

import { useEffect, useState } from 'react';
import GatheringListWithDate from '@/src/app/(crew)/my-gathering/_component/gathering-list-with-date';
import PopOverCalendar from '@/src/components/common/input/pop-over-calendar';
import { GatheringCardProps } from '@/src/types/gathering-data';

export default function CreationPage() {
const [selectedDate, setSelectedDate] = useState(new Date());

useEffect(() => {}, [selectedDate]);
const creationGatheringList: GatheringCardProps[] = [
{
id: 1,
crewTitle: 'Power Pole',
crewMainLocation: '์„œ์šธ์‹œ',
crewSubLocation: '๊ฐ•๋‚จ๊ตฌ ์—ญ์‚ผ๋™',
title: '๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€',
dateTime: '2024-10-30T00:30',
currentCount: 8,
totalCount: 12,
imageUrl:
'https://images.unsplash.com/photo-1601758260892-a62c486ace97?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
isLiked: true,
},
{
id: 2,
crewTitle: 'ํ’€ ์—” ๊ทธ๋ ˆ์ด์Šค ์ŠคํŠœ๋””์˜ค',
crewMainLocation: '์„œ์šธ์‹œ',
crewSubLocation: '๊ฐ•๋‚จ๊ตฌ ์—ญ์‚ผ๋™',
title: '๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€',
dateTime: '2024-10-30T00:30',
currentCount: 8,
totalCount: 12,
imageUrl:
'https://images.unsplash.com/photo-1601758260892-a62c486ace97?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
isLiked: true,
},
{
id: 3,
crewTitle: 'ํ’€ ์—” ๊ทธ๋ ˆ์ด์Šค ์ŠคํŠœ๋””์˜ค',
crewMainLocation: '์„œ์šธ์‹œ',
crewSubLocation: '๊ฐ•๋‚จ๊ตฌ ์—ญ์‚ผ๋™',
title: '๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€',
dateTime: '2024-11-11T00:30',
currentCount: 8,
totalCount: 12,
imageUrl:
'https://images.unsplash.com/photo-1601758260892-a62c486ace97?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
isLiked: true,
},
{
id: 4,
crewTitle: 'ํ’€ ์—” ๊ทธ๋ ˆ์ด์Šค ์ŠคํŠœ๋””์˜ค',
crewMainLocation: '์„œ์šธ์‹œ',
crewSubLocation: '๊ฐ•๋‚จ๊ตฌ ์—ญ์‚ผ๋™',
title: '๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€',
dateTime: '2024-11-21T00:30',
currentCount: 8,
totalCount: 12,
imageUrl:
'https://images.unsplash.com/photo-1601758260892-a62c486ace97?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
isLiked: true,
},
];

return (
<div className="">
<div className="pl-4 md:pt-2">
<PopOverCalendar value={selectedDate} onChange={(d) => setSelectedDate(d)} />
</div>
<GatheringListWithDate gatheringList={creationGatheringList} />
</div>
);
}
function setState(arg0: Date) {
throw new Error('Function not implemented.');
}
10 changes: 10 additions & 0 deletions src/app/(crew)/my-gathering/favorite/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import GatheringList from '@/src/components/gathering-list/gathering-list';
import { gatheringData } from '@/src/mock/gathering-data';

export default function FavoritePage() {
return (
<div className="md:mt-[45px]">
<GatheringList gatheringData={gatheringData} />
</div>
);
}
48 changes: 48 additions & 0 deletions src/app/(crew)/my-gathering/layout.tsx
Copy link
Contributor

Choose a reason for hiding this comment

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

์ด๋Ÿฐ์‹์œผ๋กœ๋„ ํ•˜๋Š”๊ตฐ์š”.... ์—ญ์‹œ ๊น”๋”~~~ ๐Ÿ‘๐Ÿ‘๐Ÿ‘

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use client';

import { useEffect, useState } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { Button } from '@mantine/core';

const buttonData = [
{ id: 1, label: '์ฐธ์—ฌํ•œ ์•ฝ์†', route: '/my-gathering/participation' },
{ id: 2, label: '๋งŒ๋“  ์•ฝ์†', route: '/my-gathering/creation' },
{ id: 3, label: '์ฐœํ•œ ์•ฝ์†', route: '/my-gathering/favorite' },
];

const getSelectedButtonIndex = (currentPath: string) => {
return buttonData.findIndex(({ route }) => currentPath.endsWith(route.split('/').pop()!)) + 1;
};

export default function MyGatheringLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const currentPath = usePathname();

const [selectedButton, setSelectedButton] = useState(getSelectedButtonIndex(currentPath));

useEffect(() => {
const newIdx = getSelectedButtonIndex(currentPath);
setSelectedButton(newIdx);
}, [currentPath]);

return (
<div className="mt-4 md:mx-[46px] md:mt-[45px]">
<div className="m-4 grid grid-cols-3 gap-2 md:gap-4">
{buttonData.map(({ id, label, route }) => (
<Link key={id} href={route}>
<Button
className={`${id === selectedButton ? 'btn-filled' : 'btn-outlined'} w-full text-sm font-bold md:text-lg`}
>
{label}
</Button>
</Link>
))}
</div>
{children}
</div>
);
}
16 changes: 3 additions & 13 deletions src/app/(crew)/my-gathering/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
'use client';

import { useState } from 'react';
import CalendarFilter from '@/src/components/common/input/calendar-filter';

const toDoDates = [new Date('2024-10-12'), new Date('2024-10-15')];
import { redirect } from 'next/navigation';

export default function MyGatheringPage() {
const [date, setDate] = useState<Date>(new Date());

return (
<div className="container mx-auto my-0 max-w-pc px-5 lg:px-0">
<CalendarFilter value={date} toDoDates={toDoDates} onChange={setDate} />
</div>
);
redirect('/my-gathering/participation');
return null;
}
65 changes: 65 additions & 0 deletions src/app/(crew)/my-gathering/participation/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use client';

import { useEffect, useState } from 'react';
import GatheringListWithDate from '@/src/app/(crew)/my-gathering/_component/gathering-list-with-date';
import PopOverCalendar from '@/src/components/common/input/pop-over-calendar';
import { GatheringCardProps } from '@/src/types/gathering-data';

export default function ParticipationPage() {
const [selectedDate, setSelectedDate] = useState(new Date());

useEffect(() => {}, [selectedDate]);
const creationGatheringList: GatheringCardProps[] = [
{
id: 1,
crewTitle: 'ํ’€ ์—” ๊ทธ๋ ˆ์ด์Šค ์ŠคํŠœ๋””์˜ค',
crewMainLocation: '์„œ์šธ์‹œ',
crewSubLocation: '๊ฐ•๋‚จ๊ตฌ ์—ญ์‚ผ๋™',
title: '๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€',
dateTime: '2024-10-30T00:30',
currentCount: 8,
totalCount: 12,
imageUrl:
'https://images.unsplash.com/photo-1601758260892-a62c486ace97?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
isLiked: true,
},
{
id: 2,
crewTitle: 'ํ’€ ์—” ๊ทธ๋ ˆ์ด์Šค ์ŠคํŠœ๋””์˜ค',
crewMainLocation: '์„œ์šธ์‹œ',
crewSubLocation: '๊ฐ•๋‚จ๊ตฌ ์—ญ์‚ผ๋™',
title: '๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€',
dateTime: '2024-10-30T00:30',
currentCount: 8,
totalCount: 12,
imageUrl:
'https://images.unsplash.com/photo-1601758260892-a62c486ace97?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
isLiked: true,
},
{
id: 3,
crewTitle: 'ํ’€ ์—” ๊ทธ๋ ˆ์ด์Šค ์ŠคํŠœ๋””์˜ค',
crewMainLocation: '์„œ์šธ์‹œ',
crewSubLocation: '๊ฐ•๋‚จ๊ตฌ ์—ญ์‚ผ๋™',
title: '๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๊ฐ€',
dateTime: '2024-10-31T00:30',
currentCount: 8,
totalCount: 12,
imageUrl:
'https://images.unsplash.com/photo-1601758260892-a62c486ace97?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
isLiked: true,
},
];

return (
<div className="">
<div className="pl-4 md:pt-2">
<PopOverCalendar value={selectedDate} onChange={(d) => setSelectedDate(d)} />
</div>
<GatheringListWithDate gatheringList={creationGatheringList} />
</div>
);
}
function setState(arg0: Date) {
throw new Error('Function not implemented.');
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { useCallback } from 'react';
import { useCallback, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useGetGatheringQuery } from '@/src/_queries/gathering/gathering-queries';
import GatheringDetailModalContainer from '@/src/components/gathering-detail-modal/container';
import { GatheringDetailType } from '@/src/types/gathering-data';
import ScheduledGatheringCardPresenter from './presenter';

interface ScheduledGatheringCardContainerProps {
Expand All @@ -19,19 +23,34 @@ interface ScheduledGatheringCardContainerProps {
export default function ScheduledGatheringCardContainer({
data,
}: ScheduledGatheringCardContainerProps) {
const [isOpened, setIsOpened] = useState(false);
const { data: modalData } = useQuery<GatheringDetailType>(useGetGatheringQuery());

const handleCardClick = useCallback(() => {
alert('์นด๋“œ ํด๋ฆญ๋จ'); // TODO: ๋ชจ๋‹ฌ ์—ด๊ธฐ ๋กœ์ง ๊ตฌํ˜„
setIsOpened(true);
// TODO: retry or refetch์‚ฌ์šฉํ•ด์„œ useQuery๋ถ€๋ถ„ ์•ˆ์œผ๋กœ ๋„ฃ๊ธฐ
}, []);

const handleLikeToggle = useCallback(() => {
alert('์ข‹์•„์š” ํ† ๊ธ€๋จ'); // TODO: ์ข‹์•„์š” ํ† ๊ธ€ ๋กœ์ง ๊ตฌํ˜„
}, []);

return (
<ScheduledGatheringCardPresenter
data={data}
onClick={handleCardClick}
onLikeToggle={handleLikeToggle}
/>
<div>
<ScheduledGatheringCardPresenter
data={data}
onClick={handleCardClick}
onLikeToggle={handleLikeToggle}
/>
{modalData && (
<GatheringDetailModalContainer
opened={isOpened}
close={() => {
setIsOpened(false);
}}
data={modalData}
/>
)}
</div>
);
}
Loading