Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 12 additions & 27 deletions src/app/schedule/(components)/current.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
'use client';

import { useRouter } from 'next/navigation';
import { MeetingList } from './meeting-list';
import type { Meeting } from './types';

import Card from '@/components/shared/card';

const MOCK_MEETINGS = [
const MOCK_MEETINGS: Meeting[] = [
{
id: 1,
title: '네즈코와 무한성에서 정모 하실 분',
Expand All @@ -14,33 +13,19 @@ const MOCK_MEETINGS = [
nickName: 'Hope Lee',
participantCount: 8,
maxParticipants: 10,
tags: ['#태그', '#태그', '#태그'],
tags: ['#젠이츠', '#기유', '#네즈코'],
},
];

export default function Current() {
const router = useRouter();

return (
<section className='flex w-full flex-col gap-4 px-4 py-4'>
{MOCK_MEETINGS.map((meeting) => (
<Card
key={meeting.id}
dateTime={meeting.dateTime}
images={meeting.images}
leaveAndChatActions={{
onLeave: () => console.log('모임 탈퇴', meeting.id),
onChat: () => router.push(`/chat/${meeting.id}`),
}}
location={meeting.location}
maxParticipants={meeting.maxParticipants}
nickName={meeting.nickName}
participantCount={meeting.participantCount}
tags={meeting.tags}
title={meeting.title}
onClick={() => router.push(`/meetup/${meeting.id}`)}
/>
))}
</section>
<MeetingList
emptyStatePath='/'
emptyStateType='current'
leaveActionText='모임 탈퇴'
meetings={MOCK_MEETINGS}
showActions={true}
tabType='current'
/>
);
}
51 changes: 51 additions & 0 deletions src/app/schedule/(components)/empty-state.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use client';

import { Icon } from '@/components/icon';
import { Button } from '@/components/ui';
import { cn } from '@/lib/utils';

type EmptyStateProps = {
type: 'current' | 'my' | 'history';
onButtonClick: () => void;
};

const EMPTY_STATE_CONFIG = {
current: {
text: '현재 참여 중인 모임이 없어요.\n지금 바로 모임을 참여해보세요!',
buttonText: '모임 보러가기',
buttonWidth: 'w-[124px]',
},
my: {
text: '아직 생성한 모임이 없어요.\n지금 바로 모임을 만들어보세요!',
buttonText: '모임 만들기',
buttonWidth: 'w-[112px]',
},
history: {
text: '아직 참여한 모임이 없어요.\n마음에 드는 모임을 발견해보세요!',
buttonText: '모임 보러가기',
buttonWidth: 'w-[124px]',
},
} as const;

export const EmptyState = ({ type, onButtonClick }: EmptyStateProps) => {
const config = EMPTY_STATE_CONFIG[type];

return (
<div className='flex flex-col items-center pt-[202px]'>
<Icon id='wego-logo' className='text-gray-500' size={85} />

<div className='mt-5 text-center'>
<p className='text-text-sm-medium whitespace-pre-line text-gray-600'>{config.text}</p>
</div>

<Button
className={cn('text-text-sm-bold mt-[18px]', config.buttonWidth)}
size='xs'
variant='primary'
onClick={onButtonClick}
>
{config.buttonText}
</Button>
</div>
);
};
48 changes: 10 additions & 38 deletions src/app/schedule/(components)/history.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,18 @@
'use client';

import { useRouter } from 'next/navigation';
import { MeetingList } from './meeting-list';
import type { Meeting } from './types';

import Card from '@/components/shared/card';

const MOCK_MEETINGS = [
{
id: 3,
title: '동네 책모임 신규 멤버 구함',
images: [],
location: '망원동 카페 거리',
dateTime: '25. 12. 10 - 19:30',
nickName: 'Book Lover',
participantCount: 3,
maxParticipants: 8,
tags: ['#책모임', '#수다환영'],
},
];
const MOCK_MEETINGS: Meeting[] = [];

export default function History() {
const router = useRouter();

return (
<section className='flex w-full flex-col gap-4 px-4 py-4'>
{MOCK_MEETINGS.map((meeting) => (
<Card
key={meeting.id}
dateTime={meeting.dateTime}
images={meeting.images}
leaveAndChatActions={{
onLeave: () => console.log('모임 탈퇴', meeting.id),
onChat: () => router.push(`/chat/${meeting.id}`),
}}
location={meeting.location}
maxParticipants={meeting.maxParticipants}
nickName={meeting.nickName}
participantCount={meeting.participantCount}
tags={meeting.tags}
title={meeting.title}
onClick={() => router.push(`/meetup/${meeting.id}`)}
/>
))}
</section>
<MeetingList
emptyStatePath='/'
emptyStateType='history'
meetings={MOCK_MEETINGS}
showActions={false}
tabType='history'
/>
);
}
60 changes: 60 additions & 0 deletions src/app/schedule/(components)/meeting-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client';

import { useRouter } from 'next/navigation';

import Card from '@/components/shared/card';

import { EmptyState } from './empty-state';
import type { Meeting, TabType } from './types';

type MeetingListProps = {
meetings: Meeting[];
tabType: TabType;
emptyStateType: TabType;
emptyStatePath: string;
showActions: boolean;
leaveActionText?: string;
};

export const MeetingList = ({
meetings,
tabType,
emptyStateType,
emptyStatePath,
showActions,
leaveActionText,
}: MeetingListProps) => {
const router = useRouter();

if (meetings.length === 0) {
return <EmptyState type={emptyStateType} onButtonClick={() => router.push(emptyStatePath)} />;
}

return (
<section className='flex w-full flex-col gap-4 px-4 py-4'>
{meetings.map((meeting) => (
<Card
key={meeting.id}
dateTime={meeting.dateTime}
images={meeting.images}
leaveAndChatActions={
showActions
? {
onLeave: () => console.log(leaveActionText || '모임 탈퇴', meeting.id),
onChat: () => router.push(`/chat/${meeting.id}`),
}
: undefined
}
location={meeting.location}
maxParticipants={meeting.maxParticipants}
nickName={meeting.nickName}
participantCount={meeting.participantCount}
tabType={tabType}
tags={meeting.tags}
title={meeting.title}
onClick={() => router.push(`/meetup/${meeting.id}`)}
/>
))}
</section>
);
};
37 changes: 11 additions & 26 deletions src/app/schedule/(components)/my.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
'use client';

import { useRouter } from 'next/navigation';
import { MeetingList } from './meeting-list';
import type { Meeting } from './types';

import Card from '@/components/shared/card';

const MOCK_MEETINGS = [
const MOCK_MEETINGS: Meeting[] = [
{
id: 2,
title: '주말 러닝 크루 모집',
Expand All @@ -19,28 +18,14 @@ const MOCK_MEETINGS = [
];

export default function My() {
const router = useRouter();

return (
<section className='flex w-full flex-col gap-4 px-4 py-4'>
{MOCK_MEETINGS.map((meeting) => (
<Card
key={meeting.id}
dateTime={meeting.dateTime}
images={meeting.images}
leaveAndChatActions={{
onLeave: () => console.log('모임 탈퇴', meeting.id),
onChat: () => router.push(`/chat/${meeting.id}`),
}}
location={meeting.location}
maxParticipants={meeting.maxParticipants}
nickName={meeting.nickName}
participantCount={meeting.participantCount}
tags={meeting.tags}
title={meeting.title}
onClick={() => router.push(`/meetup/${meeting.id}`)}
/>
))}
</section>
<MeetingList
emptyStatePath='/post-meetup'
emptyStateType='my'
leaveActionText='모임 취소'
meetings={MOCK_MEETINGS}
showActions={true}
tabType='my'
/>
);
}
13 changes: 13 additions & 0 deletions src/app/schedule/(components)/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export type Meeting = {
id: number;
title: string;
images: string[];
location: string;
dateTime: string;
nickName: string;
participantCount: number;
maxParticipants: number;
tags: string[];
};

export type TabType = 'current' | 'my' | 'history';
28 changes: 28 additions & 0 deletions src/components/shared/card/card-profile/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Image from 'next/image';

type CardProfileProps = {
nickName: string;
profileImage?: string | null;
size?: number;
};

const DEFAULT_SIZE = 16;

export const CardProfile = ({ nickName, profileImage, size = DEFAULT_SIZE }: CardProfileProps) => {
return (
<div className='mt-3 flex items-center gap-1.5'>
{profileImage ? (
<Image
width={size}
className='rounded-full object-cover'
alt={nickName}
height={size}
src={profileImage}
/>
) : (
<div className='rounded-full bg-gray-600' style={{ width: size, height: size }} />
)}
<span className='text-text-xs-medium text-gray-900'>{nickName}</span>
</div>
);
};
Loading