@@ -3,7 +3,7 @@ import { useNavigate, useSearchParams } from "react-router";
33import { useForm , useWatch } from "react-hook-form" ;
44import { zodResolver } from "@hookform/resolvers/zod" ;
55import { toast } from "sonner" ;
6- import { createCampaignProposal , getCampaignDetail } from "../../api/matching" ;
6+ import { createCampaignProposal } from "../../api/matching" ;
77import { tokenStorage } from "../../../../lib/token" ;
88import { useCampaignProposalStore } from "../../../../stores/campaign-proposal" ;
99import { useAuthStore } from "../../../../stores/auth-store" ;
@@ -28,7 +28,6 @@ import {
2828 TONE_TAGS ,
2929 INVOLVEMENT_TAGS ,
3030 USAGE_RANGE_TAGS ,
31- PROPOSAL_TAG_ID_BY_NAME ,
3231 type ProposalTag ,
3332} from "../../../../data/proposalTags" ;
3433import {
@@ -106,171 +105,30 @@ export default function CreateCampaignContent() {
106105 } , [ ] ) ;
107106
108107 useEffect ( ( ) => {
109- // 신규 제안 시 폼 초기화
110- if ( type !== "existing" ) {
111- reset ( defaultCampaignFormValues ) ;
112- return ;
113- }
114-
115- let alive = true ;
116-
117- // URL 파라미터로 캠페인 조회 (기존 캠페인 제안 시)
118- const campaignIdParam = searchParams . get ( "campaignId" ) ;
119-
120- if ( campaignIdParam ) {
121- const campaignId = Number ( campaignIdParam ) ;
122-
123- // campaignId가 0보다 큰 경우에만 API 호출 (0은 광고 캠페인이므로 proposalData 사용)
124- if ( Number . isFinite ( campaignId ) && campaignId > 0 ) {
125- ( async ( ) => {
126- try {
127- const detail = await getCampaignDetail ( campaignId ) ;
128- if ( ! alive ) return ;
129-
130- setValue ( "campaignName" , detail . title ) ;
131- setValue ( "description" , detail . description ) ;
132- setValue ( "fee" , detail . rewardAmount . toString ( ) ) ;
133- setValue ( "sponsorProduct" , detail . product ? [ detail . product ] : [ ] ) ;
134- if ( detail . startDate ) setValue ( "startDate" , detail . startDate ) ;
135- if ( detail . endDate ) setValue ( "endDate" , detail . endDate ) ;
136-
137- if ( detail . contentTags ?. formats ?. length > 0 ) {
138- setValue ( "format" , detail . contentTags . formats . map ( f => String ( f . id ) ) ) ;
139- }
140- if ( detail . contentTags ?. categories ?. length > 0 ) {
141- setValue ( "category" , detail . contentTags . categories . map ( c => String ( c . id ) ) ) ;
142- }
143- if ( detail . contentTags ?. tones ?. length > 0 ) {
144- setValue ( "tone" , detail . contentTags . tones . map ( t => String ( t . id ) ) ) ;
145- }
146- if ( detail . contentTags ?. involvements ?. length > 0 ) {
147- setValue ( "involvement" , detail . contentTags . involvements . map ( i => String ( i . id ) ) ) ;
148- }
149- if ( detail . contentTags ?. usageRanges ?. length > 0 ) {
150- setValue ( "usageScope" , detail . contentTags . usageRanges . map ( u => String ( u . id ) ) ) ;
151- }
152- } catch ( error ) {
153- console . error ( "캠페인 상세 조회 실패:" , error ) ;
154- toast . error ( "캠페인 정보를 불러오지 못했습니다" ) ;
155- }
156- } ) ( ) ;
157-
158- return ( ) => {
159- alive = false ;
160- } ;
161- }
162- }
163-
164- if ( proposalData ) {
165- if ( proposalData . campaignTitle ) setValue ( "campaignName" , proposalData . campaignTitle ) ;
166- if ( proposalData . campaignDescription ) setValue ( "description" , proposalData . campaignDescription ) ;
167-
168- // 태그 매핑 (ID를 문자열로 변환하여 배열로 사용)
169- if ( proposalData . contentTags ?. formats && proposalData . contentTags . formats . length > 0 ) {
170- setValue ( "format" , proposalData . contentTags . formats . map ( f => String ( f . id ) ) ) ;
171- }
172- if ( proposalData . contentTags ?. categories && proposalData . contentTags . categories . length > 0 ) {
173- setValue ( "category" , proposalData . contentTags . categories . map ( c => String ( c . id ) ) ) ;
174- }
175- if ( proposalData . contentTags ?. tones && proposalData . contentTags . tones . length > 0 ) {
176- setValue ( "tone" , proposalData . contentTags . tones . map ( t => String ( t . id ) ) ) ;
177- }
178- if ( proposalData . contentTags ?. involvements && proposalData . contentTags . involvements . length > 0 ) {
179- setValue ( "involvement" , proposalData . contentTags . involvements . map ( i => String ( i . id ) ) ) ;
180- }
181- if ( proposalData . contentTags ?. usageRanges && proposalData . contentTags . usageRanges . length > 0 ) {
182- setValue ( "usageScope" , proposalData . contentTags . usageRanges . map ( u => String ( u . id ) ) ) ;
183- }
184-
185- const reward = proposalData . rewardAmount ?. toString ( ) ;
186- if ( reward ) setValue ( "fee" , reward ) ;
187-
188- // products 배열이 있으면 id가 0이 아닌 첫 번째 제품을 선택, 없으면 단일 product 사용
189- let productSet = false ;
190- if ( proposalData . products && proposalData . products . length > 0 ) {
191- const validProduct = proposalData . products . find ( p => {
192- const id = Number ( p . id ) ;
193- return Number . isFinite ( id ) && id > 0 ;
194- } ) ;
195- if ( validProduct ) {
196- setValue ( "sponsorProduct" , [ String ( validProduct . id ) ] ) ;
197- productSet = true ;
198- }
199- }
200-
201- // products에서 유효한 제품을 찾지 못했거나 products가 없으면 product 필드 사용
202- if ( ! productSet && proposalData . product ) {
203- setValue ( "sponsorProduct" , [ proposalData . product ] ) ;
204- }
205-
206- if ( proposalData . startDate ) setValue ( "startDate" , proposalData . startDate ) ;
207- if ( proposalData . endDate ) setValue ( "endDate" , proposalData . endDate ) ;
208- }
209-
210- return ( ) => {
211- alive = false ;
212- } ;
213- } , [ type , proposalData , searchParams , setValue , reset ] ) ;
108+ // 신규/기존 모두 폼 초기화 (기존 제안도 빈 폼으로 시작)
109+ reset ( defaultCampaignFormValues ) ;
110+ } , [ type , reset ] ) ;
214111
215112 const formValues = useWatch ( { control, defaultValue : defaultCampaignFormValues } ) ;
216113
217- const tags = type === "new" ? undefined : proposalData ?. contentTags ;
218-
219- const toOptions = ( defaultTags : ProposalTag [ ] , campaignTags ?: { id ?: number ; name : string } [ ] ) => {
220- if ( campaignTags && campaignTags . length > 0 ) {
221- return campaignTags . map ( ( t ) => ( {
222- value : String ( t . id ?? PROPOSAL_TAG_ID_BY_NAME [ t . name ] ?? t . name ) ,
223- label : t . name ,
224- } ) ) ;
225- }
114+ const toOptions = ( defaultTags : ProposalTag [ ] ) => {
226115 return defaultTags . map ( ( t ) => ( { value : String ( t . id ) , label : t . name } ) ) ;
227116 } ;
228117
229- const formatOptions = toOptions ( FORMAT_TAGS , tags ?. formats ) ;
230- const categoryOptions = toOptions ( CATEGORY_TAGS , tags ?. categories ) ;
231- const toneOptions = toOptions ( TONE_TAGS , tags ?. tones ) ;
232- const involvementOptions = toOptions ( INVOLVEMENT_TAGS , tags ?. involvements ) ;
233- const usageScopeOptions = toOptions ( USAGE_RANGE_TAGS , tags ?. usageRanges ) ;
118+ const formatOptions = toOptions ( FORMAT_TAGS ) ;
119+ const categoryOptions = toOptions ( CATEGORY_TAGS ) ;
120+ const toneOptions = toOptions ( TONE_TAGS ) ;
121+ const involvementOptions = toOptions ( INVOLVEMENT_TAGS ) ;
122+ const usageScopeOptions = toOptions ( USAGE_RANGE_TAGS ) ;
234123
235124 const sponsorProductOptions = useMemo ( ( ) => {
236- const options : { value : string ; label : string } [ ] = [ ] ;
237-
238- // product 필드가 있으면 추가 (문자열 값)
239- if ( proposalData ?. product ) {
240- options . push ( { value : proposalData . product , label : proposalData . product } ) ;
241- }
242-
243- // products 배열이 있으면 추가 (id > 0인 것만)
244- if ( proposalData ?. products && proposalData . products . length > 0 ) {
245- const validProducts = proposalData . products
246- . filter ( ( p ) => {
247- const id = String ( p . id ) . trim ( ) ;
248- const name = String ( p . name ) . trim ( ) ;
249- // id가 0이 아니고, id와 name이 모두 있는 경우만 포함
250- return id && name && id !== "0" ;
251- } )
252- . map ( ( p ) => ( { value : String ( p . id ) , label : String ( p . name ) . trim ( ) } ) ) ;
253- options . push ( ...validProducts ) ;
254- }
255-
256- // 중복 제거 (value 기준)
257- const uniqueOptions = options . reduce ( ( acc , current ) => {
258- const exists = acc . find ( opt => opt . value === current . value ) ;
259- if ( ! exists ) {
260- acc . push ( current ) ;
261- }
262- return acc ;
263- } , [ ] as { value : string ; label : string } [ ] ) ;
264-
265- const baseOptions = type === "new" ? [ ] : uniqueOptions ;
266-
267- // formValues.sponsorProduct 배열에 있는데 options에 없는 항목들 추가 (id가 0이 아닌 경우만)
268- const missingOptions = ( formValues . sponsorProduct || [ ] )
269- . filter ( sp => sp !== "0" && ! baseOptions . find ( opt => opt . value === sp ) )
125+ // 사용자가 직접 입력한 협찬품 항목만 표시
126+ const customOptions = ( formValues . sponsorProduct || [ ] )
127+ . filter ( sp => sp !== "0" )
270128 . map ( sp => ( { value : sp , label : sp } ) ) ;
271129
272- return [ ... missingOptions , ... baseOptions ] ;
273- } , [ proposalData , type , formValues . sponsorProduct ] ) ;
130+ return customOptions ;
131+ } , [ formValues . sponsorProduct ] ) ;
274132
275133 // ID 배열로 label들 찾기 헬퍼 함수
276134 const findLabels = ( options : { value : string ; label : string } [ ] , values ?: string [ ] ) => {
0 commit comments