@@ -3,13 +3,16 @@ import Image from 'next/image';
33import Link from 'next/link' ;
44import { useEffect , useMemo , useState } from 'react' ;
55
6+ import { Container } from '@/components/layout' ; // ✅ my-shop과 동일 패턴
67import Frame from '@/components/layout/frame/frame' ;
78import Button from '@/components/ui/button/button' ;
89import Table from '@/components/ui/table/Table' ;
9- import type { TableRowProps } from '@/components/ui/table/TableRowProps' ;
10+
1011import { ICONS , ICON_SIZES } from '@/constants/icon' ;
1112import { useUserApplications } from '@/context/userApplicationsProvider' ;
1213import useAuth from '@/hooks/useAuth' ;
14+
15+ import type { TableRowProps } from '@/components/ui/table/TableRowProps' ;
1316import type { ApiResponse } from '@/types/api' ;
1417import type { ApplicationItem } from '@/types/applications' ;
1518import type { User , UserType } from '@/types/user' ;
@@ -22,8 +25,6 @@ export default function MyProfileDetailPage() {
2225 const [ offset , setOffset ] = useState ( 0 ) ;
2326 const limit = 5 ;
2427
25- const [ tableRows , setTableRows ] = useState < TableRowProps [ ] > ( [ ] ) ;
26-
2728 // 프로필 비었는지 판단 (User | null 안전)
2829 function isProfileEmpty ( u : User | null ) : boolean {
2930 const name = u ?. name ?. trim ( ) ?? '' ;
@@ -37,12 +38,13 @@ export default function MyProfileDetailPage() {
3738 const headers : string [ ] = [ '가게명' , '근무일시' , '시급' , '상태' ] ;
3839 const userType : UserType = 'employee' ;
3940
40- // 서버 응답 → TableRowProps 매핑
41+ // 서버 응답 → TableRowProps 매핑 (shopId/noticeId 포함)
4142 const rows : TableRowProps [ ] = useMemo ( ( ) => {
4243 return applications . map ( ( app : ApiResponse < ApplicationItem > ) => {
4344 const a = app . item ;
4445 const status =
4546 a . status === 'accepted' ? 'approved' : a . status === 'rejected' ? 'rejected' : 'pending' ;
47+
4648 return {
4749 id : a . id ,
4850 name : a . shop . item . name ,
@@ -52,6 +54,7 @@ export default function MyProfileDetailPage() {
5254 status,
5355 bio : '' ,
5456 phone : '' ,
57+ // ✅ TableRow가 요구하는 키 채움
5558 shopId : a . shop . item . id ,
5659 noticeId : a . notice . item . id ,
5760 } ;
@@ -78,46 +81,20 @@ export default function MyProfileDetailPage() {
7881
7982 const pagedRows = useMemo ( ( ) => currentRows . slice ( offset , offset + limit ) , [ currentRows , offset ] ) ;
8083
81- useEffect ( ( ) => {
82- const mappedRows : TableRowProps [ ] = applications . map ( app => {
83- const a = app . item ;
84- const status =
85- a . status === 'accepted' ? 'approved' : a . status === 'rejected' ? 'rejected' : 'pending' ;
86- return {
87- id : a . id ,
88- name : a . shop . item . name ,
89- hourlyPay : `${ a . notice . item . hourlyPay . toLocaleString ( ) } 원` ,
90- startsAt : a . notice . item . startsAt ,
91- workhour : a . notice . item . workhour ,
92- status,
93- bio : '' ,
94- phone : '' ,
95- shopId : a . shop . item . id ,
96- noticeId : a . notice . item . id ,
97- } ;
98- } ) ;
99-
100- setTableRows ( mappedRows ) ;
101- } , [ applications ] ) ;
102-
10384 return (
10485 < main className = 'mx-auto w-full max-w-[1440px] py-6 tablet:py-8' >
105- { /* 공통 컨테이너: Table과 좌측선/폭 동일 */ }
106- < div className = 'mx-auto w-full max-w-full px-8 md:px-10 lg:mx-auto lg:max-w-[1000px] lg:px-0' >
107- { profileIsEmpty ? (
108- < >
109- < h1 className = 'mb-6 text-heading-l font-semibold' > 내 프로필</ h1 >
110- < div className = 'mx-auto w-full' >
111- < Frame
112- title = ''
113- content = '내 프로필을 등록하고 원하는 가게에 지원해 보세요.'
114- buttonText = '내 프로필 등록하기'
115- href = '/my-profile/register'
116- />
117- </ div >
118- </ >
119- ) : (
120- // ✅ 데스크탑에서 제목과 카드가 같은 flex 라인에 놓이도록
86+ { /* ───────────────── 상단 영역 ───────────────── */ }
87+ { profileIsEmpty ? (
88+ // ✅ 2중 컨테이너 제거: Frame만 단독 렌더
89+ < Frame
90+ title = '내 프로필'
91+ content = '내 프로필을 등록하고 원하는 가게에 지원해 보세요.'
92+ buttonText = '내 프로필 등록하기'
93+ href = '/my-profile/register'
94+ />
95+ ) : (
96+ // ✅ 공용 Container로 감싸서 my-shop과 동일한 레이아웃 패턴
97+ < Container as = 'section' isPage >
12198 < div className = 'desktop:flex desktop:items-start desktop:gap-8' >
12299 < h1 className = 'mb-6 text-heading-l font-semibold desktop:mb-0 desktop:w-[200px] desktop:shrink-0 desktop:pt-2' >
123100 내 프로필
@@ -185,52 +162,49 @@ export default function MyProfileDetailPage() {
185162 </ div >
186163 </ section >
187164 </ div >
188- ) }
189- </ div >
165+ </ Container >
166+ ) }
190167
191- { /* 하단: 신청 내역 — 프로필 있고 로그인 상태일 때만 */ }
168+ { /* ──────────────── 하단: 신청 내역 ──────────────── */ }
192169 { ! profileIsEmpty && isLogin && (
193- < section className = 'mt-8 bg-[var(--gray-50)] py-8' >
194- < div className = 'mx-auto w-full max-w-full px-8 md:px-10 lg:mx-auto lg:max-w-[1000px] lg:px-0' >
195- { isLoading && currentRows . length === 0 ? (
196- < >
197- < div className = 'px-0 text-xl font-bold' >
198- < h2 className = 'text-heading-l font-semibold' > 신청 내역</ h2 >
199- </ div >
200- < div className = 'm-7 overflow-hidden rounded-lg border bg-white lg:mx-auto lg:max-w-[1000px]' >
201- < div className = 'h-[48px] bg-[var(--red-100)]' />
202- { [ ...Array ( 5 ) ] . map ( ( _ , i ) => (
203- < div key = { i } className = 'h-[56px] border-t bg-white last:border-b' />
204- ) ) }
205- < div className = 'flex justify-center px-3 py-2' />
206- </ div >
207- </ >
208- ) : currentRows . length === 0 ? (
209- < Frame
210- title = '신청 내역'
211- content = '마음에 드는 공고를 찾아 지원해 보세요.'
212- buttonText = '공고 보러가기'
213- href = '/notices'
214- />
215- ) : (
216- < div className = 'mx-auto w-full desktop:max-w-[964px]' >
170+ < section className = 'mt-8 bg-[var(--gray-50)] pb-8 pt-0 tablet:pt-8' >
171+ { isLoading && currentRows . length === 0 ? (
172+ < Container as = 'section' isPage className = 'pt-0' >
173+ < div className = 'px-0 text-xl font-bold' >
174+ < h2 className = 'text-heading-l font-semibold' > 신청 내역</ h2 >
175+ </ div >
176+ < div className = 'm-7 overflow-hidden rounded-lg border bg-white lg:mx-auto lg:max-w-[1000px]' >
177+ < div className = 'h-[48px] bg-[var(--red-100)]' />
178+ { [ ...Array ( 5 ) ] . map ( ( _ , i ) => (
179+ < div key = { i } className = 'h-[56px] border-t bg-white last:border-b' />
180+ ) ) }
181+ < div className = 'flex justify-center px-3 py-2' />
182+ </ div >
183+ </ Container >
184+ ) : currentRows . length === 0 ? (
185+ // ✅ 2중 컨테이너 제거: Frame만 단독 렌더
186+ < Frame
187+ title = '신청 내역'
188+ content = '마음에 드는 공고를 찾아 지원해 보세요.'
189+ buttonText = '공고 보러가기'
190+ href = '/notices'
191+ />
192+ ) : (
193+ < Container as = 'section' isPage className = 'pt-0' >
194+ < div className = 'mx-auto w-full lg:mx-auto lg:max-w-[1000px]' >
217195 < Table
218196 headers = { headers }
219197 tableData = { pagedRows }
220198 userRole = { userType }
221- total = { applications . length }
199+ total = { currentTotal }
222200 limit = { limit }
223201 offset = { offset }
224202 onPageChange = { setOffset }
225- onStatusUpdate = { ( id , newStatus ) =>
226- setTableRows ( prev =>
227- prev . map ( row => ( row . id === id ? { ...row , status : newStatus } : row ) )
228- )
229- }
203+ onStatusUpdate = { ( ) => { } } // ✅ 이 페이지에서는 상태 변경 없음(필수 prop 무해한 no-op)
230204 />
231205 </ div >
232- ) }
233- </ div >
206+ </ Container >
207+ ) }
234208 </ section >
235209 ) }
236210 </ main >
0 commit comments