Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d099657
PROD-2437 #comment started creating service call to patch challenge #…
Jul 8, 2022
264a62b
Merge branch 'PROD-2321_bug-hunt-intake-form' into PROD-2437_patch-ch…
Jul 11, 2022
6c39b2f
PROD-2437 #comment Created method to build the update challenge body.…
Jul 11, 2022
b7f0286
Merge branch 'PROD-2321_bug-hunt-intake-form' into PROD-2437_patch-ch…
Jul 12, 2022
3c6bd73
PROD-2437 #comment Merge branch 'PROD-2436_create-challenge' into PRO…
Jul 12, 2022
314b265
PROD-2437 #comment Finalizing the updateAsync method #time 1h
Jul 13, 2022
062fda4
Merge branch 'PROD-2321_bug-hunt-intake-form' into PROD-2437_patch-ch…
Jul 18, 2022
3d244f0
PROD-2437 #comment Bug Hunt form gets saved when clicking on Complete…
Jul 18, 2022
225b76d
PROD-2437 #comment Added an enum for Challenge Metadata Titles #time 45m
Jul 18, 2022
305049e
Merge branch 'PROD-2321_bug-hunt-intake-form' into PROD-2437_patch-ch…
Jul 18, 2022
27c7e9f
PROD-2437 #comment Lint and code cleanup #time 10m
Jul 18, 2022
2253597
PROD-2437 #comment Removed Lodash round in favor of Math.round #time 5m
Jul 19, 2022
1160c16
Merge branch 'PROD-2321_bug-hunt-intake-form' into PROD-2437_patch-ch…
Jul 19, 2022
798fbef
PROD-2437 #comment Added comments for clarification and save formData…
Jul 19, 2022
c0cfdb0
Merge branch 'PROD-2321_bug-hunt-intake-form' into PROD-2437_patch-ch…
Jul 19, 2022
9ee0585
Added packageType to ChallangeMetadata
Jul 19, 2022
0c443d1
Merge branch 'PROD-2321_bug-hunt-intake-form' into PROD-2437_patch-ch…
Jul 19, 2022
2b20e5b
PROD-2437 #comment Added a json file to hold string constants #time 30m
Jul 19, 2022
473f89e
cleanup
Jul 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src-ts/tools/work/work-lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './work-constants'
export * from './work-images'
export * from './work-pdfs'
export * from './work-provider'
Expand Down
1 change: 1 addition & 0 deletions src-ts/tools/work/work-lib/work-constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as WorkStrings } from './strings.json'
5 changes: 5 additions & 0 deletions src-ts/tools/work/work-lib/work-constants/strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"INFO_NOT_PROVIDED": "Information not provided",
"MARKDOWN_SUBMISSION_GUIDELINES": "## Final Submission Guidelines \n\n Please submit a zip file containing your analysis/solution.",
"NOT_PROVIDED": "Not provided"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './work-factory'
export {
type Challenge,
ChallengeMetadataName,
ChallengeMetadataTitle,
type Work,
workBugHuntConfig,
workPriceData,
Expand All @@ -27,4 +28,5 @@ export {
getGroupedByStatus as workGetGroupedByStatus,
getPricesConfig as workGetPricesConfig,
getStatusFilter as workGetStatusFilter,
updateAsync as workUpdateAsync,
} from './work.functions'
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './work-solution.model'
export {
create as workFactoryCreate,
buildCreateBody as workFactoryBuildCreateBody,
buildUpdateBody as workFactoryBuildUpdateBody,
getStatus as workFactoryGetStatus,
mapFormData as workFactoryMapFormData,
} from './work.factory'
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import moment from 'moment'

import { WorkStrings } from '../../../work-constants'
import {
Challenge,
ChallengeCreateBody,
ChallengeMetadata,
ChallengeMetadataName,
ChallengeMetadataTitle,
ChallengePhase,
ChallengePhaseName,
ChallengeUpdateBody,
Work,
WorkPrice,
WorkPriceBreakdown,
WorkPricesType,
WorkPrize,
WorkProgress,
WorkProgressStep,
WorkStatus,
Expand Down Expand Up @@ -74,7 +79,7 @@ export function buildCreateBody(workTypeConfig: WorkTypeConfig): ChallengeCreate
}

return {
description: 'Information not provided',
description: WorkStrings.INFO_NOT_PROVIDED,
discussions: [
{
name: 'new-self-service-project',
Expand All @@ -97,6 +102,69 @@ export function buildCreateBody(workTypeConfig: WorkTypeConfig): ChallengeCreate
}
}

export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Challenge, formData: any): ChallengeUpdateBody {

const type: WorkType = workTypeConfig.type

const intakeForm: ChallengeMetadata | undefined = findMetadata(challenge, ChallengeMetadataName.intakeForm) || undefined
const form: IntakeForm = !!intakeForm?.value ? JSON.parse(intakeForm.value)?.form : {}
form.basicInfo = formData

// TODO: Add the progress.currentStep to form to determine if it's in the review phase (review page)
// or not. The legacy intakes use currentStep 7 for review and 5 for taking the user to the login step
// as those numbers map to the routes configured for each work type (see IntakeForm.jsx for an example).
// We can probably clean that up as we don't need that many routes

// --- Build Metadata --- //
const intakeMetadata: Array<ChallengeMetadata> = [
{
name: ChallengeMetadataName.intakeForm,
value: JSON.stringify({ form }),
},
]

Object.keys(formData).forEach((key) => {
intakeMetadata.push({
name: ChallengeMetadataName[key as keyof typeof ChallengeMetadataName],
value: formData[key] || '',
})
})
// ---- End Build Metadata ---- //

// --- Build the Markdown string that gets displayed in Work Manager app and others --- //
const templateString: Array<string> = []

const data: ReadonlyArray<FormDetail> = mapFormData(
type,
formData
)

data.forEach((formDetail) => {
if (Object.keys(formDetail).length <= 0) { return }

const formattedValue: string = formatFormDataOption(formDetail.value)
templateString.push(`### ${formDetail.title}\n\n${formattedValue}\n\n`)
})

if (getTypeCategory(type) === WorkTypeCategory.data) {
templateString.push(
WorkStrings.MARKDOWN_SUBMISSION_GUIDELINES
)
}
// ---- End Build Markdown string ---- //

const body: ChallengeUpdateBody = {
description: templateString.join(''),
id: challenge.id,
metadata: intakeMetadata,
name: formData.projectTitle,
phases: workTypeConfig.timeline,
prizeSets: getPrizes(workTypeConfig),
}

return body
}

export function getStatus(challenge: Challenge): WorkStatus {

switch (challenge.status) {
Expand Down Expand Up @@ -135,11 +203,50 @@ export function mapFormData(type: string, formData: any): ReadonlyArray<FormDeta
case (WorkType.design):
return buildFormDataDesign(formData)
case (WorkType.bugHunt):
return buildFormBughunt(formData)
return buildFormDataBugHunt(formData)
default:
return formData
}
}
function buildFormDataBugHunt(formData: any): ReadonlyArray<FormDetail> {
return [
{
key: ChallengeMetadataName.projectTitle,
title: ChallengeMetadataTitle.projectTitle,
value: formData.projectTitle,
},
{
key: ChallengeMetadataName.websiteURL,
title: ChallengeMetadataTitle.websiteURL,
value: formData.websiteURL,
},
{
key: ChallengeMetadataName.goals,
title: ChallengeMetadataTitle.bugHuntGoals,
value: formData.goals,
},
{
key: ChallengeMetadataName.featuresToTest,
title: ChallengeMetadataTitle.featuresToTest,
value: formData.featuresToTest,
},
{
key: ChallengeMetadataName.deliveryType,
title: ChallengeMetadataTitle.bugDeliveryType,
value: `${formData.deliveryType}${formData.repositoryLink ? ': ' + formData.repositoryLink : ''}`,
},
{
key: ChallengeMetadataName.additionalInformation,
title: ChallengeMetadataTitle.additionalInformation,
value: formData.additionalInformation,
},
{
key: ChallengeMetadataName.packageType,
title: ChallengeMetadataTitle.bugHuntPackage,
value: formData.packageType,
},
]
}

function buildFormDataData(formData: any): ReadonlyArray<FormDetail> {
return [
Expand Down Expand Up @@ -207,41 +314,6 @@ function buildFormDataDesign(formData: any): ReadonlyArray<FormDetail> {
]
}

function buildFormBughunt(formData: any): ReadonlyArray<FormDetail> {

return [
{
key: 'projectTitle',
...formData.projectTitle,
},
{
key: 'websiteURL',
...formData.websiteURL,
},
{
key: 'goals',
...formData.goals,
},
{
key: 'features',
...formData.features,
},
{
key: 'bugDelivery',
title: 'Bug Delivery',
value: `[${formData.deliveryType.value}]: ${formData.deliveryUrl.value}`,
},
{
key: 'additionalInformation',
...formData.additionalInformation,
},
{
key: 'packageType',
...formData.packageType,
},
]
}

function buildFormDataFindData(formData: any): ReadonlyArray<FormDetail> {
const isPrimaryDataChallengeOther: boolean = formData.primaryDataChallenge?.value === 3
return [
Expand Down Expand Up @@ -289,6 +361,22 @@ function buildFormDataProblem(formData: any): ReadonlyArray<FormDetail> {
]
}

/**
* This function checks if the param provided is empty based on its type
* The param is empty if: is falsey || is an empty string || is an empty array || is an empty object
* This is used for determining if a form field entry is emtpy after being formatted for display
*/
function checkFormDataOptionEmpty(detail: any): boolean {
return (
!detail ||
(typeof detail === 'string' && detail.trim().length === 0) ||
(Array.isArray(detail) && detail.length === 0) ||
(typeof detail === 'object' &&
Object.values(detail).filter((val: any) => val && val.trim().length !== 0)
.length === 0)
)
}

function findMetadata(challenge: Challenge, metadataName: ChallengeMetadataName): ChallengeMetadata | undefined {
return challenge.metadata?.find((item: ChallengeMetadata) => item.name === metadataName)
}
Expand Down Expand Up @@ -326,6 +414,27 @@ function findPhase(challenge: Challenge, phases: Array<string>): ChallengePhase
return phase
}

function formatFormDataOption(detail: Array<string> | { [key: string]: any }): string {
const noInfoProvidedText: string = WorkStrings.NOT_PROVIDED
const isEmpty: boolean = checkFormDataOptionEmpty(detail)

if (isEmpty) {
return noInfoProvidedText
}
if (Array.isArray(detail)) {
return detail.join('\n\n')
}
if (typeof detail === 'object') {
return Object.keys(detail)
.map((key: string) => {
const value: string = detail[key] || noInfoProvidedText
return `${key}: ${value}`
})
.join('\n\n')
}
return detail
}

function getCost(challenge: Challenge, priceConfig: WorkPrice, type: WorkType): number | undefined {

switch (type) {
Expand Down Expand Up @@ -357,6 +466,33 @@ function getDescription(challenge: Challenge, type: WorkType): string | undefine
}
}

function getPrizes(workTypeConfig: WorkTypeConfig): Array<WorkPrize> {
const priceConfig: WorkPriceBreakdown =
workTypeConfig.usePromo && workTypeConfig.promo
? workTypeConfig.promo
: workTypeConfig.base

return [
{
description: 'Challenge Prizes',
prizes: priceConfig.placementDistributions.map((percentage) => ({
type: 'USD',
value: Math.round(percentage * priceConfig.price),
})),
type: 'placement',
},
{
description: 'Reviewer Payment',
prizes:
priceConfig.reviewerDistributions.map((percentage) => ({
type: 'USD',
value: Math.round(percentage * priceConfig.price),
})),
type: 'reviewer',
},
]
}

function getProgress(challenge: Challenge, workStatus: WorkStatus): WorkProgress {

const steps: ReadonlyArray<WorkProgressStep> = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
export enum ChallengeMetadataName {
additionalInformation = 'additionalInformation',
deliveryType = 'deliveryType',
deviceCount = 'basicInfo.numberOfDevices',
description = 'websitePurpose.description',
featuresToTest = 'featuresToTest',
feedback = 'customerFeedback',
goals = 'goals',
intakeForm = 'intake-form',
pageCount = 'basicInfo.numberOfPages',
packageType = 'packageType',
projectTitle = 'projectTitle',
repositoryLink = 'repositoryLink',
websiteURL = 'websiteURL',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export enum ChallengeMetadataTitle {
additionalInformation = 'Additional Information',
bugDeliveryType = 'Bug Delivery',
bugHuntGoals = 'Bug Hunt Goals',
bugHuntPackage = 'Bug Hunt Package',
featuresToTest = 'Features to Test',
projectTitle = 'Project Title',
websiteURL = 'Website URL',
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { ChallengeMetadata } from './challenge-metadata.model'
import { ChallengePhase } from './challenge-phase'
import { ChallengeTag } from './challenge-tag.enum'
import { WorkPrize } from './work-prize.model'
import { WorkTimelinePhase } from './work-timeline-phase.model'

export interface Challenge {
created: string
description: string
discussions?: Array<{ [key: string]: string }>
id: string
legacy?: { [key: string]: any },
legacy?: { [key: string]: any }
metadata: Array<ChallengeMetadata>
name: string
numOfRegistrants?: number
numOfSubmissions?: number
phases: Array<ChallengePhase>
prizeSets?: Array<WorkPrize>
status: string
tags: Array<ChallengeTag>
timelineTemplateId?: string
Expand All @@ -33,3 +36,14 @@ export type ChallengeCreateBody = Pick<
'trackId' |
'typeId'
>

export type ChallengeUpdateBody = Pick<
Challenge,
'description' |
'id' |
'metadata' |
'name' |
'prizeSets'
> & {
phases: ReadonlyArray<WorkTimelinePhase>
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './challenge-metadata-name.enum'
export * from './challenge-metadata-title.enum'
export * from './challenge-metadata.model'
export * from './challenge-phase'
export * from './challenge-phase-name.enum'
Expand All @@ -14,6 +15,7 @@ export {
problem as workPriceProblem,
getPricesConfig as workGetPricesConfig,
} from './work-prices.store'
export * from './work-prize.model'
export * from './work-progress.model'
export * from './work-progress-step.model'
export * from './work-status-filter.enum'
Expand All @@ -31,4 +33,5 @@ export {
deleteAsync as workStoreDeleteAsync,
getAsync as workStoreGetAsync,
getFilteredByStatus as workStoreGetFilteredByStatus,
updateAsync as workStoreUpdateAsync,
} from './work.store'
Loading