From 57812a96b63b4c64a3ec0ee25bdd999299eb1531 Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 00:55:02 +0900 Subject: [PATCH 01/37] feat : add icon for appbar --- src/assets/icon/icon-user-square.svg | 3 +++ src/assets/icon/index.ts | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 src/assets/icon/icon-user-square.svg diff --git a/src/assets/icon/icon-user-square.svg b/src/assets/icon/icon-user-square.svg new file mode 100644 index 0000000..7c81cc3 --- /dev/null +++ b/src/assets/icon/icon-user-square.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/index.ts b/src/assets/icon/index.ts index e022a39..d25f58e 100644 --- a/src/assets/icon/index.ts +++ b/src/assets/icon/index.ts @@ -16,6 +16,7 @@ import NotificationIcon from './icon-notification.png'; import ResultIcon from './icon-result.png'; import TextBoxIcon from './icon-textbox.svg'; import UserIcon from './icon-user.svg'; +import UserSquareIcon from './icon-user-square.svg'; import VoteCompleteIcon from './icon-vote-complete.png'; import VoteIcon from './icon-vote.svg'; import WriteIcon from './icon-write.svg'; @@ -38,6 +39,7 @@ export { ResultIcon, TextBoxIcon, UserIcon, + UserSquareIcon, VerifiedCheckIcon, VoteCompleteIcon, VoteIcon, From d4e538a18a81e3023c059f37c866ed83defd613f Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 01:05:28 +0900 Subject: [PATCH 02/37] feat : add icon at `AdminAppBar` --- src/shared/ui/AppBar.tsx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/shared/ui/AppBar.tsx b/src/shared/ui/AppBar.tsx index ec1cf6a..5875f25 100644 --- a/src/shared/ui/AppBar.tsx +++ b/src/shared/ui/AppBar.tsx @@ -1,5 +1,11 @@ /* eslint-disable react-refresh/only-export-components */ -import { BackButton, LogoutIcon, UserIcon, WriteIcon } from '@/assets/icon'; +import { + BackButton, + LogoutIcon, + UserIcon, + UserSquareIcon, + WriteIcon, +} from '@/assets/icon'; import { HomeBg, LoginBg, VoteBg } from '@/assets/image'; import type { MouseEvent } from 'react'; @@ -21,13 +27,13 @@ export const HomeAppBar = ( renderRight: () => ( <> + ), }); From 79e27ad8590a8ab0e4f7d9b1aa33e51690099ade Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 01:05:44 +0900 Subject: [PATCH 03/37] feat : add logout logic at `onLogoutClick` function --- src/screen/admin-home/ui/AdminHomeScreen.tsx | 7 ++++++- src/screen/home/ui/HomeScreen.tsx | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/screen/admin-home/ui/AdminHomeScreen.tsx b/src/screen/admin-home/ui/AdminHomeScreen.tsx index a57e615..42f409c 100644 --- a/src/screen/admin-home/ui/AdminHomeScreen.tsx +++ b/src/screen/admin-home/ui/AdminHomeScreen.tsx @@ -2,6 +2,7 @@ import { useFlow } from '@/app/stackflow'; import { VoteBg } from '@/assets/image'; import { PATH } from '@/shared/constants'; import { AdminAppBar } from '@/shared/ui'; +import { logout } from '@/shared/utils'; import { AdminHomeContainer } from '@/widgets/admin-home/ui'; import { AppScreen } from '@stackflow/plugin-basic-ui'; @@ -13,8 +14,12 @@ export default function AdminHomeScreen() { preventSwipeBack backgroundImage={`url(${VoteBg})`} appBar={AdminAppBar( - () => replace(PATH.LOGIN, {}), + () => { + replace(PATH.LOGIN, {}, { animate: false }); + logout(); + }, () => push(PATH.NOTICE_CREATE, {}), + () => replace(PATH.HOME, {}), )} > diff --git a/src/screen/home/ui/HomeScreen.tsx b/src/screen/home/ui/HomeScreen.tsx index 7f967b8..76c0c48 100644 --- a/src/screen/home/ui/HomeScreen.tsx +++ b/src/screen/home/ui/HomeScreen.tsx @@ -5,6 +5,7 @@ import { HomeAppBar } from '@/shared/ui'; import { HomeContainer } from '@/widgets/home/ui'; import { useFlow } from '@/app/stackflow'; import { PATH } from '@/shared/constants'; +import { logout } from '@/shared/utils'; export default function HomeScreen() { const { replace } = useFlow(); @@ -14,7 +15,10 @@ export default function HomeScreen() { preventSwipeBack backgroundImage={`url(${HomeBg})`} appBar={HomeAppBar( - () => replace(PATH.LOGIN, {}), + () => { + replace(PATH.LOGIN, {}, { animate: false }); + logout(); + }, () => {}, )} > From 0c272bf49234fe8d328ed8158d2a503999075d67 Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 01:57:29 +0900 Subject: [PATCH 04/37] feat : implement logic fetches election data by status --- src/features/admin-dashboard/api/election.ts | 19 +++++++++++++++++++ src/features/admin-dashboard/api/index.ts | 1 + src/shared/api/requests.ts | 1 + 3 files changed, 21 insertions(+) create mode 100644 src/features/admin-dashboard/api/election.ts create mode 100644 src/features/admin-dashboard/api/index.ts diff --git a/src/features/admin-dashboard/api/election.ts b/src/features/admin-dashboard/api/election.ts new file mode 100644 index 0000000..c9672f7 --- /dev/null +++ b/src/features/admin-dashboard/api/election.ts @@ -0,0 +1,19 @@ +import { REQUEST, userGet } from '@/shared/api'; +import type { Election, VoteStatus } from '@/shared/types'; +import { useQuery } from '@tanstack/react-query'; + +const fetchElectionByStatus = async (status: VoteStatus) => { + const response = await userGet({ + request: REQUEST.ELECTION_STATUS, + params: { status: status }, + }); + return response.data; +}; + +export const useFetchElectionByStatus = (status: VoteStatus) => { + return useQuery({ + queryKey: ['election-status', `${status}`], + queryFn: () => fetchElectionByStatus(status), + staleTime: 60 * 5, + }); +}; diff --git a/src/features/admin-dashboard/api/index.ts b/src/features/admin-dashboard/api/index.ts new file mode 100644 index 0000000..71fe4e1 --- /dev/null +++ b/src/features/admin-dashboard/api/index.ts @@ -0,0 +1 @@ +export * from './election'; diff --git a/src/shared/api/requests.ts b/src/shared/api/requests.ts index acf0a63..ed51f73 100644 --- a/src/shared/api/requests.ts +++ b/src/shared/api/requests.ts @@ -4,6 +4,7 @@ export const REQUEST = { JOIN: '/auth/kakao/signup', REFRESH: '/auth/refresh', ELECTION_ALL: '/api/elections/all', + ELECTION_STATUS: '/api/elections/status', NOTICE_CAMPUS: '/api/notices/notices/campus/', NOTICE: '/api/notices/', CANDIDATE: '/api/candidates/all/', From 7be72f0504003da3482c3a6233718f1ac9729950 Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 01:58:03 +0900 Subject: [PATCH 05/37] feat : change `VoteStatus` type --- src/shared/types/vote.ts | 2 +- src/widgets/admin-dashboard/ui/AdminDashboardContainer.tsx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shared/types/vote.ts b/src/shared/types/vote.ts index 40fadc1..d82cc1c 100644 --- a/src/shared/types/vote.ts +++ b/src/shared/types/vote.ts @@ -1 +1 @@ -export type VoteStatus = '진행중' | '종료' | '예정'; +export type VoteStatus = 'ongoing' | 'ended' | 'upcoming'; diff --git a/src/widgets/admin-dashboard/ui/AdminDashboardContainer.tsx b/src/widgets/admin-dashboard/ui/AdminDashboardContainer.tsx index c0535f6..ee798b7 100644 --- a/src/widgets/admin-dashboard/ui/AdminDashboardContainer.tsx +++ b/src/widgets/admin-dashboard/ui/AdminDashboardContainer.tsx @@ -1,11 +1,10 @@ import { CardList } from '@/features/admin-dashboard/ui'; -import type { VoteStatus } from '@/shared/types'; import { cn } from '@/shared/utils'; import { useState } from 'react'; export default function AdminDashboardContainer() { const [selected, setSelected] = useState(0); - const STATUS: VoteStatus[] = ['진행중', '종료', '예정']; + const STATUS = ['진행중', '종료', '예정']; return (
From 1976edcce04932924ca730a3f14b2cb08102a10e Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 01:58:33 +0900 Subject: [PATCH 06/37] feat : show real data at admin dashboard screen --- src/features/admin-dashboard/ui/CardList.tsx | 63 ++++++++++++++------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/src/features/admin-dashboard/ui/CardList.tsx b/src/features/admin-dashboard/ui/CardList.tsx index 09adf57..1315a35 100644 --- a/src/features/admin-dashboard/ui/CardList.tsx +++ b/src/features/admin-dashboard/ui/CardList.tsx @@ -1,25 +1,52 @@ -import type { VoteStatus } from '@/shared/types'; -// import { Card } from '@/shared/ui'; -import { VOTE_MOCK } from '@/features/admin-dashboard/mock'; +import type { Election, VoteStatus } from '@/shared/types'; +import { Card } from '@/shared/ui'; +import { getDate } from '@/shared/utils'; -export default function CardList({ status }: { status: VoteStatus }) { - const data = VOTE_MOCK.filter( - ({ status: voteStatus }) => voteStatus === status, +import { useFetchElectionByStatus } from '@/features/admin-dashboard/api'; + +export default function CardList({ status }: { status: string }) { + const VOTE_STATUS: Record = { + 진행중: 'ongoing', + 예정: 'upcoming', + 종료: 'ended', + }; + const { data, isError, isFetching } = useFetchElectionByStatus( + VOTE_STATUS[status], ); - console.log(data); - + + const renderElection = (data: Election[]) => { + if (isError) + return ( +
+ 투표를 가져오던 중 오류가 발생했어요! +
+ ); + if (!isFetching && data.length === 0) + return ( +
투표가 없어요
+ ); + if (data && data.length > 0) + return ( + <> + {data.map(({ id, campus, title, startAt, endAt }, index) => ( + + ))} + + ); + return <>; + }; + return (
-{/* {data.map(({ id, campus, status, title, date }, index) => ( - - ))} */} + {renderElection(data || [])}
); } From 7eabc917c26375df7eb3e7fcd8873a2710169fe1 Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 06:09:35 +0900 Subject: [PATCH 07/37] refactor : remove `Button` component at container due to make form component --- .../notice-create/ui/NoticeCreateContainer.tsx | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/widgets/notice-create/ui/NoticeCreateContainer.tsx b/src/widgets/notice-create/ui/NoticeCreateContainer.tsx index 1e2c0b9..0a986cb 100644 --- a/src/widgets/notice-create/ui/NoticeCreateContainer.tsx +++ b/src/widgets/notice-create/ui/NoticeCreateContainer.tsx @@ -1,21 +1,5 @@ -import { useFlow } from '@/app/stackflow'; import { NoticeForm } from '@/features/notice-create/ui'; -import { Button } from '@/shared/ui'; export default function NoticeCreateContainer() { - const { pop } = useFlow(); - return ( - <> - -
- -
- - ); + return ; } From 70dabe83f195fea2872e1bb7c327cff3a1d0cd19 Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 06:10:08 +0900 Subject: [PATCH 08/37] refactor : move `Notice` type to shared layer --- src/features/notice/types/index.ts | 1 - src/features/notice/types/notice.ts | 15 --------------- src/shared/types/index.ts | 2 ++ src/shared/types/notice.ts | 18 ++++++++++++++++++ 4 files changed, 20 insertions(+), 16 deletions(-) delete mode 100644 src/features/notice/types/index.ts delete mode 100644 src/features/notice/types/notice.ts create mode 100644 src/shared/types/notice.ts diff --git a/src/features/notice/types/index.ts b/src/features/notice/types/index.ts deleted file mode 100644 index 6351718..0000000 --- a/src/features/notice/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './notice'; diff --git a/src/features/notice/types/notice.ts b/src/features/notice/types/notice.ts deleted file mode 100644 index 0ea5c2c..0000000 --- a/src/features/notice/types/notice.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type NoticeType = 'UPCOMING' | 'NOTIFY'; - -export type NoticeListType = NoticeType | 'ONGOING' | 'COMPLETED'; - -export type Notice = { - id: number; - title: string; - startAt: string; - endAt: string; - noticeType: NoticeType; -}; - -export type NoticeList = Omit & { - noticeStatus: NoticeListType; -}; diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts index eda329a..78cd548 100644 --- a/src/shared/types/index.ts +++ b/src/shared/types/index.ts @@ -4,3 +4,5 @@ export * from './election'; export * from './path'; export * from './user'; export * from './vote'; +export * from './util'; +export * from './notice'; diff --git a/src/shared/types/notice.ts b/src/shared/types/notice.ts new file mode 100644 index 0000000..5c48dc3 --- /dev/null +++ b/src/shared/types/notice.ts @@ -0,0 +1,18 @@ +import type { Campus } from '@/shared/types'; + +export type NoticeStatus = 'UPCOMING' | 'NOTIFY' | 'ONGOING' | 'COMPLETED'; +export type NoticeType = 'NOTIFY' | 'ELECTION'; + +export type Notice = { + title: string; + content: string; + noticeType: NoticeType; + campus: Campus; + startAt: string; + endAt: string; +}; + +export type NoticeList = Omit & { + noticeStatus: NoticeStatus; + id: number; +}; From 24913f242025c2727321f211b6b074742c15a6f5 Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 06:11:00 +0900 Subject: [PATCH 09/37] feat : add constant of `NoticeType` --- src/shared/constants/index.ts | 1 + src/shared/constants/notice.ts | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 src/shared/constants/notice.ts diff --git a/src/shared/constants/index.ts b/src/shared/constants/index.ts index fbd4605..6459150 100644 --- a/src/shared/constants/index.ts +++ b/src/shared/constants/index.ts @@ -1,3 +1,4 @@ export * from './path'; export * from './bottomSheet'; export * from './campus'; +export * from './notice'; diff --git a/src/shared/constants/notice.ts b/src/shared/constants/notice.ts new file mode 100644 index 0000000..b28de7f --- /dev/null +++ b/src/shared/constants/notice.ts @@ -0,0 +1,6 @@ +import type { NoticeType } from '@/features/notice/types'; + +export const NOTICE_TYPE: Record = { + ELECTION: '선거 공지', + NOTIFY: '알림', +}; From a68448e32802ddf0d772df5252cbfcd786e61a67 Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 06:12:34 +0900 Subject: [PATCH 10/37] refactor : change type name and import --- src/features/notice/constants/status.ts | 4 ++-- src/features/notice/ui/NoticeItem.tsx | 4 ++-- src/shared/constants/notice.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/features/notice/constants/status.ts b/src/features/notice/constants/status.ts index dd5561b..387a303 100644 --- a/src/features/notice/constants/status.ts +++ b/src/features/notice/constants/status.ts @@ -1,4 +1,4 @@ -import type { NoticeListType } from '../types'; +import type { NoticeStatus } from '@/shared/types'; type StatusStyle = { label: string; @@ -6,7 +6,7 @@ type StatusStyle = { color: string; }; -export const NOTICE_STATUS: Record = { +export const NOTICE_STATUS: Record = { COMPLETED: { label: '종료', bgColor: '#F5F5F5', color: '#999' }, NOTIFY: { label: '알림', diff --git a/src/features/notice/ui/NoticeItem.tsx b/src/features/notice/ui/NoticeItem.tsx index f8e4d6c..337cdfc 100644 --- a/src/features/notice/ui/NoticeItem.tsx +++ b/src/features/notice/ui/NoticeItem.tsx @@ -1,5 +1,5 @@ import { MessageIcon, NotificationIcon } from '@/assets/icon'; -import type { NoticeList } from '../types'; +import type { NoticeList } from '@/shared/types'; import { useFlow } from '@/app/stackflow'; import { PATH } from '@/shared/constants'; @@ -21,7 +21,7 @@ export default function NoticeItem({ className="flex w-full flex-shrink-0 cursor-pointer items-center overflow-hidden py-6 focus:outline-none" onClick={() => push(PATH.NOTICE_CONTENT, { - notice: { id, title, startAt, endAt }, + notice: { id, title, startAt, endAt, noticeStatus }, }) } > diff --git a/src/shared/constants/notice.ts b/src/shared/constants/notice.ts index b28de7f..a11d600 100644 --- a/src/shared/constants/notice.ts +++ b/src/shared/constants/notice.ts @@ -1,4 +1,4 @@ -import type { NoticeType } from '@/features/notice/types'; +import type { NoticeType } from '@/shared/types'; export const NOTICE_TYPE: Record = { ELECTION: '선거 공지', From ec9c2f6aa258ecdd8141361b1b32e732bc94c15a Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 06:12:51 +0900 Subject: [PATCH 11/37] feat : implement logic submits notice creation --- src/features/notice-create/api/create.ts | 26 ++++++++++++++++++++++++ src/features/notice-create/api/index.ts | 1 + 2 files changed, 27 insertions(+) create mode 100644 src/features/notice-create/api/create.ts create mode 100644 src/features/notice-create/api/index.ts diff --git a/src/features/notice-create/api/create.ts b/src/features/notice-create/api/create.ts new file mode 100644 index 0000000..5f9149a --- /dev/null +++ b/src/features/notice-create/api/create.ts @@ -0,0 +1,26 @@ +import { useFlow } from '@/app/stackflow'; +import { useMutation } from '@tanstack/react-query'; + +import { REQUEST, userPost } from '@/shared/api'; +import type { Replace, WholeCampus, Notice } from '@/shared/types'; + +const submitNotice = async (data: Replace) => { + const response = await userPost({ + request: REQUEST.NOTICE.slice(0, -1), + data: data, + }); + return response; +}; + +export const useSubmitNotice = () => { + const { pop } = useFlow(); + + return useMutation({ + mutationFn: (data: Replace) => + submitNotice(data), + onSuccess: () => { + alert('공지 등록 성공!'); + pop({ animate: false }); + }, + }); +}; diff --git a/src/features/notice-create/api/index.ts b/src/features/notice-create/api/index.ts new file mode 100644 index 0000000..1e03cce --- /dev/null +++ b/src/features/notice-create/api/index.ts @@ -0,0 +1 @@ +export * from './create'; From a08cb088049a85634f362528ed83c02039352cf6 Mon Sep 17 00:00:00 2001 From: cho4u4o Date: Thu, 26 Jun 2025 06:14:34 +0900 Subject: [PATCH 12/37] feat : pass parameters with `rest` for better flexibility --- .../notice-create/ui/NoticeFormButton.tsx | 19 +++++++++++++++---- .../notice-create/ui/NoticeFormInput.tsx | 11 +++++++++-- src/features/vote-create/ui/VoteButton.tsx | 2 ++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/features/notice-create/ui/NoticeFormButton.tsx b/src/features/notice-create/ui/NoticeFormButton.tsx index db0c58d..e273076 100644 --- a/src/features/notice-create/ui/NoticeFormButton.tsx +++ b/src/features/notice-create/ui/NoticeFormButton.tsx @@ -1,15 +1,26 @@ import { cn } from '@/shared/utils'; -import { useState } from 'react'; +import type { HTMLAttributes } from 'react'; -export default function NoticeFormButton({ label }: { label: string }) { - const [selected, setSelected] = useState(false); +interface NoticeFormButtonProps extends HTMLAttributes { + label: string; + selected: boolean; +} + +export default function NoticeFormButton({ + label, + selected, + onClick, + ...rest +}: NoticeFormButtonProps) { return ( diff --git a/src/features/notice-create/ui/NoticeFormInput.tsx b/src/features/notice-create/ui/NoticeFormInput.tsx index c632ae3..ef574bc 100644 --- a/src/features/notice-create/ui/NoticeFormInput.tsx +++ b/src/features/notice-create/ui/NoticeFormInput.tsx @@ -1,5 +1,12 @@ -export default function NoticeFormInput() { +import type { HTMLAttributes } from 'react'; + +type NoticeFormInputProps = HTMLAttributes; + +export default function NoticeFormInput({ ...rest }: NoticeFormInputProps) { return ( - + ); } diff --git a/src/features/vote-create/ui/VoteButton.tsx b/src/features/vote-create/ui/VoteButton.tsx index 5f3ac36..9d814ef 100644 --- a/src/features/vote-create/ui/VoteButton.tsx +++ b/src/features/vote-create/ui/VoteButton.tsx @@ -10,12 +10,14 @@ export default function VoteButton({ arrowDown = false, label, onClick, + ...rest }: VoteButtonProps) { return (