From 75029451d61ab5afda03da64067cfa05714571bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EC=A4=80?= Date: Sun, 13 Sep 2026 16:44:50 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=EC=95=84=EC=B9=B4=EC=9D=B4=EB=B9=99=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=83=81=EC=84=B8=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=96=91?= =?UTF-8?q?=EC=98=86=20=ED=8C=A8=EB=94=A9=EA=B0=92=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/_components/DashboardItem.tsx | 2 +- src/app/mobile/admin/dashboard/page.tsx | 2 +- .../_components/ArchiveCard/index.tsx | 52 +++++ .../_components/YearFilter/index.tsx | 77 ++++++++ src/app/mobile/archiving/page.tsx | 184 ++++++++++++++++++ src/app/mobile/history/page.tsx | 6 +- src/app/mobile/layout.tsx | 3 +- .../main/_components/MainHeader/index.tsx | 2 +- src/app/mobile/main/page.tsx | 2 +- src/app/mobile/notification/page.tsx | 2 +- src/app/mobile/privacy-policy/page.tsx | 2 +- src/components/mobile/Dropdown/index.tsx | 12 +- src/components/mobile/Header/index.tsx | 2 +- .../mobile/NotificationItem/index.tsx | 2 +- src/types/archiveType.ts | 10 + 15 files changed, 345 insertions(+), 15 deletions(-) create mode 100644 src/app/mobile/archiving/_components/ArchiveCard/index.tsx create mode 100644 src/app/mobile/archiving/_components/YearFilter/index.tsx create mode 100644 src/app/mobile/archiving/page.tsx create mode 100644 src/types/archiveType.ts diff --git a/src/app/mobile/admin/dashboard/_components/DashboardItem.tsx b/src/app/mobile/admin/dashboard/_components/DashboardItem.tsx index a80f549..eb98d76 100644 --- a/src/app/mobile/admin/dashboard/_components/DashboardItem.tsx +++ b/src/app/mobile/admin/dashboard/_components/DashboardItem.tsx @@ -32,7 +32,7 @@ export default function DashboardItem({ const applicatedTime = convertTime(rentAt); return ( -
+
{itemImageUrl && ( diff --git a/src/app/mobile/admin/dashboard/page.tsx b/src/app/mobile/admin/dashboard/page.tsx index 42b229d..3e4d4e6 100644 --- a/src/app/mobile/admin/dashboard/page.tsx +++ b/src/app/mobile/admin/dashboard/page.tsx @@ -106,7 +106,7 @@ export default function Dashboard() {
-
+
신청 내역
diff --git a/src/app/mobile/archiving/_components/ArchiveCard/index.tsx b/src/app/mobile/archiving/_components/ArchiveCard/index.tsx new file mode 100644 index 0000000..d998ade --- /dev/null +++ b/src/app/mobile/archiving/_components/ArchiveCard/index.tsx @@ -0,0 +1,52 @@ +import { cn } from '@/lib/utils'; +import { ArchiveCardSize } from '@/types/archiveType'; + +interface ArchiveCardProps { + title: string; + date: string; + imageUrl: string; + size?: ArchiveCardSize; + onClick?: () => void; +} + +// 시안 카드 비율 (160x176 / 160x224 / 160x256) +// 좌우 20px 패딩에 맞춰 폭이 유동적이므로 높이는 비율로 계산 +const SIZE_CLASSES: Record = { + small: 'aspect-[10/11]', + medium: 'aspect-[5/7]', + large: 'aspect-[5/8]', +}; + +export default function ArchiveCard({ + title, + date, + imageUrl, + size = 'medium', + onClick, +}: ArchiveCardProps) { + return ( + + ); +} diff --git a/src/app/mobile/archiving/_components/YearFilter/index.tsx b/src/app/mobile/archiving/_components/YearFilter/index.tsx new file mode 100644 index 0000000..54d1c15 --- /dev/null +++ b/src/app/mobile/archiving/_components/YearFilter/index.tsx @@ -0,0 +1,77 @@ +'use client'; + +import { useRef } from 'react'; +import Dropdown from '@/components/mobile/Dropdown'; +import useDropdown from '@/hooks/useDropdown'; +import IconArrow from 'public/assets/icons/icon-arrow.svg'; + +interface YearFilterProps { + recentYears: number[]; + pastYears: number[]; + selectedYear: number; + onSelectYear: (year: number) => void; +} + +export default function YearFilter({ + recentYears, + pastYears, + selectedYear, + onSelectYear, +}: YearFilterProps) { + const { showDropdown, hideDropdown, isDropdownVisible } = useDropdown(); + const pastYearButtonRef = useRef(null); + + const isPastYearSelected = pastYears.includes(selectedYear); + const pastYearLabel = isPastYearSelected + ? `${selectedYear}` + : `~${pastYears[0]}`; + + const dropdownActions = pastYears.map((year) => ({ + title: `${year}`, + func: () => onSelectYear(year), + })); + + // 시안대로 높이 32px(12/16 + py-2)를 유지하기 위해 border 대신 outline 사용 + const chipClasses = (isActive: boolean, widthClass: string) => + `flex shrink-0 items-center justify-center gap-2 rounded-[20px] px-3 py-2 text-xs leading-4 tracking-tight outline outline-1 -outline-offset-1 ${widthClass} ${ + isActive + ? 'bg-main-tertiary font-semibold text-on-kookmin outline-on-kookmin' + : 'font-medium text-gray-secondary outline-gray-border' + }`; + + return ( +
+ {recentYears.map((year) => ( + + ))} + + {/* 남는 폭을 차지해서 드롭다운이 칩 왼쪽 ~ 페이지 오른쪽 여백까지 채우도록 함 */} +
+ + + +
+
+ ); +} diff --git a/src/app/mobile/archiving/page.tsx b/src/app/mobile/archiving/page.tsx new file mode 100644 index 0000000..97d5b2a --- /dev/null +++ b/src/app/mobile/archiving/page.tsx @@ -0,0 +1,184 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import ArchiveCard from '@/app/mobile/archiving/_components/ArchiveCard'; +import YearFilter from '@/app/mobile/archiving/_components/YearFilter'; +import { Archive } from '@/types/archiveType'; +import IconArrow from 'public/assets/icons/icon-arrow.svg'; +import IconSearch from 'public/assets/icons/icon-search.svg'; + +const RECENT_YEARS = [2026, 2025, 2024]; +const PAST_YEARS = [2023, 2022, 2021, 2020]; + +// TODO: API 연동 시 제거 +const ARCHIVES: Archive[] = [ + { + archiveId: 1, + title: '2025 체육대회', + date: '2025.05.04', + year: 2025, + imageUrl: 'https://placehold.co/470x257', + size: 'large', + }, + { + archiveId: 2, + title: '2025 간식행사', + date: '2025.05.04', + year: 2025, + imageUrl: 'https://placehold.co/253x187', + size: 'small', + }, + { + archiveId: 3, + title: '2025 새내기 배움터', + date: '2025.05.04', + year: 2025, + imageUrl: 'https://placehold.co/214x286', + size: 'medium', + }, + { + archiveId: 4, + title: '2025 동문패널톡', + date: '2025.05.04', + year: 2025, + imageUrl: 'https://placehold.co/448x281', + size: 'large', + }, + { + archiveId: 5, + title: '2025 해커톤', + date: '2025.05.04', + year: 2025, + imageUrl: 'https://placehold.co/470x257', + size: 'large', + }, + { + archiveId: 6, + title: '2025 MT', + date: '2025.05.04', + year: 2025, + imageUrl: 'https://placehold.co/253x187', + size: 'small', + }, + { + archiveId: 7, + title: '2025 종강총회', + date: '2025.05.04', + year: 2025, + imageUrl: 'https://placehold.co/214x286', + size: 'medium', + }, + { + archiveId: 8, + title: '2025 졸업전시', + date: '2025.05.04', + year: 2025, + imageUrl: 'https://placehold.co/448x281', + size: 'large', + }, + { + archiveId: 9, + title: '2024 체육대회', + date: '2024.05.04', + year: 2024, + imageUrl: 'https://placehold.co/470x257', + size: 'large', + }, + { + archiveId: 10, + title: '2024 새내기 배움터', + date: '2024.03.02', + year: 2024, + imageUrl: 'https://placehold.co/253x187', + size: 'small', + }, + { + archiveId: 11, + title: '2023 동문패널톡', + date: '2023.11.11', + year: 2023, + imageUrl: 'https://placehold.co/448x281', + size: 'medium', + }, +]; + +export default function Archiving() { + const router = useRouter(); + const [selectedYear, setSelectedYear] = useState(2025); + + const filteredArchives = useMemo( + () => ARCHIVES.filter((archive) => archive.year === selectedYear), + [selectedYear], + ); + + // 두 열로 나눠서 배치 (좌: 짝수 번째, 우: 홀수 번째) + const columns = useMemo( + () => [ + filteredArchives.filter((_, index) => index % 2 === 0), + filteredArchives.filter((_, index) => index % 2 === 1), + ], + [filteredArchives], + ); + + return ( +
+ {/* 헤더 */} +
+ +
+ 아카이빙 +
+ +
+ +
+ {/* 연도 필터 */} + + + {/* 아카이빙 목록 */} + {filteredArchives.length > 0 ? ( +
+ {columns.map((column, columnIndex) => ( +
+ {column.map((archive) => ( + + ))} +
+ ))} +
+ ) : ( +
+ 아카이빙 기록이 없습니다. +
+ )} +
+
+ ); +} diff --git a/src/app/mobile/history/page.tsx b/src/app/mobile/history/page.tsx index 1d9ce7c..5cf6032 100644 --- a/src/app/mobile/history/page.tsx +++ b/src/app/mobile/history/page.tsx @@ -198,10 +198,10 @@ export default function UserRentalList() { {/* 반납이 필요한 물품 */}
-
+
반납이 필요한 물품
-
+
{returnItems.items.length > 0 ? ( returnItemsWithKeys.map((item) => ( {/* 대여 내역 */} -
+
대여 내역
); } diff --git a/src/app/mobile/main/_components/MainHeader/index.tsx b/src/app/mobile/main/_components/MainHeader/index.tsx index 6a5006f..a569b91 100644 --- a/src/app/mobile/main/_components/MainHeader/index.tsx +++ b/src/app/mobile/main/_components/MainHeader/index.tsx @@ -41,7 +41,7 @@ export default function MainHeader() { return ( <> -
+
{user?.name}님{user?.isFeePaid ? : null}
diff --git a/src/app/mobile/main/page.tsx b/src/app/mobile/main/page.tsx index 523d043..8e77036 100644 --- a/src/app/mobile/main/page.tsx +++ b/src/app/mobile/main/page.tsx @@ -79,7 +79,7 @@ export default function MobileMain() { return (
-
+
diff --git a/src/app/mobile/notification/page.tsx b/src/app/mobile/notification/page.tsx index a1a0e8f..da3a1f5 100644 --- a/src/app/mobile/notification/page.tsx +++ b/src/app/mobile/notification/page.tsx @@ -57,7 +57,7 @@ export default function Notification() {
) : (
-
+
- ); -} diff --git a/src/app/mobile/archiving/_components/YearFilter/index.tsx b/src/app/mobile/archiving/_components/YearFilter/index.tsx deleted file mode 100644 index 54d1c15..0000000 --- a/src/app/mobile/archiving/_components/YearFilter/index.tsx +++ /dev/null @@ -1,77 +0,0 @@ -'use client'; - -import { useRef } from 'react'; -import Dropdown from '@/components/mobile/Dropdown'; -import useDropdown from '@/hooks/useDropdown'; -import IconArrow from 'public/assets/icons/icon-arrow.svg'; - -interface YearFilterProps { - recentYears: number[]; - pastYears: number[]; - selectedYear: number; - onSelectYear: (year: number) => void; -} - -export default function YearFilter({ - recentYears, - pastYears, - selectedYear, - onSelectYear, -}: YearFilterProps) { - const { showDropdown, hideDropdown, isDropdownVisible } = useDropdown(); - const pastYearButtonRef = useRef(null); - - const isPastYearSelected = pastYears.includes(selectedYear); - const pastYearLabel = isPastYearSelected - ? `${selectedYear}` - : `~${pastYears[0]}`; - - const dropdownActions = pastYears.map((year) => ({ - title: `${year}`, - func: () => onSelectYear(year), - })); - - // 시안대로 높이 32px(12/16 + py-2)를 유지하기 위해 border 대신 outline 사용 - const chipClasses = (isActive: boolean, widthClass: string) => - `flex shrink-0 items-center justify-center gap-2 rounded-[20px] px-3 py-2 text-xs leading-4 tracking-tight outline outline-1 -outline-offset-1 ${widthClass} ${ - isActive - ? 'bg-main-tertiary font-semibold text-on-kookmin outline-on-kookmin' - : 'font-medium text-gray-secondary outline-gray-border' - }`; - - return ( -
- {recentYears.map((year) => ( - - ))} - - {/* 남는 폭을 차지해서 드롭다운이 칩 왼쪽 ~ 페이지 오른쪽 여백까지 채우도록 함 */} -
- - - -
-
- ); -} diff --git a/src/app/mobile/archiving/page.tsx b/src/app/mobile/archiving/page.tsx deleted file mode 100644 index 97d5b2a..0000000 --- a/src/app/mobile/archiving/page.tsx +++ /dev/null @@ -1,184 +0,0 @@ -'use client'; - -import { useMemo, useState } from 'react'; -import { useRouter } from 'next/navigation'; -import ArchiveCard from '@/app/mobile/archiving/_components/ArchiveCard'; -import YearFilter from '@/app/mobile/archiving/_components/YearFilter'; -import { Archive } from '@/types/archiveType'; -import IconArrow from 'public/assets/icons/icon-arrow.svg'; -import IconSearch from 'public/assets/icons/icon-search.svg'; - -const RECENT_YEARS = [2026, 2025, 2024]; -const PAST_YEARS = [2023, 2022, 2021, 2020]; - -// TODO: API 연동 시 제거 -const ARCHIVES: Archive[] = [ - { - archiveId: 1, - title: '2025 체육대회', - date: '2025.05.04', - year: 2025, - imageUrl: 'https://placehold.co/470x257', - size: 'large', - }, - { - archiveId: 2, - title: '2025 간식행사', - date: '2025.05.04', - year: 2025, - imageUrl: 'https://placehold.co/253x187', - size: 'small', - }, - { - archiveId: 3, - title: '2025 새내기 배움터', - date: '2025.05.04', - year: 2025, - imageUrl: 'https://placehold.co/214x286', - size: 'medium', - }, - { - archiveId: 4, - title: '2025 동문패널톡', - date: '2025.05.04', - year: 2025, - imageUrl: 'https://placehold.co/448x281', - size: 'large', - }, - { - archiveId: 5, - title: '2025 해커톤', - date: '2025.05.04', - year: 2025, - imageUrl: 'https://placehold.co/470x257', - size: 'large', - }, - { - archiveId: 6, - title: '2025 MT', - date: '2025.05.04', - year: 2025, - imageUrl: 'https://placehold.co/253x187', - size: 'small', - }, - { - archiveId: 7, - title: '2025 종강총회', - date: '2025.05.04', - year: 2025, - imageUrl: 'https://placehold.co/214x286', - size: 'medium', - }, - { - archiveId: 8, - title: '2025 졸업전시', - date: '2025.05.04', - year: 2025, - imageUrl: 'https://placehold.co/448x281', - size: 'large', - }, - { - archiveId: 9, - title: '2024 체육대회', - date: '2024.05.04', - year: 2024, - imageUrl: 'https://placehold.co/470x257', - size: 'large', - }, - { - archiveId: 10, - title: '2024 새내기 배움터', - date: '2024.03.02', - year: 2024, - imageUrl: 'https://placehold.co/253x187', - size: 'small', - }, - { - archiveId: 11, - title: '2023 동문패널톡', - date: '2023.11.11', - year: 2023, - imageUrl: 'https://placehold.co/448x281', - size: 'medium', - }, -]; - -export default function Archiving() { - const router = useRouter(); - const [selectedYear, setSelectedYear] = useState(2025); - - const filteredArchives = useMemo( - () => ARCHIVES.filter((archive) => archive.year === selectedYear), - [selectedYear], - ); - - // 두 열로 나눠서 배치 (좌: 짝수 번째, 우: 홀수 번째) - const columns = useMemo( - () => [ - filteredArchives.filter((_, index) => index % 2 === 0), - filteredArchives.filter((_, index) => index % 2 === 1), - ], - [filteredArchives], - ); - - return ( -
- {/* 헤더 */} -
- -
- 아카이빙 -
- -
- -
- {/* 연도 필터 */} - - - {/* 아카이빙 목록 */} - {filteredArchives.length > 0 ? ( -
- {columns.map((column, columnIndex) => ( -
- {column.map((archive) => ( - - ))} -
- ))} -
- ) : ( -
- 아카이빙 기록이 없습니다. -
- )} -
-
- ); -} diff --git a/src/app/mobile/history/page.tsx b/src/app/mobile/history/page.tsx index 5cf6032..1d9ce7c 100644 --- a/src/app/mobile/history/page.tsx +++ b/src/app/mobile/history/page.tsx @@ -198,10 +198,10 @@ export default function UserRentalList() { {/* 반납이 필요한 물품 */}
-
+
반납이 필요한 물품
-
+
{returnItems.items.length > 0 ? ( returnItemsWithKeys.map((item) => ( {/* 대여 내역 */} -
+
대여 내역
); } diff --git a/src/app/mobile/main/_components/MainHeader/index.tsx b/src/app/mobile/main/_components/MainHeader/index.tsx index a569b91..6a5006f 100644 --- a/src/app/mobile/main/_components/MainHeader/index.tsx +++ b/src/app/mobile/main/_components/MainHeader/index.tsx @@ -41,7 +41,7 @@ export default function MainHeader() { return ( <> -
+
{user?.name}님{user?.isFeePaid ? : null}
diff --git a/src/app/mobile/main/page.tsx b/src/app/mobile/main/page.tsx index 8e77036..523d043 100644 --- a/src/app/mobile/main/page.tsx +++ b/src/app/mobile/main/page.tsx @@ -79,7 +79,7 @@ export default function MobileMain() { return (
-
+
diff --git a/src/app/mobile/notification/page.tsx b/src/app/mobile/notification/page.tsx index da3a1f5..a1a0e8f 100644 --- a/src/app/mobile/notification/page.tsx +++ b/src/app/mobile/notification/page.tsx @@ -57,7 +57,7 @@ export default function Notification() {
) : (
-
+