Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3bf3c40
chore: 불필요한 .lazy 라우트 제거
dioo1461 Jun 8, 2025
21be09e
refactor: Rename defaultValue to initialValue in SegmentControl
dioo1461 Mar 16, 2025
a111e5d
refactor: Rename AttendType to OngoingScheduleAttendType
dioo1461 Mar 16, 2025
fadc54e
feat: 확정되지 않은 일정 섹션의 선택 상태가 유지되도록, 상태 관리 책임을 useState에서 jotai로 이전
dioo1461 Mar 16, 2025
eff6d05
chore: 빌드 에러 해결
dioo1461 Mar 16, 2025
66d11f0
refactor: Rename handlePageChange to setCurrentPage for clarity
dioo1461 Mar 16, 2025
573d51b
chore: lint fix
dioo1461 Jun 12, 2025
e34b565
chore: rebase 단계에서 누락된 변경사항 반영
dioo1461 Jun 26, 2025
b51ce78
feat: segmentValue에 제네릭 타입 주입 가능하게 구현
dioo1461 Jun 27, 2025
2fcae35
Revert "feat: segmentValue에 제네릭 타입 주입 가능하게 구현"
dioo1461 Jun 27, 2025
bd4bc54
chore: SegmentControl에 jsdoc 추가
dioo1461 Jun 27, 2025
9df6a06
feat: 페이지 이동 시에도 segment의 상태가 유지되도록 구현
dioo1461 Jun 27, 2025
459ae41
refactor: SegmentControlProps의 value 관련 타입을 SegmentOption['value']로 통일
dioo1461 Jun 27, 2025
44a7b33
refactor: SegmentValue 제네릭 타이핑
dioo1461 Jun 27, 2025
e0e8831
fix: 각 자식 컴포넌트가 각기 다른 context를 사용하게 되던 문제 수정
dioo1461 Jun 27, 2025
f6d8889
chore: 불필요한 as 타입변환 제거
dioo1461 Jun 27, 2025
18be1ad
refactor: simplify setSelectedIndex function in OngoingScheduleList
dioo1461 Jun 27, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const DiscussionRank = () => {
return (
<SegmentControl
className={segmentControlStyle}
defaultValue='participant'
initialValue='participant'
segmentOptions={segmentOptions}
style='weak'
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MINUTE_IN_MILLISECONDS } from '@endolphin/core/utils';
import { request } from '@utils/fetch';

import type {
AttendType,
OngoingScheduleAttendType,
OngoingSchedulesResponse,
UpcomingScheduleDetailsResponse,
UpcomingSchedulesResponse,
Expand Down Expand Up @@ -34,7 +34,7 @@ export const schedulesApi = {
getOngoingSchedules: async (
page: number,
size: number,
attendType: AttendType,
attendType: OngoingScheduleAttendType,
): Promise<OngoingSchedulesResponse> => {
const response = await request.get(ENDPOINT_PREFIX + '/ongoing', {
params: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AttendType } from '../model';
import type { OngoingScheduleAttendType } from '../model';

export const sharedScheduleKey = ['shared-schedule'];

Expand All @@ -8,7 +8,7 @@ export const upcomingDetailsQueryKey = (discussionId: string) => ['upcomingDetai

export const ongoingQueryKey = {
all: [...sharedScheduleKey, 'ongoing'],
detail: (page: number, size: number, type: AttendType) =>
detail: (page: number, size: number, type: OngoingScheduleAttendType) =>
[...ongoingQueryKey.all, page, size, type],
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { QueryClient } from '@tanstack/react-query';

import { type AttendType, FINISHED_SCHEDULE_FETCH_SIZE } from '../model';
import type { OngoingScheduleAttendType } from '../model';
import { FINISHED_SCHEDULE_FETCH_SIZE } from '../model';
import { sharedSchedulesQueryOptions } from './queryOptions';

export const prefetchUpcomingSchedules = async (queryClient: QueryClient) => {
Expand All @@ -11,7 +12,7 @@ export const prefetchOngoingSchedules = async (
queryClient: QueryClient,
page: number,
size: number,
attendType: AttendType,
attendType: OngoingScheduleAttendType,
) => {
await queryClient.prefetchQuery(sharedSchedulesQueryOptions.ongoing(page, size, attendType));
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import type {
UpcomingScheduleDetailsResponse,
UpcomingSchedulesResponse,
} from '../model';
import type { AttendType, OngoingSchedulesResponse } from '../model/ongoingSchedules';
import type {
OngoingScheduleAttendType,
OngoingSchedulesResponse,
} from '../model/ongoingSchedules';
import { sharedSchedulesQueryOptions } from './queryOptions';

export const useUpcomingQuery = () => useQuery<UpcomingSchedulesResponse>(
Expand All @@ -18,12 +21,16 @@ export const useUpcomingDetailsQuery = (discussionId: string) => (
)
);

export const useOngoingQuery = (page: number, size: number, attendType: AttendType) =>
export const useOngoingQuery = (
page: number,
size: number,
attendType: OngoingScheduleAttendType,
) =>
useQuery<OngoingSchedulesResponse>(
sharedSchedulesQueryOptions.ongoing(page, size, attendType),
);

export const useFinishedQuery = (page: number, size: number, year: number) =>
useQuery<FinishedSchedulesResponse>(
sharedSchedulesQueryOptions.finished(page, size, year),
);
);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import { keepPreviousData } from '@tanstack/react-query';

import type { AttendType } from '../model';
import type { OngoingScheduleAttendType } from '../model';
import { schedulesApi } from '.';
import {
finishedQueryKey,
Expand All @@ -19,7 +19,7 @@ export const sharedSchedulesQueryOptions = {
queryKey: upcomingDetailsQueryKey(discussionId),
queryFn: () => schedulesApi.getUpcomingScheduleDetail(discussionId),
}),
ongoing: (page: number, size: number, attendtype: AttendType) => ({
ongoing: (page: number, size: number, attendtype: OngoingScheduleAttendType) => ({
queryKey: ongoingQueryKey.detail(page, size, attendtype),
queryFn: () => schedulesApi.getOngoingSchedules(page, size, attendtype),
}),
Expand All @@ -28,4 +28,4 @@ export const sharedSchedulesQueryOptions = {
queryFn: () => schedulesApi.getFinishedSchedules(page, size, year),
placeholderData: keepPreviousData,
}),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const OngoingSchedulesResponseSchema = z.object({
ongoingDiscussions: z.array(OngoingScheduleSchema),
});

export type AttendType = 'HOST' | 'ATTENDEE' | 'ALL';
export type OngoingScheduleAttendType = 'HOST' | 'ATTENDEE' | 'ALL';

export type OngoingSchedulesResponse = z.infer<typeof OngoingSchedulesResponseSchema>;
export type OngoingSchedule = z.infer<typeof OngoingScheduleSchema>;
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { vars } from '@endolphin/theme';
import { Flex, Pagination, Text } from '@endolphin/ui';
import { useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import { useAtom } from 'jotai';

import { ongoingSegmentAtomFamily } from '@/store/home';

import { prefetchOngoingSchedules } from '../../api/prefetch';
import { useOngoingQuery } from '../../api/queries';
Expand Down Expand Up @@ -30,16 +32,16 @@ interface OngoingScheduleListProps {
segmentOption: OngoingSegmentOption;
}

// TODO: useEffect 뺄 수 있으면 다른 걸로 대체
const OngoingScheduleList = ({ segmentOption }: OngoingScheduleListProps) => {
const queryClient = useQueryClient();
const [currentPage, handlePageChange] = useState(1);
const [selectedIndex, setSelectedIndex] = useState(0);
const { data, isPending } = useOngoingQuery(currentPage, PAGE_SIZE, segmentOption.value );
if (isPending) return <div>pending...</div>;
if (!data || data.ongoingDiscussions.length === 0)
return <NoDataAlt segmentValue={segmentOption.value} />;
const [segmentAtom, setSegmentAtom] = useAtom(ongoingSegmentAtomFamily(segmentOption.value));
const setPage = (page: number) => setSegmentAtom((prev) => ({ ...prev, page }));
const setListIndex = (index: number) => setSegmentAtom((prev) => ({ ...prev, listIndex: index }));

const { data, isPending } = useOngoingQuery(segmentAtom.page, PAGE_SIZE, segmentOption.value);

if (isPending) return <div>pending...</div>;
if (!data?.ongoingDiscussions.length) return <NoDataAlt segmentValue={segmentOption.value} />;
return (
<div className={mainContainerStyle}>
<Flex
Expand All @@ -50,30 +52,28 @@ const OngoingScheduleList = ({ segmentOption }: OngoingScheduleListProps) => {
>
<ScheduleItems
schedules={data.ongoingDiscussions}
selectedIndex={selectedIndex}
setSelectedIndex={setSelectedIndex}
selectedIndex={segmentAtom.listIndex}
setSelectedIndex={setListIndex}
/>
<Pagination
className={paginationStyle}
currentPage={currentPage}
currentPage={segmentAtom.page}
onPageButtonHover={(page) =>
prefetchOngoingSchedules(queryClient, page, PAGE_SIZE, segmentOption.value )}
prefetchOngoingSchedules(queryClient, page, PAGE_SIZE, segmentOption.value)}
onPageChange={(page: number) => {
setSelectedIndex(0);
handlePageChange(page);
setListIndex(0);
setPage(page);
}}
totalPages={data.totalPages}
/>
</Flex>
<ScheduleDetails discussionId={data.ongoingDiscussions[selectedIndex].discussionId} />
<ScheduleDetails discussionId={data.ongoingDiscussions[segmentAtom.listIndex].discussionId} />
</div>
);
};

interface ScheduleItemsProps {
schedules: NonNullable<
ReturnType<typeof useOngoingQuery>['data']
>['ongoingDiscussions'];
schedules: NonNullable<ReturnType<typeof useOngoingQuery>['data']>['ongoingDiscussions'];
selectedIndex: number;
setSelectedIndex: (index: number) => void;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@

import { Flex, SegmentControl, Text } from '@endolphin/ui';
import { Flex, SegmentControl, Text } from '@endolphin/ui';
import { useQueryClient } from '@tanstack/react-query';
import { useAtom } from 'jotai';

import { ongoingSegmentValueAtom } from '@/store/home';

import { prefetchOngoingSchedules } from '../../api/prefetch';
import { useOngoingQuery } from '../../api/queries';
import { sharedSchedulesQueryOptions } from '../../api/queryOptions';
import { type AttendType, ONGOING_SCHEDULE_FETCH_SIZE } from '../../model/';
import type { OngoingScheduleAttendType } from '../../model/';
import { ONGOING_SCHEDULE_FETCH_SIZE } from '../../model/';
import { ongoingFallbackContainerStyle } from '../Fallbacks/index.css';
import OngoingFallback from '../Fallbacks/OngoingFallback';
import { containerStyle, segmentControlStyle, titleStyle } from './index.css';
import OngoingScheduleList, { PAGE_SIZE } from './OngoingScheduleList';

export interface OngoingSegmentOption {
label: string;
value: AttendType;
value: OngoingScheduleAttendType;
}

const segmentOptions: OngoingSegmentOption[] = [
Expand All @@ -29,12 +32,15 @@ const OngoingSchedules = () => (
justify='flex-start'
width='full'
>
<Text className={titleStyle} typo='h2'>확정되지 않은 일정</Text>
<Text className={titleStyle} typo='h2'>
확정되지 않은 일정
</Text>
<Content />
</Flex>
);

const Content = () => {
const [segmentValue, setSegmentValue] = useAtom(ongoingSegmentValueAtom);
const queryClient = useQueryClient();
const { data, isPending } = useOngoingQuery(1, 6, 'ALL');
if (!data || isPending) return <div className={ongoingFallbackContainerStyle} />;
Expand All @@ -44,26 +50,28 @@ const Content = () => {
);
return <OngoingFallback />;
}

return (
<SegmentControl
className={segmentControlStyle}
defaultValue='ALL'
onButtonHover={(value) => prefetchOngoingSchedules(
// TODO: segmentOption value의 타입을 제네릭으로 지정할 수 있게 구현 (as 변환 리팩토룅)
queryClient, 1, PAGE_SIZE, value as AttendType,
)}
initialValue={segmentValue}
onButtonHover={(value) =>
prefetchOngoingSchedules(
queryClient,
1,
PAGE_SIZE,
value,
)}
onValueChange={(value) => setSegmentValue(value)}
Copy link
Contributor

Choose a reason for hiding this comment

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

p3;
onValueChange={setSegmentValue} 이렇게만 넘겨도 될 것 같습니당

segmentOptions={segmentOptions}
>
{segmentOptions.map((option, idx) => (
<SegmentControl.Content key={`${option.value}-${idx}`} value={option.value}>
<OngoingScheduleList
segmentOption={option}
/>
<OngoingScheduleList segmentOption={option} />
</SegmentControl.Content>
))}
</SegmentControl>
);
};

export default OngoingSchedules;
export default OngoingSchedules;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { formatDateToDdayString } from '@endolphin/core/utils';
import { Chip, Flex, Text } from '@endolphin/ui';
import { useUpcomingDetailsQuery } from '@features/shared-schedule/api/queries';
import { useParams } from '@tanstack/react-router';

import { useUpcomingDetailsQuery } from '@/features/shared-schedule/api/queries';
import TimelineScheduleModal from '@/features/timeline-schedule/ui';

import Header from './Header';
Expand Down Expand Up @@ -60,4 +60,4 @@ const TopBarContent = ({
</Flex>
);

export default UpcomingScheduleDetailPage;
export default UpcomingScheduleDetailPage;

This file was deleted.

This file was deleted.

This file was deleted.

12 changes: 0 additions & 12 deletions frontend/apps/client/src/routes/login/index.lazy.tsx

This file was deleted.

20 changes: 20 additions & 0 deletions frontend/apps/client/src/store/home/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { atom } from 'jotai';
import { atomFamily } from 'jotai/utils';

import type { OngoingScheduleAttendType } from '@/features/shared-schedule/model';

export const ongoingSegmentValueAtom = atom<OngoingScheduleAttendType>('ALL');

export interface OngoingSegmentStateAtom {
listIndex: number;
page: number;
}

export const ongoingSegmentAtomFamily = atomFamily((_: OngoingScheduleAttendType) =>
atom({
listIndex: 0,
page: 1,
} as OngoingSegmentStateAtom),
Comment on lines +14 to +17
Copy link
Contributor

Choose a reason for hiding this comment

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

p3;
단언문보다는 제네릭 활용이 더 안정성 있을 것 같습니다!

Suggested change
atom({
listIndex: 0,
page: 1,
} as OngoingSegmentStateAtom),
atom<OngoingSegmentStateAtom>({
listIndex: 0,
page: 1,
}),

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 좋습니다!

);

export const ongoingListIndexAtom = atom(0);
Loading