11import moment from 'moment'
22
3+ import { WorkStrings } from '../../../work-constants'
34import {
45 Challenge ,
56 ChallengeCreateBody ,
67 ChallengeMetadata ,
78 ChallengeMetadataName ,
9+ ChallengeMetadataTitle ,
810 ChallengePhase ,
911 ChallengePhaseName ,
12+ ChallengeUpdateBody ,
1013 Work ,
1114 WorkPrice ,
15+ WorkPriceBreakdown ,
1216 WorkPricesType ,
17+ WorkPrize ,
1318 WorkProgress ,
1419 WorkProgressStep ,
1520 WorkStatus ,
@@ -74,7 +79,7 @@ export function buildCreateBody(workTypeConfig: WorkTypeConfig): ChallengeCreate
7479 }
7580
7681 return {
77- description : 'Information not provided' ,
82+ description : WorkStrings . INFO_NOT_PROVIDED ,
7883 discussions : [
7984 {
8085 name : 'new-self-service-project' ,
@@ -97,6 +102,69 @@ export function buildCreateBody(workTypeConfig: WorkTypeConfig): ChallengeCreate
97102 }
98103}
99104
105+ export function buildUpdateBody ( workTypeConfig : WorkTypeConfig , challenge : Challenge , formData : any ) : ChallengeUpdateBody {
106+
107+ const type : WorkType = workTypeConfig . type
108+
109+ const intakeForm : ChallengeMetadata | undefined = findMetadata ( challenge , ChallengeMetadataName . intakeForm ) || undefined
110+ const form : IntakeForm = ! ! intakeForm ?. value ? JSON . parse ( intakeForm . value ) ?. form : { }
111+ form . basicInfo = formData
112+
113+ // TODO: Add the progress.currentStep to form to determine if it's in the review phase (review page)
114+ // or not. The legacy intakes use currentStep 7 for review and 5 for taking the user to the login step
115+ // as those numbers map to the routes configured for each work type (see IntakeForm.jsx for an example).
116+ // We can probably clean that up as we don't need that many routes
117+
118+ // --- Build Metadata --- //
119+ const intakeMetadata : Array < ChallengeMetadata > = [
120+ {
121+ name : ChallengeMetadataName . intakeForm ,
122+ value : JSON . stringify ( { form } ) ,
123+ } ,
124+ ]
125+
126+ Object . keys ( formData ) . forEach ( ( key ) => {
127+ intakeMetadata . push ( {
128+ name : ChallengeMetadataName [ key as keyof typeof ChallengeMetadataName ] ,
129+ value : formData [ key ] || '' ,
130+ } )
131+ } )
132+ // ---- End Build Metadata ---- //
133+
134+ // --- Build the Markdown string that gets displayed in Work Manager app and others --- //
135+ const templateString : Array < string > = [ ]
136+
137+ const data : ReadonlyArray < FormDetail > = mapFormData (
138+ type ,
139+ formData
140+ )
141+
142+ data . forEach ( ( formDetail ) => {
143+ if ( Object . keys ( formDetail ) . length <= 0 ) { return }
144+
145+ const formattedValue : string = formatFormDataOption ( formDetail . value )
146+ templateString . push ( `### ${ formDetail . title } \n\n${ formattedValue } \n\n` )
147+ } )
148+
149+ if ( getTypeCategory ( type ) === WorkTypeCategory . data ) {
150+ templateString . push (
151+ WorkStrings . MARKDOWN_SUBMISSION_GUIDELINES
152+ )
153+ }
154+ // ---- End Build Markdown string ---- //
155+
156+ const body : ChallengeUpdateBody = {
157+ description : templateString . join ( '' ) ,
158+ id : challenge . id ,
159+ metadata : intakeMetadata ,
160+ name : formData . projectTitle ,
161+ phases : workTypeConfig . timeline ,
162+ prizeSets : getPrizes ( workTypeConfig ) ,
163+ }
164+
165+ return body
166+ }
167+
100168export function getStatus ( challenge : Challenge ) : WorkStatus {
101169
102170 switch ( challenge . status ) {
@@ -135,11 +203,50 @@ export function mapFormData(type: string, formData: any): ReadonlyArray<FormDeta
135203 case ( WorkType . design ) :
136204 return buildFormDataDesign ( formData )
137205 case ( WorkType . bugHunt ) :
138- return buildFormBughunt ( formData )
206+ return buildFormDataBugHunt ( formData )
139207 default :
140208 return formData
141209 }
142210}
211+ function buildFormDataBugHunt ( formData : any ) : ReadonlyArray < FormDetail > {
212+ return [
213+ {
214+ key : ChallengeMetadataName . projectTitle ,
215+ title : ChallengeMetadataTitle . projectTitle ,
216+ value : formData . projectTitle ,
217+ } ,
218+ {
219+ key : ChallengeMetadataName . websiteURL ,
220+ title : ChallengeMetadataTitle . websiteURL ,
221+ value : formData . websiteURL ,
222+ } ,
223+ {
224+ key : ChallengeMetadataName . goals ,
225+ title : ChallengeMetadataTitle . bugHuntGoals ,
226+ value : formData . goals ,
227+ } ,
228+ {
229+ key : ChallengeMetadataName . featuresToTest ,
230+ title : ChallengeMetadataTitle . featuresToTest ,
231+ value : formData . featuresToTest ,
232+ } ,
233+ {
234+ key : ChallengeMetadataName . deliveryType ,
235+ title : ChallengeMetadataTitle . bugDeliveryType ,
236+ value : `${ formData . deliveryType } ${ formData . repositoryLink ? ': ' + formData . repositoryLink : '' } ` ,
237+ } ,
238+ {
239+ key : ChallengeMetadataName . additionalInformation ,
240+ title : ChallengeMetadataTitle . additionalInformation ,
241+ value : formData . additionalInformation ,
242+ } ,
243+ {
244+ key : ChallengeMetadataName . packageType ,
245+ title : ChallengeMetadataTitle . bugHuntPackage ,
246+ value : formData . packageType ,
247+ } ,
248+ ]
249+ }
143250
144251function buildFormDataData ( formData : any ) : ReadonlyArray < FormDetail > {
145252 return [
@@ -207,41 +314,6 @@ function buildFormDataDesign(formData: any): ReadonlyArray<FormDetail> {
207314 ]
208315}
209316
210- function buildFormBughunt ( formData : any ) : ReadonlyArray < FormDetail > {
211-
212- return [
213- {
214- key : 'projectTitle' ,
215- ...formData . projectTitle ,
216- } ,
217- {
218- key : 'websiteURL' ,
219- ...formData . websiteURL ,
220- } ,
221- {
222- key : 'goals' ,
223- ...formData . goals ,
224- } ,
225- {
226- key : 'features' ,
227- ...formData . features ,
228- } ,
229- {
230- key : 'bugDelivery' ,
231- title : 'Bug Delivery' ,
232- value : `[${ formData . deliveryType . value } ]: ${ formData . deliveryUrl . value } ` ,
233- } ,
234- {
235- key : 'additionalInformation' ,
236- ...formData . additionalInformation ,
237- } ,
238- {
239- key : 'packageType' ,
240- ...formData . packageType ,
241- } ,
242- ]
243- }
244-
245317function buildFormDataFindData ( formData : any ) : ReadonlyArray < FormDetail > {
246318 const isPrimaryDataChallengeOther : boolean = formData . primaryDataChallenge ?. value === 3
247319 return [
@@ -289,6 +361,22 @@ function buildFormDataProblem(formData: any): ReadonlyArray<FormDetail> {
289361 ]
290362}
291363
364+ /**
365+ * This function checks if the param provided is empty based on its type
366+ * The param is empty if: is falsey || is an empty string || is an empty array || is an empty object
367+ * This is used for determining if a form field entry is emtpy after being formatted for display
368+ */
369+ function checkFormDataOptionEmpty ( detail : any ) : boolean {
370+ return (
371+ ! detail ||
372+ ( typeof detail === 'string' && detail . trim ( ) . length === 0 ) ||
373+ ( Array . isArray ( detail ) && detail . length === 0 ) ||
374+ ( typeof detail === 'object' &&
375+ Object . values ( detail ) . filter ( ( val : any ) => val && val . trim ( ) . length !== 0 )
376+ . length === 0 )
377+ )
378+ }
379+
292380function findMetadata ( challenge : Challenge , metadataName : ChallengeMetadataName ) : ChallengeMetadata | undefined {
293381 return challenge . metadata ?. find ( ( item : ChallengeMetadata ) => item . name === metadataName )
294382}
@@ -326,6 +414,27 @@ function findPhase(challenge: Challenge, phases: Array<string>): ChallengePhase
326414 return phase
327415}
328416
417+ function formatFormDataOption ( detail : Array < string > | { [ key : string ] : any } ) : string {
418+ const noInfoProvidedText : string = WorkStrings . NOT_PROVIDED
419+ const isEmpty : boolean = checkFormDataOptionEmpty ( detail )
420+
421+ if ( isEmpty ) {
422+ return noInfoProvidedText
423+ }
424+ if ( Array . isArray ( detail ) ) {
425+ return detail . join ( '\n\n' )
426+ }
427+ if ( typeof detail === 'object' ) {
428+ return Object . keys ( detail )
429+ . map ( ( key : string ) => {
430+ const value : string = detail [ key ] || noInfoProvidedText
431+ return `${ key } : ${ value } `
432+ } )
433+ . join ( '\n\n' )
434+ }
435+ return detail
436+ }
437+
329438function getCost ( challenge : Challenge , priceConfig : WorkPrice , type : WorkType ) : number | undefined {
330439
331440 switch ( type ) {
@@ -357,6 +466,33 @@ function getDescription(challenge: Challenge, type: WorkType): string | undefine
357466 }
358467}
359468
469+ function getPrizes ( workTypeConfig : WorkTypeConfig ) : Array < WorkPrize > {
470+ const priceConfig : WorkPriceBreakdown =
471+ workTypeConfig . usePromo && workTypeConfig . promo
472+ ? workTypeConfig . promo
473+ : workTypeConfig . base
474+
475+ return [
476+ {
477+ description : 'Challenge Prizes' ,
478+ prizes : priceConfig . placementDistributions . map ( ( percentage ) => ( {
479+ type : 'USD' ,
480+ value : Math . round ( percentage * priceConfig . price ) ,
481+ } ) ) ,
482+ type : 'placement' ,
483+ } ,
484+ {
485+ description : 'Reviewer Payment' ,
486+ prizes :
487+ priceConfig . reviewerDistributions . map ( ( percentage ) => ( {
488+ type : 'USD' ,
489+ value : Math . round ( percentage * priceConfig . price ) ,
490+ } ) ) ,
491+ type : 'reviewer' ,
492+ } ,
493+ ]
494+ }
495+
360496function getProgress ( challenge : Challenge , workStatus : WorkStatus ) : WorkProgress {
361497
362498 const steps : ReadonlyArray < WorkProgressStep > = [
0 commit comments