From 7b65e56a8b935210e6bba03bf659e41c181d96c3 Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 15 Oct 2026 16:09:57 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor:=20=EC=83=81=ED=83=9C=20=EC=9A=94?= =?UTF-8?q?=EC=95=BD=20=EC=B9=B4=EB=93=9C=EB=A5=BC=20=EA=B3=B5=EC=9A=A9=20?= =?UTF-8?q?StatusSummaryCard=EB=A1=9C=20=EB=A7=8C=EB=93=A4=EA=B3=A0=20?= =?UTF-8?q?=EC=82=AC=EB=AC=BC=ED=95=A8=20=EB=B0=B0=EC=A0=95=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EC=97=90=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/StatusSummaryCard.tsx | 65 +++++++++++++++++++ .../components/LockersAssignmentContent.tsx | 50 +++----------- 2 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 src/components/ui/StatusSummaryCard.tsx diff --git a/src/components/ui/StatusSummaryCard.tsx b/src/components/ui/StatusSummaryCard.tsx new file mode 100644 index 0000000..11fba5e --- /dev/null +++ b/src/components/ui/StatusSummaryCard.tsx @@ -0,0 +1,65 @@ +import { ContentBadge, Typography } from "@wanteddev/wds"; +import type { ReactNode } from "react"; + +export interface StatusSummaryCardRow { + label: string; + value: string; +} + +interface StatusSummaryCardProps { + /** 상태 배지 — 상태별 문구·색은 각 기능 constants의 배지 매핑에서 골라 넘긴다 */ + badge: { label: string; color: "green" | "orange" | "red" }; + title: ReactNode; + rows: StatusSummaryCardRow[]; +} + +// Figma: 신청내역 상세 Event Summary (nodeId 1133:46188), 학생회비 납부내역 (3147:147860), +// 사물함 배정 상태 (3147:148357) — 같은 모양의 Stream 로컬 카드라 하나로 모았다. +// 흰 카드 안에 상태 배지 → 제목 → 라벨/값 행. 행을 무엇으로 채울지는 쓰는 쪽이 정한다. +// 행 사이는 6px다. Figma 학생회비 카드만 8px로 그려져 있는데 디자인 실수로 보고 맞췄다(#120). +function StatusSummaryCard({ badge, title, rows }: StatusSummaryCardProps) { + return ( +
+ + {badge.label} + + + {title} + +
+ {rows.map((row) => ( +
+ + {row.label} + + + {row.value} + +
+ ))} +
+
+ ); +} + +export default StatusSummaryCard; diff --git a/src/features/lockers/components/LockersAssignmentContent.tsx b/src/features/lockers/components/LockersAssignmentContent.tsx index b798fe5..2134fa1 100644 --- a/src/features/lockers/components/LockersAssignmentContent.tsx +++ b/src/features/lockers/components/LockersAssignmentContent.tsx @@ -1,7 +1,8 @@ -import { Button, ContentBadge, Typography } from "@wanteddev/wds"; +import { Button, Typography } from "@wanteddev/wds"; import { IconChevronRight } from "@wanteddev/wds-icon"; import { use } from "react"; +import StatusSummaryCard from "@/components/ui/StatusSummaryCard"; import { fetchMyLockerAssignment } from "@/entities/lockers/lockersApi"; import LockersEmptyState from "@/features/lockers/components/LockersEmptyState"; import { LOCKER_STATUS_BADGES } from "@/features/lockers/constants/lockers"; @@ -15,7 +16,7 @@ interface LockersAssignmentContentProps { } // Figma: 사물함 배정 상태 배정완료 (nodeId 3147:148357), 빈 상태 (3147:148331) -// 배정 요약 카드와 배정된 사물함 카드 둘 다 Stream 로컬 카드다(학생회비 납부내역 카드와 같은 틀). +// 배정 요약은 공용 StatusSummaryCard, 배정된 사물함 카드는 사물함 로컬 카드다. function LockersAssignmentContent({ onViewLocation, }: LockersAssignmentContentProps) { @@ -44,46 +45,11 @@ function LockersAssignmentContent({ return (
-
- - {ASSIGNED_BADGE.label} - - - {assignment.semester} 사물함 - -
- {rows.map((row) => ( -
- - {row.label} - - - {row.value} - -
- ))} -
-
+
From 830dd33396cc6c725f0a60291ab7cd7943b7c8df Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 15 Oct 2026 16:13:33 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=20=ED=96=89=EC=82=AC=20=EC=8B=A0?= =?UTF-8?q?=EC=B2=AD=EB=82=B4=EC=97=AD=20=EC=9A=94=EC=95=BD=EC=9D=84=20Sta?= =?UTF-8?q?tusSummaryCard=EB=A1=9C=20=EB=B0=94=EA=BF=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/EventsApplicationSummary.tsx | 54 ++++--------------- 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/src/features/events/components/EventsApplicationSummary.tsx b/src/features/events/components/EventsApplicationSummary.tsx index 397ae02..dccfd56 100644 --- a/src/features/events/components/EventsApplicationSummary.tsx +++ b/src/features/events/components/EventsApplicationSummary.tsx @@ -1,17 +1,16 @@ -import { ContentBadge, Typography } from "@wanteddev/wds"; - +import StatusSummaryCard from "@/components/ui/StatusSummaryCard"; import type { MyEventApplication } from "@/entities/events/types"; import { EVENTS_APPLICATION_STATUS_BADGES } from "@/features/events/constants/events"; import { formatDateTime } from "@/lib/date"; -// Figma: 신청내역 상세 Event Summary (nodeId 1133:46188), 신청취소 상세 (1133:46223) — Stream 로컬 카드. -// 신청 폼·완료 화면의 EventsSummaryCard(아이콘 + 일시·장소)와 달리 "행사·신청·취소" 라벨 행이라 따로 둔다. +// Figma: 신청내역 상세 Event Summary (nodeId 1133:46188), 신청취소 상세 (1133:46223). +// 신청내역에서 "행사·신청·(취소)" 행을 만들어 공용 StatusSummaryCard에 넘긴다 — 취소 행은 취소된 신청에만 있다. +// 신청 폼·완료 화면의 EventsSummaryCard(아이콘 + 일시·장소)와는 다른 카드다. function EventsApplicationSummary({ application, }: { application: MyEventApplication; }) { - const badge = EVENTS_APPLICATION_STATUS_BADGES[application.status]; const rows = [ { label: "행사", @@ -29,46 +28,11 @@ function EventsApplicationSummary({ ]; return ( -
- - {badge.label} - - - {application.eventTitle} - -
- {rows.map((row) => ( -
- - {row.label} - - - {row.value} - -
- ))} -
-
+ ); } From e99321c2fd191a5cc29d77c74c6edd05f064027c Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 15 Oct 2026 16:15:12 +0900 Subject: [PATCH 3/7] =?UTF-8?q?refactor:=20=ED=95=99=EC=83=9D=ED=9A=8C?= =?UTF-8?q?=EB=B9=84=20=EB=82=A9=EB=B6=80=20=EC=9A=94=EC=95=BD=EC=9D=84=20?= =?UTF-8?q?StatusSummaryCard=EB=A1=9C=20=EB=B0=94=EA=BE=B8=EA=B3=A0=20?= =?UTF-8?q?=ED=96=89=20=EA=B0=84=EA=B2=A9=EC=9D=84=206px=EB=A1=9C=20?= =?UTF-8?q?=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fee/components/FeePaymentCard.tsx | 50 ++++--------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/src/features/fee/components/FeePaymentCard.tsx b/src/features/fee/components/FeePaymentCard.tsx index f595cd9..c0482d7 100644 --- a/src/features/fee/components/FeePaymentCard.tsx +++ b/src/features/fee/components/FeePaymentCard.tsx @@ -1,5 +1,6 @@ -import { Button, ContentBadge, Typography } from "@wanteddev/wds"; +import { Button, Typography } from "@wanteddev/wds"; +import StatusSummaryCard from "@/components/ui/StatusSummaryCard"; import type { FeePayment } from "@/entities/fee/types"; import { FEE_STATUS_BADGES } from "@/features/fee/constants/fee"; import { formatDateTime } from "@/lib/date"; @@ -15,9 +16,9 @@ function formatAmount(value: number | null) { } // Figma: 학생회비 납부내역 납부확인중 (nodeId 3147:147860), 확인필요 (3147:147879), 납부완료 (3147:147841) -// 납부 카드 아래에, 확인필요일 때만 학생회 확인 내용 카드가 붙는다. 둘 다 Stream 로컬 카드다. +// 납부 요약은 공용 StatusSummaryCard이고, 그 아래에 확인필요일 때만 학생회 확인 내용 카드(학생회비 로컬)가 붙는다. +// 행 간격은 Figma(8px)가 아니라 다른 요약 카드와 같은 6px다 — Figma 쪽 실수로 보고 맞췄다(#120). function FeePaymentCard({ payment, onContact }: FeePaymentCardProps) { - const badge = FEE_STATUS_BADGES[payment.status]; const rows = [ { label: "납부금액", value: formatAmount(payment.amount) }, { label: "납부일시", value: formatDateTime(payment.paidAt) }, @@ -29,44 +30,11 @@ function FeePaymentCard({ payment, onContact }: FeePaymentCardProps) { return (
-
- - {badge.label} - - - {payment.title} - - {rows.map((row) => ( -
- - {row.label} - - - {row.value} - -
- ))} -
+ {payment.status === "needs-check" && (
From 13aca08366932b637eeffaf5a38b6a40dcca85ba Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 15 Oct 2026 16:15:59 +0900 Subject: [PATCH 4/7] =?UTF-8?q?docs:=20=EC=83=81=ED=83=9C=20=EC=9A=94?= =?UTF-8?q?=EC=95=BD=20=EC=B9=B4=EB=93=9C=20=EA=B3=B5=EC=9A=A9=ED=99=94?= =?UTF-8?q?=EB=A5=BC=20=EB=AC=B8=EC=84=9C=EC=97=90=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conventions/wds-component-usage.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conventions/wds-component-usage.md b/docs/conventions/wds-component-usage.md index cd97a6b..0fba9d8 100644 --- a/docs/conventions/wds-component-usage.md +++ b/docs/conventions/wds-component-usage.md @@ -653,7 +653,7 @@ Figma는 헤더 배경이 없어서 배너 그림자(`Shadow/Spread/Small`, 60px | 빈 상태 버튼 `열린피드백 작성하기` / `열린피드백 보러 가기` | `Button color="assistive" size="small" variant="solid"` | 행사 목록 빈 상태(outlined)와 variant가 다르다 | | 뒤로가기 헤더 | `ScreenHeader variant="normal"` + `TopNavigationButton` | `useBackNavigation(fallbackPath)`(`hooks/`) — 바로 들어와 뒤로 갈 기록이 없으면 홈(상세는 목록, 위치 보기는 배정 상태)으로 보낸다. 대비 경로는 각 기능 `constants`의 경로 상수(`FEE_PAYMENTS_PATH`·`MY_FEEDBACKS_PATH`·`LOCKER_ASSIGNMENT_PATH` 등)를 쓰고, 데이터가 없을 때의 ``도 화면이 넘긴 `fallbackPath`로 간다 | -- **카드·빈 상태는 Stream 로컬**: 작성내역 카드(`FeedbacksHistoryCard`), 납부 카드(`FeePaymentCard`), 배정 카드는 흰 바탕 `rounded-xl p-4` 로컬 카드다. 빈 상태는 행사 목록 Empty State와 같은 이유(`FallbackView`의 일러스트 크기·패딩 고정)로 로컬이다. 열린피드백은 `FeedbacksEmptyState`(그림 `icons/feedbacks/empty-feedback.svg`)를 쓰고, 사물함은 `LockersEmptyState`(그림은 행사 목록과 같은 `icons/common/empty-events.svg`)를 쓴다. +- **카드·빈 상태는 Stream 로컬**: 작성내역 카드(`FeedbacksHistoryCard`)와 학생회비 확인 내용 카드, 배정된 사물함 카드는 흰 바탕 `rounded-xl p-4` 로컬 카드다. 학생회비 납부 요약과 사물함 배정 요약(배지 + 제목 + 라벨/값 행)은 행사 신청내역 상세 요약과 같은 공용 `StatusSummaryCard`(`components/ui/`)를 쓴다 — 행 내용은 각 기능(`FeePaymentCard`·`LockersAssignmentContent`)이 만들어 넘긴다. 행 간격은 6px로, Figma 학생회비 카드(`3147:147860`)만 8px로 그려진 건 디자인 실수로 보고 맞췄다(#120). 빈 상태는 행사 목록 Empty State와 같은 이유(`FallbackView`의 일러스트 크기·패딩 고정)로 로컬이다. 열린피드백은 `FeedbacksEmptyState`(그림 `icons/feedbacks/empty-feedback.svg`)를 쓰고, 사물함은 `LockersEmptyState`(그림은 행사 목록과 같은 `icons/common/empty-events.svg`)를 쓴다. - **답변 강조 표시는 두 상세 화면이 공유한다**: 답변 글의 `**굵게**`를 볼드 `Typography`로 바꾸는 `FeedbacksAnswerText`를 모아보기 상세와 작성내역 상세가 같이 쓴다. - **사물함 위치 보기(`/my/locker/location`)는 Figma에 없다**: 칸 선택 화면 배치를 보기 전용으로 쓴다. 칸 영역(미니맵·확대 스크롤)은 `LockersMapView`로 두 화면이 공유하고, 범례는 화면이 `legend`로 넘긴다(신청 ``, 위치 보기 `` — "내 사물함" 하나). 내 칸은 배정 정보(`lockerLabel`) 하나에서 정해서 `selectedLockerNumber`로 넘기고, 선택된 칸 모양(Primary/Normal 배경 + 흰 번호)으로 그린다. 보기 전용 여부는 `onSelect`가 없는지로만 판단하고, 이때 칸을 버튼으로 그리지 않는다. 처음 열 때 선택된 칸(`data-selected`)이 화면 밖이면 보일 만큼만 스크롤한다. 신청 화면의 내 칸(구역 목데이터 `isMine`, 초록 테두리, 선택 불가)은 보기 전용에서는 그리지 않는다. - **Figma와 다르게 둔 값**: 요일은 날짜로 계산해서 Figma의 요일 표기와 다를 수 있다. 사물함 번호는 칸 배치 목데이터가 있는 A-1 구역에 맞춰 A-7로 두었다(Figma는 B-25). 사물함 빈 상태 문구의 연도는 기기 시계의 올해다(API 연동 때 서버 값으로 — 코드에 TODO). 날짜는 `lib/date`의 `formatDate`·`formatDateTime`으로 맞추고, 작성내역 상세만 Figma(`3147:147756`)대로 `2026-04-25` 하이픈 표기다. @@ -669,7 +669,7 @@ Figma는 헤더 배경이 없어서 배너 그림자(`Shadow/Spread/Small`, 60px | 취소 완료 토스트 | `ScreenToast variant="positive"` | 체크 아이콘이 WDS 기본값 그대로 | | 상세 문항 `Control/Checkbox`·`Control/Radio`·`Textinput/Textarea` | 신청 폼의 `EventsQuestionField` 재사용 | `readOnly`로 읽기 전용(선택 표시는 그대로, 바꿀 수 없음). 입력 폼은 `onAnswerChange`가 필수라 빠뜨리면 타입 검사에서 걸린다. 신청취소 상세는 `disabled`로 WDS 비활성 모양을 쓰고, 선택지 글자는 `Label/Disable`(Figma `1133:46240`) | -- **카드·요약은 Stream 로컬**: 신청내역 카드(`EventsApplicationCard`, 70px 회색 썸네일 + 배지·제목·일시 + 버튼 2개)와 상세 요약(`EventsApplicationSummary`)은 로컬이다. 요약은 신청 폼·완료 화면의 `EventsSummaryCard`(아이콘 + 일시·장소)와 달리 "행사·신청·취소" 라벨 행이라 따로 뒀다. +- **카드·요약은 Stream 로컬**: 신청내역 카드(`EventsApplicationCard`, 70px 회색 썸네일 + 배지·제목·일시 + 버튼 2개)는 행사 로컬이다. 상세 요약은 공용 `StatusSummaryCard`이고, `EventsApplicationSummary`는 "행사·신청·(취소)" 행만 만들어 넘긴다. 신청 폼·완료 화면의 `EventsSummaryCard`(아이콘 + 일시·장소)와는 다른 카드다. - **빈 상태는 `EventsEmptyState` 재사용**: 버튼은 `action={{ label, onClick }}` 한 묶음으로 받아서 동작 없는 버튼이 생기지 않는다(신청내역 "행사 둘러보기" → `/events`, 행사 목록 모집중 "아카이빙 둘러보기" → `ARCHIVES_PATH`). 그림·버튼 모양은 행사 목록 빈 상태와 같고, 설명 굵기만 다르다(행사 목록 Medium, 신청내역 Regular) — `descriptionWeight`로 고른다. 위치는 목록 영역 가운데가 아니라 Figma대로 토글 아래 176px이다. - **탭은 경로로 나눈다**: 행사 `/events`, 신청내역 `/events/applications`, 상세 `/events/applications/:applicationId`. 같은 목록 화면을 라우터가 `tab` prop(`"event"`/`"application"`)으로 골라 넘기고(화면이 주소를 비교하지 않아 끝에 `/`가 붙어도 맞다), 탭을 바꿀 때는 replace라 히스토리가 쌓이지 않는다. 신청내역 탭은 Figma에 상태 필터 행이 없어서 숨긴다. 하단 탭은 신청내역 라우트 `handle`의 `bottomNavValue: "event"`로 "행사"가 선택된다. - **취소는 목록까지 반영된다**: 취소 API(`cancelMyEventApplication`)가 목데이터를 바꾸고 목록·상세 조회 캐시를 지운다(조회·무효화가 같은 `eventsKeys`로 key를 만든다). 요청·토스트 상태는 `useEventsApplicationCancel` 훅이 맡고, 토스트 문구·색은 `CANCEL_TOASTS` 한 곳에 있다. 다시 그리는 업데이트를 transition으로 묶어 새 데이터를 받는 동안 스켈레톤 대신 지금 화면을 유지하고, 토스트는 취소된 화면과 함께 뜬다. 실패 토스트 문구("신청 취소에 실패했어요. 다시 시도해 주세요.")는 Figma에 없어 임의로 정했다. From f829a0c12da8935977e48ed779ac10a7d307b1c7 Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 15 Oct 2026 16:28:33 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20=EC=9A=94=EC=95=BD=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=8A=A4=EC=BC=88=EB=A0=88=ED=86=A4=EC=9D=84=20Sta?= =?UTF-8?q?tusSummaryCardSkeleton=EC=9C=BC=EB=A1=9C=20=EB=AA=A8=EC=95=84?= =?UTF-8?q?=20=EC=B9=B4=EB=93=9C=20=EA=B0=84=EA=B2=A9=EA=B3=BC=20=EB=A7=9E?= =?UTF-8?q?=EC=B6=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/StatusSummaryCard.tsx | 51 ++++++++++++++++++- .../EventsApplicationDetailSkeleton.tsx | 29 +---------- .../fee/components/FeePaymentsSkeleton.tsx | 43 ++-------------- .../components/LockersAssignmentSkeleton.tsx | 29 +---------- 4 files changed, 59 insertions(+), 93 deletions(-) diff --git a/src/components/ui/StatusSummaryCard.tsx b/src/components/ui/StatusSummaryCard.tsx index 11fba5e..3a56952 100644 --- a/src/components/ui/StatusSummaryCard.tsx +++ b/src/components/ui/StatusSummaryCard.tsx @@ -1,6 +1,8 @@ -import { ContentBadge, Typography } from "@wanteddev/wds"; +import { ContentBadge, Skeleton, Typography } from "@wanteddev/wds"; import type { ReactNode } from "react"; +import { useSkeletonAnimation } from "@/components/ui/ScreenSkeleton"; + export interface StatusSummaryCardRow { label: string; value: string; @@ -62,4 +64,51 @@ function StatusSummaryCard({ badge, title, rows }: StatusSummaryCardProps) { ); } +interface StatusSummaryCardSkeletonProps { + /** 행마다 막대 폭 — 행 수만큼 넘긴다 */ + rowWidths: string[]; + badgeWidth?: string; + titleWidth?: string; +} + +// 데이터를 받는 동안 StatusSummaryCard 자리를 채운다 — 배지·제목·행 높이와 간격을 카드와 같게 둬서, +// 데이터가 들어와도 아래 내용이 밀리지 않는다. +export function StatusSummaryCardSkeleton({ + rowWidths, + badgeWidth = "64px", + titleWidth = "60%", +}: StatusSummaryCardSkeletonProps) { + const animation = useSkeletonAnimation(); + + return ( +
+ + +
+ {rowWidths.map((width, index) => ( + + ))} +
+
+ ); +} + export default StatusSummaryCard; diff --git a/src/features/events/components/EventsApplicationDetailSkeleton.tsx b/src/features/events/components/EventsApplicationDetailSkeleton.tsx index 42aae9c..8a9780b 100644 --- a/src/features/events/components/EventsApplicationDetailSkeleton.tsx +++ b/src/features/events/components/EventsApplicationDetailSkeleton.tsx @@ -1,6 +1,7 @@ import { Skeleton } from "@wanteddev/wds"; import { useSkeletonAnimation } from "@/components/ui/ScreenSkeleton"; +import { StatusSummaryCardSkeleton } from "@/components/ui/StatusSummaryCard"; const QUESTION_SKELETON_KEYS = ["question-1", "question-2", "question-3"]; @@ -10,33 +11,7 @@ function EventsApplicationDetailSkeleton() { return (
-
- - - - -
+ {QUESTION_SKELETON_KEYS.map((key) => (
-
- - - - - -
+
); } diff --git a/src/features/lockers/components/LockersAssignmentSkeleton.tsx b/src/features/lockers/components/LockersAssignmentSkeleton.tsx index 4a40d2d..e70436b 100644 --- a/src/features/lockers/components/LockersAssignmentSkeleton.tsx +++ b/src/features/lockers/components/LockersAssignmentSkeleton.tsx @@ -1,6 +1,7 @@ import { Skeleton } from "@wanteddev/wds"; import { useSkeletonAnimation } from "@/components/ui/ScreenSkeleton"; +import { StatusSummaryCardSkeleton } from "@/components/ui/StatusSummaryCard"; // 배정 상태를 받는 동안 보이는 스켈레톤 — 배정 요약 카드(배지 + 제목 + 2줄)와 사물함 카드 배치만 따른다. function LockersAssignmentSkeleton() { @@ -8,33 +9,7 @@ function LockersAssignmentSkeleton() { return (
-
- - - - -
+
Date: Thu, 15 Oct 2026 16:41:05 +0900 Subject: [PATCH 6/7] =?UTF-8?q?docs:=20=EC=9A=94=EC=95=BD=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=8A=A4=EC=BC=88=EB=A0=88=ED=86=A4=EC=9D=84=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conventions/wds-component-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conventions/wds-component-usage.md b/docs/conventions/wds-component-usage.md index 0fba9d8..537641f 100644 --- a/docs/conventions/wds-component-usage.md +++ b/docs/conventions/wds-component-usage.md @@ -653,7 +653,7 @@ Figma는 헤더 배경이 없어서 배너 그림자(`Shadow/Spread/Small`, 60px | 빈 상태 버튼 `열린피드백 작성하기` / `열린피드백 보러 가기` | `Button color="assistive" size="small" variant="solid"` | 행사 목록 빈 상태(outlined)와 variant가 다르다 | | 뒤로가기 헤더 | `ScreenHeader variant="normal"` + `TopNavigationButton` | `useBackNavigation(fallbackPath)`(`hooks/`) — 바로 들어와 뒤로 갈 기록이 없으면 홈(상세는 목록, 위치 보기는 배정 상태)으로 보낸다. 대비 경로는 각 기능 `constants`의 경로 상수(`FEE_PAYMENTS_PATH`·`MY_FEEDBACKS_PATH`·`LOCKER_ASSIGNMENT_PATH` 등)를 쓰고, 데이터가 없을 때의 ``도 화면이 넘긴 `fallbackPath`로 간다 | -- **카드·빈 상태는 Stream 로컬**: 작성내역 카드(`FeedbacksHistoryCard`)와 학생회비 확인 내용 카드, 배정된 사물함 카드는 흰 바탕 `rounded-xl p-4` 로컬 카드다. 학생회비 납부 요약과 사물함 배정 요약(배지 + 제목 + 라벨/값 행)은 행사 신청내역 상세 요약과 같은 공용 `StatusSummaryCard`(`components/ui/`)를 쓴다 — 행 내용은 각 기능(`FeePaymentCard`·`LockersAssignmentContent`)이 만들어 넘긴다. 행 간격은 6px로, Figma 학생회비 카드(`3147:147860`)만 8px로 그려진 건 디자인 실수로 보고 맞췄다(#120). 빈 상태는 행사 목록 Empty State와 같은 이유(`FallbackView`의 일러스트 크기·패딩 고정)로 로컬이다. 열린피드백은 `FeedbacksEmptyState`(그림 `icons/feedbacks/empty-feedback.svg`)를 쓰고, 사물함은 `LockersEmptyState`(그림은 행사 목록과 같은 `icons/common/empty-events.svg`)를 쓴다. +- **카드·빈 상태는 Stream 로컬**: 작성내역 카드(`FeedbacksHistoryCard`)와 학생회비 확인 내용 카드, 배정된 사물함 카드는 흰 바탕 `rounded-xl p-4` 로컬 카드다. 학생회비 납부 요약과 사물함 배정 요약(배지 + 제목 + 라벨/값 행)은 행사 신청내역 상세 요약과 같은 공용 `StatusSummaryCard`(`components/ui/`)를 쓴다 — 행 내용은 각 기능(`FeePaymentCard`·`LockersAssignmentContent`)이 만들어 넘긴다. 행 간격은 6px로, Figma 학생회비 카드(`3147:147860`)만 8px로 그려진 건 디자인 실수로 보고 맞췄다(#120). 로딩 중에는 같은 파일의 `StatusSummaryCardSkeleton`(행 수만큼 `rowWidths`)이 카드와 같은 높이·간격으로 자리를 채운다. 빈 상태는 행사 목록 Empty State와 같은 이유(`FallbackView`의 일러스트 크기·패딩 고정)로 로컬이다. 열린피드백은 `FeedbacksEmptyState`(그림 `icons/feedbacks/empty-feedback.svg`)를 쓰고, 사물함은 `LockersEmptyState`(그림은 행사 목록과 같은 `icons/common/empty-events.svg`)를 쓴다. - **답변 강조 표시는 두 상세 화면이 공유한다**: 답변 글의 `**굵게**`를 볼드 `Typography`로 바꾸는 `FeedbacksAnswerText`를 모아보기 상세와 작성내역 상세가 같이 쓴다. - **사물함 위치 보기(`/my/locker/location`)는 Figma에 없다**: 칸 선택 화면 배치를 보기 전용으로 쓴다. 칸 영역(미니맵·확대 스크롤)은 `LockersMapView`로 두 화면이 공유하고, 범례는 화면이 `legend`로 넘긴다(신청 ``, 위치 보기 `` — "내 사물함" 하나). 내 칸은 배정 정보(`lockerLabel`) 하나에서 정해서 `selectedLockerNumber`로 넘기고, 선택된 칸 모양(Primary/Normal 배경 + 흰 번호)으로 그린다. 보기 전용 여부는 `onSelect`가 없는지로만 판단하고, 이때 칸을 버튼으로 그리지 않는다. 처음 열 때 선택된 칸(`data-selected`)이 화면 밖이면 보일 만큼만 스크롤한다. 신청 화면의 내 칸(구역 목데이터 `isMine`, 초록 테두리, 선택 불가)은 보기 전용에서는 그리지 않는다. - **Figma와 다르게 둔 값**: 요일은 날짜로 계산해서 Figma의 요일 표기와 다를 수 있다. 사물함 번호는 칸 배치 목데이터가 있는 A-1 구역에 맞춰 A-7로 두었다(Figma는 B-25). 사물함 빈 상태 문구의 연도는 기기 시계의 올해다(API 연동 때 서버 값으로 — 코드에 TODO). 날짜는 `lib/date`의 `formatDate`·`formatDateTime`으로 맞추고, 작성내역 상세만 Figma(`3147:147756`)대로 `2026-04-25` 하이픈 표기다. From 0b4ba5393ed7acdb11ac5f6c78b5d7ff3f5f03f6 Mon Sep 17 00:00:00 2001 From: sangrae Date: Fri, 16 Oct 2026 01:50:42 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20=EB=82=B4=20=EB=82=B4=EC=97=AD?= =?UTF-8?q?=C2=B7=EC=8B=A0=EC=B2=AD=EB=82=B4=EC=97=AD=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=EC=9D=98=20=EC=B9=B4=EB=93=9C=20=EC=82=AC=EC=9D=B4=20=EA=B0=84?= =?UTF-8?q?=EA=B2=A9=EC=9D=84=208px=EB=A1=9C=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../events/components/EventsApplicationDetailContent.tsx | 2 +- .../events/components/EventsApplicationDetailSkeleton.tsx | 2 +- src/features/fee/components/FeePaymentList.tsx | 2 +- src/features/lockers/components/LockersAssignmentContent.tsx | 2 +- src/features/lockers/components/LockersAssignmentSkeleton.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/features/events/components/EventsApplicationDetailContent.tsx b/src/features/events/components/EventsApplicationDetailContent.tsx index 8c9af93..8dc7608 100644 --- a/src/features/events/components/EventsApplicationDetailContent.tsx +++ b/src/features/events/components/EventsApplicationDetailContent.tsx @@ -35,7 +35,7 @@ function EventsApplicationDetailContent({ return (
-
+
{application.questions.map((question) => ( +
{QUESTION_SKELETON_KEYS.map((key) => (
+
{payments.map((payment) => ( +
+