@@ -10,6 +10,8 @@ import { getNotice, putNotice } from "@/apis/services/noticeService";
1010import { Close } from "@/assets/icon" ;
1111import Button from "@/components/Button" ;
1212import TextField from "@/components/TextField" ;
13+ import { ROUTES } from "@/constants/router" ;
14+ import { MIN_WAGE , MAX_WAGE } from "@/constants/wage" ;
1315import { useUserStore } from "@/hooks/useUserStore" ;
1416import { useModalStore } from "@/store/useModalStore" ;
1517import { extractDigits , numberCommaFormatter } from "@/utils/number" ;
@@ -44,19 +46,77 @@ export default function NoticeEditPage() {
4446 } ) ;
4547
4648 useEffect ( ( ) => {
47- async function fetchNotice ( ) {
48- if ( ! shopId || ! noticeId ) return ;
49- const res = await getNotice ( shopId , noticeId ) ;
50- const { hourlyPay, startsAt, workhour, description } = res . data . item ;
51- setForm ( {
52- hourlyPay : numberCommaFormatter ( hourlyPay ) ,
53- startsAt : new Date ( startsAt ) ,
54- workhour : String ( workhour ) ,
55- description : description ?? "" ,
49+ if ( ! user ) {
50+ openModal ( {
51+ type : "alert" ,
52+ iconType : "warning" ,
53+ message : "로그인 후에 이용 가능한 기능입니다." ,
54+ onClose : ( ) => navigate ( ROUTES . AUTH . SIGNIN ) ,
55+ } ) ;
56+ return ;
57+ }
58+ if ( user . type === "employee" ) {
59+ openModal ( {
60+ type : "alert" ,
61+ iconType : "warning" ,
62+ message : "사장님 계정으로만 이용 가능한 기능입니다." ,
63+ onClose : ( ) => navigate ( ROUTES . PROFILE . ROOT ) ,
5664 } ) ;
65+ return ;
5766 }
67+ if ( ! user . shopId ) {
68+ openModal ( {
69+ type : "alert" ,
70+ iconType : "warning" ,
71+ message : "가게 정보 등록 후 이용 가능합니다." ,
72+ onClose : ( ) => navigate ( ROUTES . SHOP . REGISTER ) ,
73+ } ) ;
74+ return ;
75+ }
76+ } , [ ] ) ;
77+
78+ useEffect ( ( ) => {
79+ if ( ! shopId || ! noticeId ) return ;
80+ const fetchNotice = async ( ) => {
81+ try {
82+ const res = await getNotice ( shopId , noticeId ) ;
83+ const {
84+ hourlyPay,
85+ startsAt,
86+ workhour,
87+ description,
88+ shop : noticeShop ,
89+ } = res . data . item ;
90+
91+ const ownerShopId = noticeShop ?. item . id ;
92+
93+ if ( ownerShopId !== shopId ) {
94+ openModal ( {
95+ type : "alert" ,
96+ iconType : "warning" ,
97+ message : "다른 가게의 공고 편집은 불가능합니다." ,
98+ onClose : ( ) => navigate ( ROUTES . SHOP . ROOT ) ,
99+ } ) ;
100+ return ;
101+ }
102+
103+ setForm ( {
104+ hourlyPay : numberCommaFormatter ( hourlyPay ) ,
105+ startsAt : new Date ( startsAt ) ,
106+ workhour : String ( workhour ) ,
107+ description : description ?? "" ,
108+ } ) ;
109+ } catch {
110+ openModal ( {
111+ type : "alert" ,
112+ iconType : "warning" ,
113+ message : "다른 가게의 공고 편집은 불가능합니다." ,
114+ onClose : ( ) => navigate ( ROUTES . SHOP . ROOT ) ,
115+ } ) ;
116+ }
117+ } ;
58118 fetchNotice ( ) ;
59- } , [ shopId , noticeId ] ) ;
119+ } , [ shopId , noticeId , navigate , openModal ] ) ;
60120
61121 const handleChange = ( key : keyof FormType , value : string | null | Date ) => {
62122 setForm ( ( prev ) => ( { ...prev , [ key ] : value } ) ) ;
@@ -90,11 +150,20 @@ export default function NoticeEditPage() {
90150 }
91151
92152 const hourlyPay = Number ( extractDigits ( form . hourlyPay ) ) ;
93- if ( isNaN ( hourlyPay ) || hourlyPay <= 0 ) {
153+ const formattedMaxWage = numberCommaFormatter ( MAX_WAGE ) ;
154+
155+ if ( hourlyPay < MIN_WAGE ) {
94156 openModal ( {
95157 type : "alert" ,
96158 iconType : "warning" ,
97- message : "유효한 시급을 입력해 주세요." ,
159+ message : "시급은 최저시급 이상이어야 합니다." ,
160+ } ) ;
161+ return ;
162+ } else if ( hourlyPay > MAX_WAGE ) {
163+ openModal ( {
164+ type : "alert" ,
165+ iconType : "warning" ,
166+ message : `시급은 ${ formattedMaxWage } 원 이하여야 합니다.` ,
98167 } ) ;
99168 return ;
100169 }
@@ -153,86 +222,88 @@ export default function NoticeEditPage() {
153222 } ;
154223
155224 return (
156- < form
157- className = "w-full max-w-[964px] mx-auto px-4 py-12"
158- onSubmit = { ( e ) => {
159- e . preventDefault ( ) ;
160- handleSubmit ( ) ;
161- } }
162- >
163- < div className = "flex justify-between items-center mb-8" >
164- < h2 className = "sm:text-[1.75rem] text-[1.25rem] font-bold" >
165- 공고 수정
166- </ h2 >
167- < button type = "button" onClick = { ( ) => navigate ( "/shop" ) } >
168- < Close className = "sm:w-8 sm:h-8 w-6 h-6 cursor-pointer" />
169- </ button >
170- </ div >
171-
172- < div className = "grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-5 mb-6" >
173- < TextField . Input
174- label = "시급*"
175- placeholder = "입력"
176- fullWidth
177- value = { form . hourlyPay }
178- onChange = { ( e ) => {
179- const rawValue = e . target . value ;
180- const digitsOnly = extractDigits ( rawValue ) ;
181- const formatted = digitsOnly
182- ? numberCommaFormatter ( Number ( digitsOnly ) )
183- : "" ;
184- handleChange ( "hourlyPay" , formatted ) ;
185- } }
186- postfix = { < span className = "text-black mr-2" > 원</ span > }
187- />
188- < div className = "flex flex-col" >
189- < label className = "inline-block mb-2 leading-[1.625rem]" >
190- 시작 일시*
191- </ label >
192- < DatePicker
193- selected = { form . startsAt }
194- onChange = { ( date ) => handleChange ( "startsAt" , date ) }
195- showTimeSelect
196- timeFormat = "HH:mm"
197- timeIntervals = { 10 }
198- dateFormat = "yyyy-MM-dd HH:mm"
199- placeholderText = "선택"
200- className = "w-full border border-gray-30 focus-within:border-blue-20 rounded-[0.375rem] py-4 px-5 text-[1rem]"
225+ < div className = "w-full bg-gray-5 min-h-screen" >
226+ < form
227+ className = "w-full max-w-[964px] mx-auto px-4 py-12"
228+ onSubmit = { ( e ) => {
229+ e . preventDefault ( ) ;
230+ handleSubmit ( ) ;
231+ } }
232+ >
233+ < div className = "flex justify-between items-center mb-8" >
234+ < h2 className = "sm:text-[1.75rem] text-[1.25rem] font-bold" >
235+ 공고 수정
236+ </ h2 >
237+ < button type = "button" onClick = { ( ) => navigate ( "/shop" ) } >
238+ < Close className = "sm:w-8 sm:h-8 w-6 h-6 cursor-pointer" />
239+ </ button >
240+ </ div >
241+
242+ < div className = "grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-5 mb-6" >
243+ < TextField . Input
244+ label = "시급*"
245+ placeholder = "입력"
246+ fullWidth
247+ value = { form . hourlyPay }
248+ onChange = { ( e ) => {
249+ const rawValue = e . target . value ;
250+ const digitsOnly = extractDigits ( rawValue ) ;
251+ const formatted = digitsOnly
252+ ? numberCommaFormatter ( Number ( digitsOnly ) )
253+ : "" ;
254+ handleChange ( "hourlyPay" , formatted ) ;
255+ } }
256+ postfix = { < span className = "text-black mr-2" > 원</ span > }
201257 />
258+ < div className = "flex flex-col" >
259+ < label className = "inline-block mb-2 leading-[1.625rem]" >
260+ 시작 일시*
261+ </ label >
262+ < DatePicker
263+ selected = { form . startsAt }
264+ onChange = { ( date ) => handleChange ( "startsAt" , date ) }
265+ showTimeSelect
266+ timeFormat = "HH:mm"
267+ timeIntervals = { 10 }
268+ dateFormat = "yyyy-MM-dd HH:mm"
269+ placeholderText = "선택"
270+ className = "w-full border border-gray-30 focus-within:border-blue-20 rounded-[0.375rem] py-4 px-5 text-[1rem] bg-white"
271+ />
272+ </ div >
273+ < TextField . Input
274+ label = "업무 시간*"
275+ placeholder = "입력"
276+ fullWidth
277+ value = { form . workhour }
278+ onChange = { ( e ) => handleChange ( "workhour" , e . target . value ) }
279+ postfix = {
280+ < span className = "text-black mr-2 whitespace-nowrap" > 시간</ span >
281+ }
282+ />
283+ </ div >
284+ < div className = "mb-10" >
285+ < TextField . TextArea
286+ label = "공고 설명 (최대 500자)"
287+ placeholder = "입력"
288+ fullWidth
289+ rows = { 4 }
290+ maxLength = { 500 }
291+ value = { form . description }
292+ onChange = { ( e ) => handleChange ( "description" , e . target . value ) }
293+ />
294+ </ div >
295+ < div className = "text-center" >
296+ < Button
297+ variant = "primary"
298+ textSize = "md"
299+ className = "sm:w-[350px] w-full px-34 py-3.5"
300+ disabled = { isSubmitting }
301+ type = "submit"
302+ >
303+ 수정하기
304+ </ Button >
202305 </ div >
203- < TextField . Input
204- label = "업무 시간*"
205- placeholder = "입력"
206- fullWidth
207- value = { form . workhour }
208- onChange = { ( e ) => handleChange ( "workhour" , e . target . value ) }
209- postfix = {
210- < span className = "text-black mr-2 whitespace-nowrap" > 시간</ span >
211- }
212- />
213- </ div >
214- < div className = "mb-10" >
215- < TextField . TextArea
216- label = "공고 설명 (최대 500자)"
217- placeholder = "입력"
218- fullWidth
219- rows = { 4 }
220- maxLength = { 500 }
221- value = { form . description }
222- onChange = { ( e ) => handleChange ( "description" , e . target . value ) }
223- />
224- </ div >
225- < div className = "text-center" >
226- < Button
227- variant = "primary"
228- textSize = "md"
229- className = "sm:w-[350px] w-full px-34 py-3.5"
230- disabled = { isSubmitting }
231- type = "submit"
232- >
233- 수정하기
234- </ Button >
235- </ div >
236- </ form >
306+ </ form >
307+ </ div >
237308 ) ;
238309}
0 commit comments