# 선물함 리스트 페이지 생성 프롬프트 이 문서는 Android/iOS 앱의 `선물함` 리스트 페이지를 생성할 때 사용하는 프롬프트다. 참고 Figma: - 팬 모드, 신청한 내역이 있을 때: `2481:19382` - 팬 모드, 신청한 내역이 없을 때: `2520:35587` - 크리에이터 모드, 받은 선물 내역이 없을 때: `2531:36283` - 크리에이터 모드, 받은 선물 내역이 있을 때: `2531:36194` - 크리에이터 모드, 받은 선물 상태별 카드 표시: `2531:36237` 전제: - Android/iOS 각각의 기존 디자인 시스템, 컴포넌트, API client, 상태 관리, toast/dialog, navigation 패턴을 재사용한다. - Figma의 visual structure를 기준으로 구현하되, 아래 사용자 요구사항을 Figma보다 우선한다. - 상단 뒤로가기 내비게이션 영역은 고정한다. - 상단 뒤로가기 내비게이션 영역을 제외한 전체 콘텐츠 영역은 스크롤되어야 한다. - `신청 내역`, `선물 내역` 섹션 타이틀은 표시하지 않는다. - 리스트는 신청일/취소일 최신순으로 보여야 한다. - request/response 설명은 모바일 공통 JSON 기준이다. --- ## 모바일 앱 구현 프롬프트 ```text Android/iOS 앱의 선물함 리스트 페이지를 Figma 기준으로 생성하고 API 연동을 구현해줘. Figma는 두 관점의 상태를 보여준다. - 보낸 선물 관점: 사용자가 본인이 신청한 선물 내역을 확인하는 상태다. Figma `2481:19382`, `2520:35587`를 기준으로 한다. - 받은 선물 관점: 사용자가 본인이 받을 선물 내역을 확인하는 상태다. Figma `2531:36283`, `2531:36194`, `2531:36237`를 기준으로 한다. - 실제 선물함 API는 두 관점을 나누어 호출하지 않고 `type=ALL`로 한 번 호출한다. - 응답 item의 `direction` 값이 `SENT`이면 보낸 선물 카드로, `RECEIVED`이면 받은 선물 카드로 렌더링한다. - 각 카드에는 상대방 프로필 이미지와 닉네임을 표시한다. - `direction=SENT`: 상대방은 선물을 받는 크리에이터다. - `direction=RECEIVED`: 상대방은 선물을 보낸 팬이다. 중요 요구사항: - 상단 뒤로가기 내비게이션은 고정한다. - 상단 내비게이션 아래의 전체 콘텐츠만 스크롤되게 한다. - Figma에 보이는 `신청 내역`, `선물 내역` 섹션 타이틀은 실제 구현에서 표시하지 않는다. - 선물함 리스트는 신청일/취소일 최신순으로 정렬한다. - 현재 API 응답만으로 취소일 기준 정렬/표시는 완전하지 않으므로, API가 취소일을 내려주지 않으면 서버 응답 순서를 우선 사용하고 취소 건 날짜 라벨은 `createdAt` 기준으로 표시한다. 취소일 표시가 필수이면 API 보강이 필요하다. API 호출: - 선물함 리스트는 항상 `GET /api/v2/gifts?type=ALL&page=0&size=20`로 조회한다. - `SENT`, `RECEIVED`로 따로 호출하지 않는다. - `items[].direction`으로 보낸 선물/받은 선물 UI를 결정한다. - 페이지 진입 시 첫 페이지를 조회한다. - `hasNext=true`이면 스크롤 하단에서 다음 page를 추가 조회한다. - pull-to-refresh가 기존 앱에 있으면 page를 0으로 초기화하고 다시 조회한다. 공통 레이아웃: 1. 상단 고정 내비게이션 - 타이틀: `선물함` - 뒤로가기 버튼은 기존 앱 패턴을 사용한다. - 이 영역은 스크롤되지 않는다. 2. 스크롤 콘텐츠 - nav 아래부터 시작한다. - 안내 배너, 빈 상태, 리스트, 하단 여백 또는 하단 문의 버튼까지 스크롤 영역에 포함한다. - iOS safe area와 Android navigation bar 여백은 기존 앱 패턴을 따른다. 보낸 선물 UI: - `direction=SENT`인 item에 적용한다. - 사용자가 신청한 선물 내역을 보여준다. - 보낸 선물만 있는 상태는 Figma `2481:19382`를 따른다. - 상단 안내 배너를 표시한다. - 제목: `사서함을 통해 안전하게 전달됩니다` - 본문: `크리에이터 및 팬의 주소는 공개되지 않습니다. 선물은 소다라이브 사서함에 도착한 뒤 크리에이터에게 전달됩니다.` - `신청 내역` 섹션 타이틀은 표시하지 않는다. - 카드 구성: - 상단 왼쪽: `statusName` - 상단 오른쪽: 날짜 라벨 - 기본: `{createdAt} 신청` - 상태가 `CANCELED`이고 취소일 필드가 있으면 `{canceledAt} 취소` - 현재 리스트 API에는 `canceledAt`이 없으므로 기존 API만 사용할 때는 `{createdAt} 취소` 또는 `{createdAt} 신청` 중 제품 정책에 맞춰 하나로 통일한다. - 프로필 row 내부: `counterpartProfileImageUrl`, `counterpartNickname`을 사용해 받는 크리에이터 프로필을 표시한다. - 프로필 row 아래 보조 문구: `sizeName · categoryName` - 프로필 이미지가 없으면 기존 앱의 기본 프로필 이미지를 표시한다. - 우측 chevron - 탭 시 선물 상세 페이지로 이동하며 `applicationNo`를 전달한다. - 리스트가 비어 있고 보낸 선물 관점으로 진입한 화면이면 Figma `2520:35587`를 따른다. - 상단 안내 배너만 표시한다. - 별도 empty title/body를 추가하지 않는다. 받은 선물 UI: - `direction=RECEIVED`인 item에 적용한다. - 사용자가 받을 선물 내역을 보여준다. - 리스트가 비어 있고 받은 선물 관점으로 진입한 화면이면 Figma `2531:36283`를 따른다. - 가운데 empty title: `전달 예정인 선물이 없어요` - empty body: `베타 기간에는 팬이 선물을 보내는 기능만 제공돼요. 더 다양해진 선물 기능으로 곧 다시 만나요!` - 버튼: `의견 남기기` - 의견 남기기 동작은 기존 앱의 문의/피드백 이동 패턴을 사용한다. - 받은 선물이 있는 상태는 Figma `2531:36194`, `2531:36237`를 따른다. - 상단 안내 배너를 표시한다. - 제목: `배송지 입력 기간 안내` - 본문: `알림을 받은 날부터 7일 이내에 배송지를 입력해 주세요. 기한 내 입력하지 않으면 선물이 반송됩니다.` - `선물 내역` 섹션 타이틀은 표시하지 않는다. - 배송지 입력이 필요한 선물이 있으면 파란 안내 배너를 리스트 상단에 표시한다. - 제목: `팬이 보낸 선물이 있어요!` - 본문: `선물이 늦지 않게 전달될 수 있도록 배송지를 입력해 주세요.` - 보조 문구: `*n일 이내로 입력하지 않으면 선물이 사라져요.` - 현재 리스트 API에는 배송지 입력 마감일이 없으므로 정확한 n일 계산이 필요하면 API 보강이 필요하다. - 배너 탭 시 배송지 입력이 필요한 첫 번째 선물 상세로 이동한다. - 카드 구성: - 상단 왼쪽 프로필 row 내부: `counterpartProfileImageUrl`, `counterpartNickname`을 사용해 보낸 팬 프로필을 표시한다. - 상단 오른쪽: `{createdAt} 신청` - 본문 메인: 상태 표시 문구 - 본문 서브: 상태 보조 문구가 필요한 경우만 표시 - 우측 chevron - 탭 시 선물 상세 페이지로 이동하며 `applicationNo`를 전달한다. - 리스트 하단에는 Figma처럼 `문의하기` 하단 버튼을 둘 수 있다. 기존 앱 정책상 고정 버튼이면 하단 safe area를 포함하고, 스크롤 콘텐츠 내부 버튼이면 콘텐츠 하단에 둔다. 상태 표시 매핑: 보낸 선물 카드: | API status | 표시 문구 | |---|---| | `RECEIVED` | `운송장 등록 필요` | | `TRACKING_REGISTERED` | `발송 확인` | | `ARRIVED_AT_MAILBOX` | `사서함 도착` | | `INSPECTION_COMPLETED` | `선물 검수 완료` | | `DELIVERED` | `전달 완료` | | `UNDELIVERABLE` | `전달 불가` | | `CANCELED` | `신청 취소` | 받은 선물 카드: | API status | 메인 문구 | 서브 문구 | |---|---|---| | `TRACKING_REGISTERED` | `배송지 입력 필요` | `전달 예정` | | `ARRIVED_AT_MAILBOX` | `선물 검수` | `선물 확인 중` | | `INSPECTION_COMPLETED` | `선물 검수 완료` | `배송 중` | | `DELIVERED` | `전달 완료` | 없음 | | `UNDELIVERABLE` | `전달 불가` | 없음 | API 명세: 선물함 리스트 조회 API: - Method: `GET` - URL: `/api/v2/gifts` - 인증: 로그인 필요 - Query: - `type`: `ALL`, `SENT`, `RECEIVED` - `page`: 0부터 시작 - `size`: 페이지 크기. 기본 20 - 이 페이지에서는 `type=ALL`만 사용한다. - Response envelope 예시: ```json { "success": true, "data": { "totalCount": 1, "items": [], "page": 0, "size": 20, "hasNext": false }, "message": "" } ``` Response `data` 예시: ```json { "totalCount": 2, "items": [ { "applicationNo": "A-1002609300001", "direction": "SENT", "status": "RECEIVED", "statusName": "접수 완료", "priceCan": 80, "categoryName": "아크릴/스탠드", "sizeName": "소형", "counterpartMemberId": 200, "counterpartNickname": "달빛수집가", "counterpartProfileImageUrl": "https://example.com/profile.png", "createdAt": "2026-09-18T03:00:00Z" } ], "page": 0, "size": 20, "hasNext": false } ``` Response `data` 필드: | 필드 | 타입 | 설명 | |---|---|---| | `totalCount` | number | 전체 개수 | | `items` | array | 선물함 리스트 | | `items[].applicationNo` | string | 선물 신청번호. 상세 이동 ID | | `items[].direction` | string | `SENT` 또는 `RECEIVED` | | `items[].status` | string | 선물 상태 코드 | | `items[].statusName` | string | 서버 상태 표시명 | | `items[].priceCan` | number | 사용된 캔 | | `items[].categoryName` | string | 카테고리명 | | `items[].sizeName` | string | 사이즈명 | | `items[].counterpartMemberId` | number | 상대방 회원 ID. `SENT`에서는 받는 크리에이터, `RECEIVED`에서는 보낸 팬 | | `items[].counterpartNickname` | string | 상대방 닉네임 | | `items[].counterpartProfileImageUrl` | string 또는 null | 상대방 프로필 이미지 URL. 없으면 기본 프로필 이미지 표시 | | `items[].createdAt` | string 또는 null | 신청일. UTC ISO 문자열 | | `page` | number | 현재 페이지 | | `size` | number | 페이지 크기 | | `hasNext` | boolean | 다음 페이지 존재 여부 | 정렬: - 현재 서버 API는 `createdAt desc, id desc`로 정렬한다. - 요구사항은 신청일/취소일 최신순이다. - 취소일 최신순까지 정확히 맞추려면 리스트 API가 `canceledAt` 또는 `displayedAt` 같은 정렬 기준 시각을 내려주고 그 기준으로 정렬해야 한다. - API 보강 전에는 서버 응답 순서를 그대로 사용하고, 클라이언트에서 임의 재정렬하지 않는다. 상대방 프로필 표시 규칙: - `counterpartNickname`은 카드의 프로필 row 이름으로 표시한다. - `counterpartProfileImageUrl`이 있으면 해당 이미지를 원형 프로필 이미지로 표시한다. - `counterpartProfileImageUrl`이 `null`이거나 빈 값이면 기존 앱의 기본 프로필 이미지를 표시한다. - `direction=SENT`에서는 받는 크리에이터 정보로 해석한다. - `direction=RECEIVED`에서는 보낸 팬 정보로 해석한다. 현재 API만으로 부족한 Figma 표시값: - 취소일 `canceledAt` - 배송지 입력 마감일 또는 남은 일수 추가 API 보강이 가능하면 리스트 item에 아래 필드를 추가해달라고 요청한다. ```json { "canceledAt": "2026-09-18T03:00:00Z", "recipientAddressDeadlineAt": "2026-09-25T03:00:00Z", "sortAt": "2026-09-18T03:00:00Z" } ``` - `canceledAt`: 취소 상태의 취소일 표시용 - `recipientAddressDeadlineAt`: 크리에이터 배송지 입력 안내 배너의 남은 일수 계산용 - `sortAt`: 신청/취소 최신순 정렬 기준. 취소 건은 취소일, 그 외에는 신청일 로딩/에러/빈 상태: - 최초 로딩 중에는 기존 앱 리스트 스켈레톤 또는 loading 패턴을 사용한다. - 실패 시 기존 앱 toast/dialog와 재시도 버튼을 사용한다. - 빈 상태는 진입 관점에 따라 다르게 표시한다. - 보낸 선물 관점으로 진입한 화면이면 안내 배너만 남긴다. - 받은 선물 관점으로 진입한 화면이면 중앙 empty UI와 `의견 남기기` 버튼을 표시한다. 테스트/검증: - 선물함 진입 시 `type=ALL`로 API를 한 번 호출하는지 확인한다. - `direction=SENT` item은 보낸 선물 카드 UI로 표시되는지 확인한다. - `direction=RECEIVED` item은 받은 선물 카드 UI로 표시되는지 확인한다. - 각 item의 `counterpartNickname`, `counterpartProfileImageUrl`이 프로필 row에 표시되는지 확인한다. - `counterpartProfileImageUrl=null`이면 기본 프로필 이미지가 표시되는지 확인한다. - 상단 내비게이션은 고정되고 아래 콘텐츠만 스크롤되는지 확인한다. - `신청 내역`, `선물 내역` 텍스트가 실제 화면에 노출되지 않는지 확인한다. - 리스트 item 탭 시 `applicationNo`로 상세 화면 이동이 되는지 확인한다. - 빈 상태가 진입 관점에 맞는 Figma 기준으로 표시되는지 확인한다. - `hasNext=true`일 때 다음 page를 추가 조회하는지 확인한다. - API 실패 시 입력/스크롤 상태를 깨지 않고 오류와 재시도를 제공하는지 확인한다. ``` --- ## API 요약 | 목적 | Method | URL | Query | Response data | |---|---|---|---|---| | 선물함 리스트 조회 | GET | `/api/v2/gifts` | `type=ALL`, `page`, `size` | 선물 리스트, 페이지 정보 | ## Figma 반영 메모 - 보낸 선물 리스트 있음: 안내 배너 + 카드 리스트. 단, 실제 구현에서는 `신청 내역` 타이틀을 제거한다. - 보낸 선물 관점 empty: 안내 배너만 표시한다. - 받은 선물 관점 empty: 중앙 empty UI와 `의견 남기기` 버튼을 표시한다. - 받은 선물 리스트 있음: 안내 배너 + 배송지 입력 CTA 배너 + 카드 리스트. 단, 실제 구현에서는 `선물 내역` 타이틀을 제거한다. - 받은 선물 상태별 카드는 `배송지 입력 완료/전달 예정`, `전달 완료`, `전달 불가`, `선물 검수/선물 확인 중`, `선물 검수 완료/배송 중` 패턴을 사용한다.