Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
14 changes: 5 additions & 9 deletions apps/audience/src/entities/festival/api/festival.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,22 @@ import type {
WishListResponseData,
} from '@shared/types/festival';
import type {
AllFestivalsResponse,
FestivalsResponse,
NicknameResponse,
UpcomingFestivalResponse,
UpcomingFestivalsResponse,
UpcomingFestivalItem,
} from '@shared/types/home-response';
Comment on lines +10 to 12
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Suggest: FestivalsResponsehome-response 밖으로 분리해 주세요.

getAllFestivalsgetWishlists는 공용 festival entity API인데, 응답 타입이 @shared/types/home-response에 머물면 home이라는 페이지 의미가 entity 레이어로 스며듭니다. 이번처럼 재사용 범위가 넓어진 타입은 festival 전용 응답 타입 파일로 옮기거나 API 근처로 이동하는 편이 의존성 방향이 더 자연스럽습니다.

As per coding guidelines apps/**/src/entities/**: Entity 레이어예요. - 단일 도메인 개념을 표현해요. - 페이지/라우트 개념은 금지예요.

Also applies to: 15-18

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/audience/src/entities/festival/api/festival.ts` around lines 10 - 12,
The FestivalsResponse and UpcomingFestivalResponse types currently imported from
`@shared/types/home-response` bleed page-specific semantics into the festival
entity API; create a festival-specific response types file (e.g.,
festival-response.ts) next to the festival entity/API, move/define
FestivalsResponse and UpcomingFestivalResponse there, update imports in
functions like getAllFestivals and getWishlists to import from the new
festival-response module, and remove the dependency on
`@shared/types/home-response` so the entity layer no longer depends on a
page-scoped module.


export const getAllFestivals = (params: PageSizeParams = {}) =>
get<AllFestivalsResponse, PageSizeParams>(
END_POINT.GET_ALL_FESTIVALS,
params,
);
get<FestivalsResponse, PageSizeParams>(END_POINT.GET_ALL_FESTIVALS, params);

export const getPlannedFestivals = (params: PageSizeParams = {}) =>
get<UpcomingFestivalsResponse, PageSizeParams>(
get<FestivalsResponse, PageSizeParams>(
END_POINT.GET_PLANNED_FESTIVALS,
params,
);

export const getUpcomingFestival = (params: PageSizeParams = {}) =>
get<UpcomingFestivalResponse, PageSizeParams>(
get<UpcomingFestivalItem, PageSizeParams>(
END_POINT.GET_UPCOMING_FESTIVAL,
params,
);
Expand Down
19 changes: 19 additions & 0 deletions apps/audience/src/shared/types/festival.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
export interface Festival {
festivalId: number;
title: string;
mainImageUrl: string;
period: string;
status: '관람 중' | '관람 예정' | '관람 완료';
wishList: boolean;
dDay?: number;
}

export interface PaginationResponse {
currentPage: number;
totalPages: number;
totalElements: number;
size: number;
hasNext: boolean;
hasPrevious: boolean;
}

export interface WishListRequest {
wishList: boolean;
}
Expand Down
45 changes: 6 additions & 39 deletions apps/audience/src/shared/types/home-response.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,6 @@
export interface AllFestivalItem {
festivalId: number;
title: string;
mainImageUrl: string;
location: string;
period: string;
wishList: boolean;
dDay: number;
}
import type { Festival, PaginationResponse } from './festival';

export interface UpcomingFestivalItem {
festivalId: number;
title: string;
mainImageUrl: string;
location: string;
period: string;
status: string;
wishList: boolean;
dDay: number;
}

export interface PaginationResponse {
currentPage: number;
totalPages: number;
totalElements: number;
size: number;
hasNext: boolean;
hasPrevious: boolean;
}

export interface AllFestivalsResponse {
festivals: AllFestivalItem[];
pagination: PaginationResponse;
}

export interface UpcomingFestivalsResponse {
festivals: UpcomingFestivalItem[];
pagination: PaginationResponse;
}

export interface UpcomingFestivalResponse {
festivalId: number;
title: string;
mainImageUrl: string;
Expand All @@ -48,6 +10,11 @@ export interface UpcomingFestivalResponse {
dday: number;
}

export interface FestivalsResponse {
festivals: Festival[];
pagination: PaginationResponse;
}

export interface NicknameResponse {
nickname: string;
}
22 changes: 3 additions & 19 deletions apps/audience/src/shared/types/my-events-response.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
export interface MyEventsFestival {
festivalId: number;
title: string;
mainImageUrl: string;
period: string;
status: string;
wishList: boolean;
}

export interface MyEventsPagination {
currentPage: number;
totalPages: number;
totalElements: number;
size: number;
hasNext: boolean;
hasPrevious: boolean;
}
import type { Festival, PaginationResponse } from './festival';

export interface MyEventsResponse {
festivals: MyEventsFestival[];
pagination: MyEventsPagination;
festivals: Festival[];
pagination: PaginationResponse;
}
23 changes: 3 additions & 20 deletions apps/audience/src/shared/types/viewed-festival.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
export interface ViewedFestival {
festivalId: number;
title: string;
mainImageUrl: string;
period: string;
status: '관람 중' | '관람 예정' | '관람 완료';
wishList: boolean;
}

export interface Pagination {
currentPage: number;
totalPages: number;
totalElements: number;
size: number;
hasNext: boolean;
hasPrevious: boolean;
}

import type { Festival, PaginationResponse } from './festival';
export interface ViewedFestivalsResponse {
festivals: ViewedFestival[];
pagination: Pagination;
festivals: Festival[];
pagination: PaginationResponse;
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,96 @@
import type { KeyboardEvent } from 'react';

import { CardFestival } from '@amp/ads-ui';
import { FestivalStatusGroup } from '@amp/compositions';
import { formatDday } from '@amp/shared/utils';

import { useToggleWishListMutation } from '@features/usecase/toggle-wishlist/use-toggle-wishlist-mutation';

import type {
AllFestivalItem,
UpcomingFestivalItem,
} from '@shared/types/home-response';
import type { Festival } from '@shared/types/festival';

import FlagButton from '../flag-button/flag-button';

interface FestivalCardProps {
festival: AllFestivalItem | UpcomingFestivalItem;
onClick: () => void;
festival: Festival;
onCardClick: (festivalId: number) => void;
showWishList?: boolean;
showStatus?: boolean;
}

const FestivalCard = ({ festival, onClick }: FestivalCardProps) => {
const { festivalId, title, period, mainImageUrl, wishList, dDay } = festival;
const STATUS_BY_TEXT = {
'관람 중': 'current',
'관람 완료': 'completed',
'관람 예정': 'upcoming',
} as const;

const FestivalCard = ({
festival,
showWishList = true,
showStatus = true,
onCardClick,
}: FestivalCardProps) => {
const {
festivalId,
title,
period,
mainImageUrl,
wishList = false,
status,
dDay,
} = festival;

const { toggleWishList, isTogglePending } = useToggleWishListMutation(
festivalId,
wishList,
);

const chipStatus =
STATUS_BY_TEXT[status as keyof typeof STATUS_BY_TEXT] ?? 'completed';

const handleCardClick = () => {
onCardClick(festivalId);
};

const handleKeyDown = (event: KeyboardEvent<HTMLElement>) => {
if (event.currentTarget !== event.target) {
return;
}

if (event.key === 'Enter' || event.key === ' ') {
if (event.key === ' ') {
event.preventDefault();
}
handleCardClick();
}
};

return (
<CardFestival onClick={onClick}>
<CardFestival
role='button'
tabIndex={0}
onClick={handleCardClick}
onKeyDown={handleKeyDown}
>
<CardFestival.Image src={mainImageUrl} alt={title} />
<CardFestival.Body title={title} date={period}>
<CardFestival.Chip>
<FestivalStatusGroup dDay={formatDday(dDay)} isWishlist={wishList} />
<FestivalStatusGroup
dDay={typeof dDay === 'number' ? formatDday(dDay) : undefined}
status={chipStatus}
statusText={showStatus ? status : ''}
isWishlist={showWishList ? wishList : false}
/>
</CardFestival.Chip>
</CardFestival.Body>
<CardFestival.Button>
<FlagButton
selected={wishList}
onChange={toggleWishList}
disabled={isTogglePending}
/>
</CardFestival.Button>
{showWishList && (
<CardFestival.Button>
<FlagButton
selected={wishList}
onChange={toggleWishList}
disabled={isTogglePending}
/>
</CardFestival.Button>
)}
</CardFestival>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useNavigate } from 'react-router';
import { generatePath, useNavigate } from 'react-router';

import { EmptyView } from '@amp/ads-ui';

Expand All @@ -9,10 +9,7 @@ import {
} from '@widgets/home/constants/home-tabs';

import { ROUTE_PATH } from '@shared/constants/path';
import type {
AllFestivalItem,
UpcomingFestivalItem,
} from '@shared/types/home-response';
import type { Festival } from '@shared/types/festival';

import FestivalCard from '../festival-card/festival-card';
import HomeFestivalTabs from '../home-festival-tabs/home-festival-tabs';
Expand All @@ -22,8 +19,8 @@ import * as styles from './festival-section.css';
interface FestivalSectionProps {
selectedTab: TabValue;
onTabChange: (value: TabValue) => void;
allFestivals: AllFestivalItem[];
upcomingFestivals: UpcomingFestivalItem[];
allFestivals: Festival[];
upcomingFestivals: Festival[];
}

const FestivalSection = ({
Expand All @@ -34,8 +31,12 @@ const FestivalSection = ({
}: FestivalSectionProps) => {
const navigate = useNavigate();

const handleMoveToFestival = (festivalId: number) => () => {
navigate(ROUTE_PATH.NOTICE_LIST.replace(':eventId', String(festivalId)));
const handleCardClick = (festivalId: number) => {
navigate(
generatePath(ROUTE_PATH.NOTICE_LIST, {
eventId: String(festivalId),
}),
);
};

const targetFestivals =
Expand Down Expand Up @@ -67,7 +68,8 @@ const FestivalSection = ({
<li key={festival.festivalId}>
<FestivalCard
festival={festival}
onClick={handleMoveToFestival(festival.festivalId)}
showStatus={false}
onCardClick={handleCardClick}
/>
</li>
))}
Expand Down
Loading
Loading