Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ca6bed6
feat: 행사 신청내역 entities 추가와 신청 문항 타입 이전
sangrae2325 Oct 10, 2026
664b80a
feat: 행사 목록 탭을 경로로 나누고 신청내역 보기 연결
sangrae2325 Oct 10, 2026
e992b8c
feat: 행사 신청내역 목록과 빈 상태 추가
sangrae2325 Oct 10, 2026
8855bb4
feat: 행사 신청내역 상세 추가
sangrae2325 Oct 10, 2026
0bc8a9e
feat: 행사 신청 취소 추가
sangrae2325 Oct 10, 2026
59f84c9
docs: 행사 신청내역 WDS 매핑 정리
sangrae2325 Oct 10, 2026
52cc139
fix: 행사 신청내역 접근성과 취소 일시 타입 정리
sangrae2325 Oct 10, 2026
b75b382
fix: 신청 문항 입력칸 글자를 Figma 크기로 맞춤
sangrae2325 Oct 10, 2026
ce95bb1
Merge remote-tracking branch 'origin/main' into feat/#115-events-appl…
sangrae2325 Oct 15, 2026
298fceb
refactor: 신청내역 날짜·뒤로가기를 공용 함수로 바꾸고 없는 신청내역 경로를 화면에서 넘김
sangrae2325 Oct 15, 2026
98187f9
refactor: 신청 취소 로직을 훅으로 빼고 토스트 문구를 상수로 묶음
sangrae2325 Oct 15, 2026
6de51d0
refactor: 행사 조회 캐시 key를 함수 하나로 모으고 데이터 변경 규칙을 문서에 추가
sangrae2325 Oct 15, 2026
8604167
refactor: 행사 목록 탭은 라우터가 넘기고 하단 탭 소속은 라우트 handle로 지정
sangrae2325 Oct 15, 2026
5a085d4
refactor: 행사 빈 상태 버튼을 문구·동작 한 묶음으로 받고 아카이빙 둘러보기 연결
sangrae2325 Oct 15, 2026
8b5daab
refactor: 신청 문항 읽기 전용을 readOnly prop으로 명시
sangrae2325 Oct 15, 2026
8cd965a
refactor: 빨간 버튼 스타일을 NEGATIVE_BUTTON_SX 상수로 모음
sangrae2325 Oct 15, 2026
87e0755
docs: 행사 신청내역 문서에 리뷰 반영 구조 갱신
sangrae2325 Oct 15, 2026
01cd50d
refactor: 목데이터 취소 시각 함수를 eventsMock으로 옮김
sangrae2325 Oct 15, 2026
c332556
Merge remote-tracking branch 'origin/feat/#111-my-history-screens' in…
sangrae2325 Oct 15, 2026
5ad6668
fix: 행사 목록 탭 전환 때 신청내역을 처음 열면 화면이 멈추던 문제 수정
sangrae2325 Oct 15, 2026
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
5 changes: 4 additions & 1 deletion docs/conventions/coding-style.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
}
```

새 옵션이 필요하면 `src/app/ScreenLayoutRoute.tsx`의 `ScreenRouteHandle`에 필드를 추가하고, 그 값을 `ScreenLayout` prop으로 넘긴다. 현재 필드는 `hasBottomNav`(하단 탭 표시)와 `background`(375×812 프레임 배경 — 헤더 뒤까지 포함이라 화면 본문에서 칠할 수 없다. 신청 완료처럼 Figma가 흰 배경으로 그린 화면만 `"normal"`)다.
새 옵션이 필요하면 `src/app/ScreenLayoutRoute.tsx`의 `ScreenRouteHandle`에 필드를 추가하고, 그 값을 `ScreenLayout` prop으로 넘긴다. 현재 필드는 `hasBottomNav`(하단 탭 표시)와 `background`(375×812 프레임 배경 — 헤더 뒤까지 포함이라 화면 본문에서 칠할 수 없다. 신청 완료처럼 Figma가 흰 배경으로 그린 화면만 `"normal"`), `bottomNavValue`(하단 탭에서 선택돼 보일 탭 — 행사 신청내역 `/events/applications`처럼 하단 탭 경로와 주소가 다른 탭 화면만 지정)다. 같은 화면을 탭마다 다른 경로로 쓸 때는 화면이 주소를 해석하지 않고 라우터가 `<EventsListScreen tab="application" />`처럼 prop으로 넘긴다.
- `ScreenLayout`은 **라우터를 모르는 prop 기반 컴포넌트**로 유지한다. 라우트 정보(`useMatches`)는 `ScreenLayoutRoute`만 읽는다.
- 헤더는 `useScreenHeader`로 `ScreenLayout`의 헤더 자리에 등록한다. 예외는 홈 하나다 — Figma 홈은 헤더 배경이 없어 배너 그림자가 헤더까지 번지는데, 헤더 자리에 두면 경계에서 그림자가 잘려 선이 생긴다. 그래서 홈만 스크롤 영역 안에 `sticky` 헤더를 직접 그린다(`wds-component-usage.md` 홈 섹션 참고).
- 화면 스택을 쌓는 이동(목록→상세, 상세→신청 등)은 `navigate(to, { viewTransition: true })`·`<Link viewTransition>`으로 슬라이드 전환을 켠다. 뒤로가기는 react-router가 그 이동을 기억해 반대 방향으로 자동 적용하므로 `navigate(-1)`은 그대로 둔다. 브라우저 앞으로가기도 POP이라, `ScreenLayoutRoute`는 히스토리 위치(`history.state.idx`)가 줄어든 POP만 뒤로 방향으로 본다. Bottom Nav·상단 탭처럼 형제 화면을 오가는 이동과 홈으로 돌아가는 이동은 켜지 않는다(즉시 전환). 애니메이션은 `index.css`, 방향은 `ScreenLayoutRoute`가 정한다.
Expand All @@ -49,6 +49,9 @@

- 서버 데이터를 받는 API 함수와 타입은 `entities/<도메인>/`에 둔다(`<도메인>Api.ts`·`types.ts`). 화면은 데이터 컴포넌트에서 `use(fetchEvents())`처럼 API 함수의 Promise를 React `use()`로 읽는다. 서버 상태 라이브러리(TanStack Query)는 실 API를 연동할 때 도입하고, 그때 `use(...)`를 `useSuspenseQuery`로 바꾼다.
- 실 API 전까지 API 함수는 `<도메인>Mock.ts`의 목데이터를 `mockupApi(key, () => data)`(`lib/mockupApi.ts`)로 돌려준다. 개발 서버에서는 스켈레톤을 확인할 수 있게 500ms 늦게 응답하고, 배포 빌드에서는 바로 응답한다. 같은 key의 Promise는 재사용되므로(렌더마다 새로 만들면 `use()`가 계속 서스펜드된다) key는 요청마다 겹치지 않게 `"events"`, `` `events/${id}` ``처럼 정한다. API가 붙으면 API 함수 안쪽만 바꾼다.
- 같은 도메인의 조회 key는 API 파일 안 key 함수 하나(`eventsKeys.application(id)` 등)로 만든다. 조회와 무효화가 문자열을 각자 이어 붙이면, 한쪽만 바뀌었을 때 무효화가 조용히 빗나간다.
- 데이터를 바꾸는 요청(신청 취소 등)은 `mockupMutation(() => ...)`으로 목데이터를 바꾸고, 응답 뒤 바뀐 조회 key를 `invalidateMockupApi([...])`로 지운다(API 함수 안에서 — 화면은 무효화를 모른다). 실 API에서는 TanStack Query의 `useMutation` + `invalidateQueries`가 이 자리를 맡는다.
- 무효화된 데이터를 다시 그리는 상태 업데이트는 `startTransition`으로 감싼다. 캐시가 지워진 조회는 새로 서스펜드되는데, transition 안이면 스켈레톤 대신 지금 화면을 유지한 채 새 데이터로 바뀐다(예: `useEventsApplicationCancel`).
- 화면(`<화면>Screen.tsx`)은 헤더 등록, UI 상태, 이동 같은 동작을 맡고, 데이터를 받는 영역만 `<Suspense fallback={<전용 스켈레톤 />}>`으로 감싼다. `use()`로 데이터를 읽고 그리는 부분은 `features/<기능>/components/`의 컴포넌트(`EventsList`, `EventsDetailContent` 등)로 분리하고, 이동 같은 동작은 콜백 prop으로 받는다.
- 데이터와 무관한 헤더·탭·필터는 Suspense 밖에서 바로 그리고, 스켈레톤은 데이터 영역의 배치만 따라 그린다. 전용 스켈레톤은 `features/<기능>/components/<화면>Skeleton.tsx`에 두고 WDS `Skeleton`으로 그린다. 헤더가 데이터에 따라 달라지는 화면(공지 상세)은 헤더도 데이터 컴포넌트가 등록하고, 스켈레톤이 `useScreenHeaderSkeleton`으로 헤더 자리를 채운다.

Expand Down
17 changes: 17 additions & 0 deletions docs/conventions/wds-component-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ hex를 하드코딩하지 않고 `index.css`의 색상 토큰을 그대로 참
- `width` 기본값이 부모 폭을 채우지 않는다 — 안 주면 카드 폭의 절반 정도로 렌더링돼서 `width="100%"`를 줬다.
- 높이 계산용 숨김 textarea(`readonly`, `aria-hidden`)를 하나 더 렌더링한다 — 테스트·자동화에서 `textarea` 셀렉터를 쓸 때 제외해야 한다.
- 단답형(50자)도 같은 `TextArea`를 쓴다(Figma 텍스트 입력 예시 `1133:43105`의 디자이너 메모).
- 글자 스타일이 `body1-reading`(16px)으로 고정돼 있고 prop으로 못 바꾼다. Figma 입력 글자·안내 문구는 `Label 1/Reading`(14px)이라(`1658:183424`), `sx`에 `& textarea, & textarea::placeholder { typographyStyle("label1-reading", "regular") }`를 줘서 덮는다(`EventsQuestionField`의 `TEXT_AREA_TYPOGRAPHY`). 위 숨김 textarea도 같은 글자로 높이를 재야 자동 높이가 맞아서 `textarea` 전체를 잡는다. 처음엔 16px 그대로였다가 행사 신청내역(#115) `/figma-check`에서 잡혔다. 신청 폼(`1658:183424`)과 신청내역 상세 둘 다 Figma가 14px다. **WDS를 올릴 때 확인할 곳**: WDS 내부 클래스가 아니라 `textarea` 태그를 잡는 거라 WDS가 textarea를 계속 쓰는 한 유지되지만, 업데이트 뒤 신청 폼 입력 글자가 14px인지·자동 높이가 맞는지 한 번 본다.
- **`Action Area/Action Area` → `ActionArea background` + `ActionAreaButton`**: `background`를 켜면 `::before`가 영역 위로 `margin-y`(20px)만큼 더 올라가 그라데이션 마스크로 스크롤 내용을 흐리게 덮는다(Figma `Gradient/Solid`와 일치). `divider`는 기본값이 `true`지만 `extra` 모드에서만 선을 그려서 일반 모드에는 영향 없다. Figma Action Area(110px = 위 20 + 버튼 56 + 아래 34)는 버튼 아래가 iOS **Bottom Safe Area까지 합쳐 34px**인데 WDS `ActionArea`는 아래 padding 20px만 줘서, 모자란 **14px**을 `bg-background-elevated-normal` div로 따로 붙였다(`BottomSheet`에서 14px을 더한 것과 같은 이유). 처음엔 Safe Area 34px을 통째로 더해서 버튼 아래가 54px로 벌어졌었다 — ActionArea 자체 padding과 겹치는지 먼저 확인한다. 이때 `--color-background-elevated-normal`(`--semantic-background-elevated-normal` 별칭) 토큰을 추가했다.
- **Action Area 메인 버튼 높이**: `ActionAreaButton`(`main`)은 항상 `Button size="large"`(padding `12px 28px` → **48px**)로 그리는데, Figma `┗ Main Action`은 padding `16px 28px`(**56px**)이다. WDS에 56px 크기가 없어서 `sx={{ paddingBlock: "16px" }}`로 세로 padding만 맞췄다(`ActionAreaButton`은 `props.sx`를 내부 `Button` 스타일 맨 뒤에 붙여서 덮어쓰기가 된다). 빌릴게 대여 바텀시트 Figma(`1422:57205`)의 "대여 신청하기" 버튼도 같은 56px 스펙이지만, `BililgeRentalSheet.tsx`는 아직 `sx` 없이 48px로 렌더링된다(위 "빌릴게 대여 바텀시트" 절의 "정확히 일치" 기록은 높이까지는 대조하지 않은 것으로 보인다).
- **기타(직접 입력) 입력칸은 WDS가 아니라 plain `<input>`**: Figma `Other Option`(`1658:183954`)은 체크박스 아래에 밑줄만 있는 입력칸이라, WDS `TextField`(배경·테두리·12px radius가 있는 박스형)와 생김새가 다르다. 밑줄은 `Primary/Normal` 0.7px(에셋 SVG의 stroke로 확인, `get_variable_defs`만으로는 선 색이 안 나온다). 글자는 `Typography as="input"`으로 Figma `Label 1/Reading - Regular`(`variant="label1-reading"`, 14px·줄 높이 22px)를 받는다(`component-convention.md` 타이포그래피 참고).
Expand Down Expand Up @@ -637,6 +638,22 @@ Figma는 헤더 배경이 없어서 배너 그림자(`Shadow/Spread/Small`, 60px
- **사물함 위치 보기(`/my/locker/location`)는 Figma에 없다**: 칸 선택 화면 배치를 보기 전용으로 쓴다. 칸 영역(미니맵·확대 스크롤)은 `LockersMapView`로 두 화면이 공유하고, 범례는 화면이 `legend`로 넘긴다(신청 `<LockersLegend />`, 위치 보기 `<LockersLegend variant="mine" />` — "내 사물함" 하나). 내 칸은 배정 정보(`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` 하이픈 표기다.

## 행사 신청내역(`1133:46168` 목록 / `1165:63551` empty / `1133:46181` 상세 / `1133:46131` 신청취소 확인모달 / `1133:46216` 신청취소 상세 + 토스트) 구현 중 확정된 매핑

| Figma | 코드 | 확인 내용 |
|---|---|---|
| `Content Badge` (신청완료·신청취소) | `ContentBadge size="small" variant="solid" color="accent"` | 신청완료 green, 신청취소 red. 목록 카드와 상세가 `EVENTS_APPLICATION_STATUS_BADGES`를 같이 쓴다 |
| 카드 `행사 상세` / `신청 상세` | `Button size="small" color="assistive"` | 앞은 `variant="outlined"`, 뒤는 `variant="solid"`(Fill/Normal 배경). 둘 다 padding 7/14·radius 8·Label 2/Medium이 Figma와 같다 |
| 상세 `신청 취소` | `Button size="medium" color="primary" variant="outlined"` + `sx` | WDS Button 색이 primary/assistive뿐이라 글자·테두리(`box-shadow` inset)만 `Status/Negative`로 덮는다 — `sx={NEGATIVE_BUTTON_SX.outlined}`(`components/ui/negativeButtonSx.ts`, `ConfirmModal`의 빨간 확인 버튼은 `.solid`). outlined primary가 SemiBold 글자라 primary를 고른다 |
| 신청취소 확인모달 | `ConfirmModal tone="negative"` | 사물함 신청 확인 모달과 같은 공용 모달이고, `tone="negative"`가 느낌표 아이콘 + 빨간 확인 버튼을 그린다 |
| 취소 완료 토스트 | `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`(아이콘 + 일시·장소)와 달리 "행사·신청·취소" 라벨 행이라 따로 뒀다.
- **빈 상태는 `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에 없어 임의로 정했다.

## 알림(`3595:107100` 목록 / `3595:107112` empty / `3628:110837` 설정) 구현 중 확정된 매핑

코드는 `src/features/notifications/` 참고.
Expand Down
5 changes: 5 additions & 0 deletions src/app/ScreenLayoutRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useLayoutEffect, useRef } from "react";
import { useLocation, useMatches, useNavigationType } from "react-router-dom";

import type { BottomNavValue } from "@/components/ui/BottomNav";
import ScreenLayout, {
type ScreenBackground,
} from "@/components/ui/ScreenLayout";
Expand All @@ -12,6 +13,9 @@ export interface ScreenRouteHandle {
// 화면 프레임 자체의 배경 — 헤더 뒤까지 포함이라 화면 본문에서 칠할 수 없다.
// 기본은 회색(alternative)이고, 완료 화면처럼 Figma가 흰 배경으로 그린 화면만 normal을 지정한다.
background?: ScreenBackground;
// 하단 탭에서 선택돼 보일 탭. 하단 탭 경로와 주소가 다른 탭 화면(행사 신청내역 등)만 지정하고,
// 지정하지 않으면 ScreenLayout이 주소로 정한다.
bottomNavValue?: BottomNavValue;
}

// useMatches()는 handle을 unknown으로 준다. ScreenRouteHandle은 필드가 전부 선택이라 객체면 이 타입으로 본다.
Expand Down Expand Up @@ -83,6 +87,7 @@ function ScreenLayoutRoute() {
background={
resolveScreenRouteOption(handles, "background") ?? "alternative"
}
bottomNavValue={resolveScreenRouteOption(handles, "bottomNavValue")}
hasBottomNav={resolveScreenRouteOption(handles, "hasBottomNav") ?? true}
/>
);
Expand Down
18 changes: 17 additions & 1 deletion src/app/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import BililgeListScreen from "@/features/bililge/BililgeListScreen";
import ChatEntryScreen from "@/features/chat/ChatEntryScreen";
import EventsApplicationClosedScreen from "@/features/events/EventsApplicationClosedScreen";
import EventsApplicationCompleteScreen from "@/features/events/EventsApplicationCompleteScreen";
import EventsApplicationDetailScreen from "@/features/events/EventsApplicationDetailScreen";
import EventsApplicationScreen from "@/features/events/EventsApplicationScreen";
import EventsDetailScreen from "@/features/events/EventsDetailScreen";
import EventsListScreen from "@/features/events/EventsListScreen";
Expand Down Expand Up @@ -53,11 +54,26 @@ const routes = [
path: "/bililge",
},
{
element: <EventsListScreen />,
element: <EventsListScreen tab="event" />,
// 카드 없이 구분선으로만 나뉘는 목록이라 화면 전체가 흰 면이다
handle: { background: "normal" } satisfies ScreenRouteHandle,
path: "/events",
},
{
element: <EventsListScreen tab="application" />,
// 행사 목록의 신청내역 탭 — 같은 화면을 탭만 바꿔 그리고, 하단 탭은 "행사"가 선택된다
handle: {
background: "normal",
bottomNavValue: "event",
} satisfies ScreenRouteHandle,
path: "/events/applications",
},
{
element: <EventsApplicationDetailScreen />,
// 하단 탭 없이 회색 배경(기본값) — 흰 카드가 뜬다
handle: { hasBottomNav: false } satisfies ScreenRouteHandle,
path: "/events/applications/:applicationId",
},
{
element: <NoticesListScreen />,
// 카드 없이 구분선으로만 나뉘는 목록이라 화면 전체가 흰 면이다
Expand Down
6 changes: 2 additions & 4 deletions src/components/ui/ConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { KeyboardEvent } from "react";
import { useEffect, useId, useRef } from "react";
import { createPortal } from "react-dom";

import { NEGATIVE_BUTTON_SX } from "@/components/ui/negativeButtonSx";
import { useScreenSheetPortal } from "@/components/ui/useScreenSheetPortal";

// 모달 안에서 Tab이 돌 수 있는 요소들 — 포커스를 가둘 때 첫/마지막을 찾는 데 쓴다
Expand Down Expand Up @@ -192,11 +193,8 @@ function ConfirmModal({
fullWidth
onClick={onConfirm}
size="medium"
// WDS Button 색상은 primary/assistive뿐이라 위험 버튼은 배경색만 토큰으로 덮어쓴다
sx={{
backgroundColor: isNegative
? "var(--color-status-negative)"
: undefined,
...(isNegative && NEGATIVE_BUTTON_SX.solid),
paddingBlock: "12px",
}}
variant="solid"
Expand Down
6 changes: 5 additions & 1 deletion src/components/ui/ScreenLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const BACKGROUND_CLASS_NAMES: Record<ScreenBackground, string> = {
interface ScreenLayoutProps {
hasBottomNav?: boolean;
background?: ScreenBackground;
/** 선택돼 보일 하단 탭. 없으면 주소로 정한다(라우트 handle의 bottomNavValue) */
bottomNavValue?: BottomNavValue;
}

// 모든 화면이 공유하는 라우트 레이아웃 — router.tsx에서 부모 route로 두고 화면들을
Expand Down Expand Up @@ -78,6 +80,7 @@ interface ScreenLayoutProps {
function ScreenLayout({
hasBottomNav = true,
background = "alternative",
bottomNavValue: bottomNavValueProp,
}: ScreenLayoutProps) {
const [header, setHeader] = useState<ReactNode>(null);
const [sheetPortalEl, setSheetPortalEl] = useState<HTMLDivElement | null>(
Expand All @@ -87,7 +90,8 @@ function ScreenLayout({
useState<HTMLDivElement | null>(null);
const location = useLocation();
const navigate = useNavigate();
const bottomNavValue = getBottomNavValueFromPath(location.pathname);
const bottomNavValue =
bottomNavValueProp ?? getBottomNavValueFromPath(location.pathname);

useNativeSafeAreaColors(background, hasBottomNav);

Expand Down
Loading