From d099657f3575420f10f5edd781e0909057f13c63 Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Fri, 8 Jul 2022 16:43:17 -0700 Subject: [PATCH 01/11] PROD-2437 #comment started creating service call to patch challenge #time 30m --- .../work-functions/work-factory/work.factory.ts | 4 ++-- .../work-store/challenge.model.ts | 17 ++++++++++++++++- .../work-store/work-url.config.ts | 4 ++++ .../work-functions/work-store/work.store.ts | 12 ++++++++---- .../work-functions/work.functions.ts | 5 +++-- 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts index efbba42b2..ad54e4466 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts @@ -2,7 +2,7 @@ import moment from 'moment' import { Challenge, - ChallengeCreate, + ChallengeCreateBody, ChallengeMetadata, ChallengeMetadataName, ChallengePhase, @@ -64,7 +64,7 @@ export function create(challenge: Challenge, workPrices: WorkPricesType): Work { } } -export function buildCreateBody(type: string): ChallengeCreate { +export function buildCreateBody(type: string): ChallengeCreateBody { // TODO: once configs are merged, use type and config to fetch the necessary fields return { description: 'Information not provided', diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts index e8122e753..ae93fc7e1 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts @@ -1,5 +1,6 @@ import { ChallengeMetadata } from './challenge-metadata.model' import { ChallengePhase } from './challenge-phase' +import { WorkTimeline } from './work-timeline.model' export interface Challenge { created: string @@ -15,7 +16,7 @@ export interface Challenge { updated?: string } -export interface ChallengeCreate { +export interface ChallengeCreateBody { description: string, discussions: Array<{ [key: string]: string }>, legacy: { [key: string]: any }, @@ -25,3 +26,17 @@ export interface ChallengeCreate { trackId: string, typeId: string, } + +interface PrizeSetsType { + type: 'USD', + value: number, +} + +export interface ChallengeUpdateBody { + description: string, + id: string, // Maria do we include id here? + metadata: Array + name: string, + phases: ReadonlyArray + prizeSets: Array +} diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-url.config.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-url.config.ts index 9c63cae1f..338d3e65e 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-url.config.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-url.config.ts @@ -13,4 +13,8 @@ export function getUrl(handle: string, page: Page): string { return `${challengesPath}?createdBy=${handle}&perPage=${page.size}&page=${page.number}&selfService=true` } +export function updateUrl(workId: string): string { + return `${challengesPath}/${workId}` +} + const challengesPath: string = `${EnvironmentConfig.API.V5}/challenges` diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts index 36260f650..687775207 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts @@ -1,12 +1,12 @@ -import { Page, xhrDeleteAsync, xhrGetAsync, xhrPostAsync } from '../../../../../../lib' +import { Page, xhrDeleteAsync, xhrGetAsync, xhrPatchAsync, xhrPostAsync } from '../../../../../../lib' -import { Challenge, ChallengeCreate } from './challenge.model' +import { Challenge, ChallengeCreateBody } from './challenge.model' import { WorkStatusFilter } from './work-status-filter.enum' import { WorkStatus } from './work-status.enum' -import { createUrl, deleteUrl, getUrl } from './work-url.config' +import { createUrl, deleteUrl, getUrl, updateUrl } from './work-url.config' import { Work } from './work.model' -export async function createAsync(body: ChallengeCreate): Promise { +export async function createAsync(body: ChallengeCreateBody): Promise { return xhrPostAsync(createUrl(), JSON.stringify(body)) } @@ -28,3 +28,7 @@ export function getFilteredByStatus(work: ReadonlyArray, workStatusFilter? && (workStatusFilter === WorkStatusFilter.all || w.status === WorkStatus[workStatusFilter as keyof typeof WorkStatus])) } + +export async function patchAsync(body: ChallengeCreate): Promise { + return xhrPatchAsync(updateUrl(body.id), JSON.stringify(body)) +} diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts index ec4dfd356..78557202e 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts @@ -5,7 +5,8 @@ import { WorkByStatus } from './work-by-status.model' import { workFactoryBuildCreateBody, workFactoryCreate } from './work-factory' import { Challenge, - ChallengeCreate, + ChallengeCreateBody, + ChallengeUpdateBody, Work, workGetPricesConfig, WorkPricesType, @@ -19,7 +20,7 @@ import { } from './work-store' export async function createAsync(type: WorkType): Promise { - const body: ChallengeCreate = workFactoryBuildCreateBody(type) + const body: ChallengeCreateBody = workFactoryBuildCreateBody(type) return workStoreCreateAsync(body) } From 6c39b2fc4703efb7212d1ca658309e7a804435f1 Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Mon, 11 Jul 2022 15:45:51 -0600 Subject: [PATCH 02/11] PROD-2437 #comment Created method to build the update challenge body. Modified price and timeline models. #time 6h --- .../work-factory/work.factory.ts | 114 +++++++++++++++++- .../work-store/challenge.model.ts | 14 +-- .../work-functions/work-store/index.ts | 2 + .../work-store/work-price.model.ts | 20 ++- .../work-store/work-prices.config.ts | 89 ++++++++++---- .../work-store/work-prize.model.ts | 8 ++ .../work-store/work-timeline-phase.model.ts | 4 + .../work-store/work-timeline.model.ts | 5 +- .../work-store/work-timelines.config.ts | 2 +- .../work-store/work-type.model.ts | 4 +- .../work-functions/work-store/work.store.ts | 6 +- .../work-functions/work.functions.ts | 1 + src/constants/index.js | 8 +- src/utils/index.js | 6 +- 14 files changed, 223 insertions(+), 60 deletions(-) create mode 100644 src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prize.model.ts create mode 100644 src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timeline-phase.model.ts diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts index ad54e4466..1a884cc16 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts @@ -1,3 +1,4 @@ +import _ from 'lodash' import moment from 'moment' import { @@ -7,14 +8,18 @@ import { ChallengeMetadataName, ChallengePhase, ChallengePhaseName, + ChallengeUpdateBody, Work, WorkPrice, + WorkPriceBreakdown, WorkPricesType, + WorkPrize, WorkProgress, WorkProgressStep, WorkStatus, WorkType, WorkTypeCategory, + WorkTypeConfig, } from '../work-store' import { ChallengeStatus } from './challenge-status.enum' @@ -64,7 +69,7 @@ export function create(challenge: Challenge, workPrices: WorkPricesType): Work { } } -export function buildCreateBody(type: string): ChallengeCreateBody { +export function buildCreateBody(type: WorkType): ChallengeCreateBody { // TODO: once configs are merged, use type and config to fetch the necessary fields return { description: 'Information not provided', @@ -86,6 +91,54 @@ export function buildCreateBody(type: string): ChallengeCreateBody { } } +export function buildUpdateBody(workTypeConfig: WorkTypeConfig, intakeForm: any): ChallengeUpdateBody { + const type: WorkType = workTypeConfig.type + const form: any = JSON.parse(intakeForm)?.form + + const data: ReadonlyArray = mapFormData( + type, + form?.basicInfo + ) + + const intakeMetadata: Array = [ + { + name: ChallengeMetadataName.intakeForm, + value: intakeForm, + }, + ] + + // This is the Markdown string that gets displayed in Work Manager app and others + const templateString: Array = [] + + data.forEach((formDetail) => { + if (Object.keys(formDetail).length <= 0) { return } + + const formattedValue: string = formatFormDataOption(formDetail.value) + + intakeMetadata.push({ + name: ChallengeMetadataName[formDetail.key as keyof typeof ChallengeMetadataName], + value: formattedValue, + }) + templateString.push(`### ${formDetail.title}\n\n${formattedValue}\n\n`) + }) + + if (getTypeCategory(type) === WorkTypeCategory.data) { + templateString.push( + '## Final Submission Guidelines \n\n Please submit a zip file containing your analysis/solution.' + ) + } + + const body: ChallengeUpdateBody = { + description: templateString.join(''), + metadata: intakeMetadata, + name: form?.basicInfo?.projectTitle?.value, + phases: workTypeConfig.timeline, + prizeSets: getPrizes(workTypeConfig), + } + + return body +} + export function getStatus(challenge: Challenge): WorkStatus { switch (challenge.status) { @@ -241,6 +294,17 @@ function buildFormDataProblem(formData: any): ReadonlyArray { ] } +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) } @@ -278,6 +342,27 @@ function findPhase(challenge: Challenge, phases: Array): ChallengePhase return phase } +function formatFormDataOption(detail: Array | { [key: string]: any }): string { + const noInfoProvidedText: string = '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) { @@ -309,6 +394,33 @@ function getDescription(challenge: Challenge, type: WorkType): string | undefine } } +function getPrizes(workTypeConfig: WorkTypeConfig): Array { + const priceConfig: WorkPriceBreakdown = + workTypeConfig.usePromo && workTypeConfig.promo + ? workTypeConfig.promo + : workTypeConfig.base + + return [ + { + description: 'Challenge Prizes', + prizes: priceConfig.placementDistributions.map((percentage) => ({ + type: 'USD', + value: _.round(percentage * priceConfig.price), + })), + type: 'placement', + }, + { + description: 'Reviewer Payment', + prizes: + priceConfig.reviewerDistributions.map((percentage) => ({ + type: 'USD', + value: _.round(percentage * priceConfig.price), + })), + type: 'reviewer', + }, + ] +} + function getProgress(challenge: Challenge, workStatus: WorkStatus): WorkProgress { const steps: ReadonlyArray = [ diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts index ae93fc7e1..9323892f1 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts @@ -1,6 +1,7 @@ import { ChallengeMetadata } from './challenge-metadata.model' import { ChallengePhase } from './challenge-phase' -import { WorkTimeline } from './work-timeline.model' +import { WorkPrize } from './work-prize.model' +import { WorkTimelinePhase } from './work-timeline-phase.model' export interface Challenge { created: string @@ -27,16 +28,11 @@ export interface ChallengeCreateBody { typeId: string, } -interface PrizeSetsType { - type: 'USD', - value: number, -} - export interface ChallengeUpdateBody { description: string, - id: string, // Maria do we include id here? + id?: string, // Maria do we include id here? metadata: Array name: string, - phases: ReadonlyArray - prizeSets: Array + phases: ReadonlyArray + prizeSets: Array } diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/index.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/index.ts index f87aec9c1..c091c26b2 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/index.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/index.ts @@ -14,6 +14,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' @@ -31,4 +32,5 @@ export { deleteAsync as workStoreDeleteAsync, getAsync as workStoreGetAsync, getFilteredByStatus as workStoreGetFilteredByStatus, + updateAsync as workStoreUpdateAsync, } from './work.store' diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-price.model.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-price.model.ts index fe280c99f..23513afad 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-price.model.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-price.model.ts @@ -1,17 +1,13 @@ export interface WorkPrice { - base: number, + base: WorkPriceBreakdown, getPrice: (price: WorkPrice, pageCount?: number, deviceCount?: number) => number, - payments?: { - base?: { - prizes: ReadonlyArray, - reviewers: ReadonlyArray, - }, - promo?: { - prizes: ReadonlyArray, - reviewers: ReadonlyArray, - }, - }, perPage?: number, - promo?: number, + promo?: WorkPriceBreakdown, usePromo?: boolean, } + +export interface WorkPriceBreakdown { + placementDistributions: ReadonlyArray, + price: number, + reviewerDistributions: ReadonlyArray, +} diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prices.config.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prices.config.ts index 86d244784..801626aa1 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prices.config.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prices.config.ts @@ -1,66 +1,109 @@ import { WorkPrice } from './work-price.model' import { WorkPricesType } from './work-prices-type.model' +import { WorkPrize } from './work-prize.model' import { WorkType } from './work-type.enum' export const WorkPricesConfig: WorkPricesType = { // TODO: get real values for bug hunt [WorkType.bugHunt]: { - base: 2, + base: { + placementDistributions: [0.2609, 0.2174, 0.1304], + price: 2, + reviewerDistributions: [0.0435, 0.0435], + }, getPrice: getPriceDefault, - payments: { - base: { - prizes: [0.2609, 0.2174, 0.1304], - reviewers: [0.0435, 0.0435], - }, - promo: { - prizes: [0.348, 0.29, 0.174], - reviewers: [0.058, 0.058], - }, + promo: { + placementDistributions: [0.348, 0.29, 0.174], + price: 1, + reviewerDistributions: [0.058, 0.058], }, - promo: 1, usePromo: true, }, [WorkType.data]: { - base: 799, + base: { + placementDistributions: [0.4, 0.3333, 0.1333], + price: 799, + reviewerDistributions: [0.0667, 0.0667], + }, getPrice: getPriceDefault, - promo: 599, + promo: { + placementDistributions: [0.4, 0.3333, 0.1333], + price: 599, + reviewerDistributions: [0.0667, 0.0667], + }, usePromo: true, }, [WorkType.design]: { - base: 499, + base: { + placementDistributions: [0.4, 0.3333, 0.1333], + price: 499, + reviewerDistributions: [0.0667, 0.0667], + }, getPrice: getPriceDefault, perPage: 99, - promo: 299, + promo: { + placementDistributions: [0.4, 0.3333, 0.1333], + price: 299, + reviewerDistributions: [0.0667, 0.0667], + }, usePromo: false, }, [WorkType.designLegacy]: { - base: 398, + base: { + placementDistributions: [0.5, 0.2, 0.1], + price: 398, + reviewerDistributions: [0.1, 0.1], + }, getPrice: getPriceDesignLegacy, perPage: 99, - promo: 100, + promo: { + placementDistributions: [0.5, 0.2, 0.1], + price: 100, + reviewerDistributions: [0.1, 0.1], + }, usePromo: true, }, [WorkType.findData]: { - base: 399, + base: { + placementDistributions: [0.2609, 0.2174, 0.1304], + price: 399, + reviewerDistributions: [0.0435, 0.0435], + }, getPrice: getPriceDefault, - promo: 299, + promo: { + placementDistributions: [0.348, 0.29, 0.174], + price: 299, + reviewerDistributions: [0.058, 0.058], + }, usePromo: true, }, [WorkType.problem]: { - base: 999, + base: { + placementDistributions: [0.375, 0.3125, 0.125], + price: 999, + reviewerDistributions: [0.0625, 0.0625], + }, getPrice: getPriceDefault, - promo: 799, + promo: { + placementDistributions: [0.375, 0.3125, 0.125], + price: 799, + reviewerDistributions: [0.0625, 0.0625], + }, usePromo: true, }, [WorkType.unknown]: { - base: 0, + base: { + placementDistributions: [], + price: 0, + reviewerDistributions: [], + }, getPrice: () => 0, usePromo: false, }, } function getPriceDefault(price: WorkPrice): number { - return price.usePromo && price.promo ? price.promo : price.base + return price.usePromo && price.promo?.price ? price.promo?.price : price.base.price } function getPriceDesignLegacy(price: WorkPrice, pageCount?: number, deviceCount?: number): number { diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prize.model.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prize.model.ts new file mode 100644 index 000000000..4a8c966c6 --- /dev/null +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prize.model.ts @@ -0,0 +1,8 @@ +export interface WorkPrize { + description: string, + prizes: Array<{ + type: string, + value: number, + }>, + type: string, +} diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timeline-phase.model.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timeline-phase.model.ts new file mode 100644 index 000000000..c0c4b5ccf --- /dev/null +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timeline-phase.model.ts @@ -0,0 +1,4 @@ +export interface WorkTimelinePhase { + duration: number, + phaseId: string, +} diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timeline.model.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timeline.model.ts index ec993036f..06552d227 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timeline.model.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timeline.model.ts @@ -1,4 +1,5 @@ +import { WorkTimelinePhase } from './work-timeline-phase.model' + export interface WorkTimeline { - duration: number, - phaseId: string, + [workType: string]: ReadonlyArray } diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timelines.config.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timelines.config.ts index d3e2174ce..f0346047d 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timelines.config.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-timelines.config.ts @@ -1,7 +1,7 @@ import { WorkTimeline } from './work-timeline.model' import { WorkType } from './work-type.enum' -export const WorkTimelines: { [workType: string]: ReadonlyArray } = { +export const WorkTimelines: WorkTimeline = { // TODO: Determine actual timeline for Bug Hunt [WorkType.bugHunt]: [ { diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-type.model.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-type.model.ts index 5b3322929..b4fa6a54e 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-type.model.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-type.model.ts @@ -1,5 +1,5 @@ import { WorkPrice } from './work-price.model' -import { WorkTimeline } from './work-timeline.model' +import { WorkTimelinePhase } from './work-timeline-phase.model' import { WorkType } from './work-type.enum' export interface WorkTypeConfig extends WorkPrice { @@ -13,7 +13,7 @@ export interface WorkTypeConfig extends WorkPrice { shortDescription: string, startRoute: string, subtitle: string, - timeline: ReadonlyArray + timeline: ReadonlyArray timelineTemplateId: string, title: string, trackId: string, diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts index 687775207..774ff222c 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts @@ -1,6 +1,6 @@ import { Page, xhrDeleteAsync, xhrGetAsync, xhrPatchAsync, xhrPostAsync } from '../../../../../../lib' -import { Challenge, ChallengeCreateBody } from './challenge.model' +import { Challenge, ChallengeCreateBody, ChallengeUpdateBody } from './challenge.model' import { WorkStatusFilter } from './work-status-filter.enum' import { WorkStatus } from './work-status.enum' import { createUrl, deleteUrl, getUrl, updateUrl } from './work-url.config' @@ -29,6 +29,6 @@ export function getFilteredByStatus(work: ReadonlyArray, workStatusFilter? || w.status === WorkStatus[workStatusFilter as keyof typeof WorkStatus])) } -export async function patchAsync(body: ChallengeCreate): Promise { - return xhrPatchAsync(updateUrl(body.id), JSON.stringify(body)) +export async function updateAsync(body: ChallengeUpdateBody): Promise { + return xhrPatchAsync(updateUrl(body?.id || ''), JSON.stringify(body)) } diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts index 78557202e..8d7475b96 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts @@ -16,6 +16,7 @@ import { workStoreDeleteAsync, workStoreGetAsync, workStoreGetFilteredByStatus, + workStoreUpdateAsync, WorkType, } from './work-store' diff --git a/src/constants/index.js b/src/constants/index.js index 97771a646..ace1bbee2 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -276,7 +276,7 @@ export const webWorkTypes = [ subTitle: "​​Create a beautiful custom visual design for your website. Specify the scope and device types, your vision, and receive up to 5 modern designs.", price: workPriceDesignLegacy.getPrice(workPriceDesignLegacy), - stickerPrice: workPriceDesignLegacy.base, + stickerPrice: workPriceDesignLegacy.base.price, featured: false, startRoute: "/self-service/work/new/website-design-legacy/basic-info", basePath: "website-design-legacy", @@ -355,7 +355,7 @@ export const webWorkTypes = [ description: "We accumulate data every day in the course of life and business, yet rarely have the time to give it a closer look. Get multiple fresh, expert perspectives to identify the patterns and relationships in your data. They might just be the key to your next 'Aha' moment.", price: workPriceData.getPrice(workPriceData), - stickerPrice: workPriceData.base, + stickerPrice: workPriceData.base.price, duration: `${dataExplorationConfigs.DEFAULT_DURATION} Days`, featured: true, startRoute: "/self-service/work/new/data-exploration/basic-info", @@ -411,7 +411,7 @@ export const webWorkTypes = [ description: "Problem Statement & Data Advisory is for those asking themselves: How can I apply data science to this idea or goal? How will I interpret solutions, and how will that help me take action? What data do I need?", price: workPriceProblem.getPrice(workPriceProblem), - stickerPrice: workPriceProblem.base, + stickerPrice: workPriceProblem.base.price, duration: `${dataAdvisoryConfigs.DEFAULT_DURATION} Days`, featured: true, startRoute: "/self-service/work/new/data-advisory/basic-info", @@ -473,7 +473,7 @@ export const webWorkTypes = [ description: "Sometimes data is the only thing standing between you and something great. Tell us what you're solving for, and let our experts find the data to get you started now.", price: workPriceFindData.getPrice(workPriceFindData), - stickerPrice: workPriceFindData.base, + stickerPrice: workPriceFindData.base.price, duration: `${findMeDataConfigs.DEFAULT_DURATION} Days`, featured: true, startRoute: "/self-service/work/new/find-me-data/basic-info", diff --git a/src/utils/index.js b/src/utils/index.js index ede6415db..757644a5d 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -57,7 +57,7 @@ export function getDataAdvisoryPriceAndTimelineEstimate() { const total = workPriceProblem.getPrice(workPriceProblem); return { total, - stickerPrice: workPriceProblem.base, + stickerPrice: workPriceProblem.base.price, submissionDuration: 3, totalDuration: dataAdvisoryConfigs.DEFAULT_DURATION, prizeSets: [ @@ -89,7 +89,7 @@ export function getDataExplorationPriceAndTimelineEstimate() { const total = workPriceData.getPrice(workPriceData) return { total, - stickerPrice: workPriceData.base, + stickerPrice: workPriceData.base.price, submissionDuration: 3, totalDuration: dataExplorationConfigs.DEFAULT_DURATION, prizeSets: [ @@ -162,7 +162,7 @@ export function getFindMeDataPriceAndTimelineEstimate() { return { total, - stickerPrice: workPriceFindData.base, + stickerPrice: workPriceFindData.base.price, submissionDuration: 3, totalDuration: findMeDataConfigs.DEFAULT_DURATION, prizeSets: [ From 314b2658cd47a2698b3d77ee1f30b6fe0766f796 Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Wed, 13 Jul 2022 11:35:02 -0700 Subject: [PATCH 03/11] PROD-2437 #comment Finalizing the updateAsync method #time 1h --- .../work-lib/work-provider/work-functions/index.ts | 1 + .../work-provider/work-functions/work-factory/index.ts | 1 + .../work-store/challenge-metadata-name.enum.ts | 3 +++ .../work-functions/work-store/work.store.ts | 4 ++-- .../work-provider/work-functions/work.functions.ts | 10 ++++++++-- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/index.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/index.ts index 41f45dc56..b6ff5b0a8 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/index.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/index.ts @@ -26,4 +26,5 @@ export { getGroupedByStatus as workGetGroupedByStatus, getPricesConfig as workGetPricesConfig, getStatusFilter as workGetStatusFilter, + updateAsync as workUpdateAsync, } from './work.functions' diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/index.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/index.ts index 035bbfc35..6aa17fe5c 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/index.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/index.ts @@ -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' diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts index adf7fbde8..3cf69425e 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts @@ -1,8 +1,11 @@ export enum ChallengeMetadataName { + data = 'data', deviceCount = 'basicInfo.numberOfDevices', description = 'websitePurpose.description', feedback = 'customerFeedback', + goal = 'goal', goals = 'goals', intakeForm = 'intake-form', pageCount = 'basicInfo.numberOfPages', + projectTitle = 'projectTitle', } diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts index 774ff222c..59105553d 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts @@ -29,6 +29,6 @@ export function getFilteredByStatus(work: ReadonlyArray, workStatusFilter? || w.status === WorkStatus[workStatusFilter as keyof typeof WorkStatus])) } -export async function updateAsync(body: ChallengeUpdateBody): Promise { - return xhrPatchAsync(updateUrl(body?.id || ''), JSON.stringify(body)) +export async function updateAsync(workId: string, body: ChallengeUpdateBody): Promise { + return xhrPatchAsync(updateUrl(workId), JSON.stringify(body)) } diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts index 936b5a68a..e54a19e28 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts @@ -2,7 +2,7 @@ import { Page, UserProfile } from '../../../../../lib' import { WorkByStatus } from './work-by-status.model' -import { workFactoryBuildCreateBody, workFactoryCreate } from './work-factory' +import { workFactoryBuildCreateBody, workFactoryBuildUpdateBody, workFactoryCreate } from './work-factory' import { Challenge, ChallengeCreateBody, @@ -23,7 +23,7 @@ import { } from './work-store' export async function createAsync(type: WorkType): Promise { - const workConfig: WorkTypeConfig = WorkTypeConfigs[WorkType.bugHunt] + const workConfig: WorkTypeConfig = WorkTypeConfigs[type] const body: ChallengeCreateBody = workFactoryBuildCreateBody(workConfig) return workStoreCreateAsync(body) } @@ -95,6 +95,12 @@ export function getStatusFilter(filterKey?: string): WorkStatusFilter | undefine return !workStatusFilter ? undefined : WorkStatusFilter[workStatusFilter] } +export async function updateAsync(type: WorkType, workId: string, intakeForm: any): Promise { + const workConfig: WorkTypeConfig = WorkTypeConfigs[type] + const body: ChallengeUpdateBody = workFactoryBuildUpdateBody(workConfig, intakeForm) + return workStoreUpdateAsync(workId, body) +} + async function getPageAsync(handle: string, page: Page): Promise> { // get the response From 3d244f07383d42a2ae8ef67e400d9c4bad401ac6 Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Mon, 18 Jul 2022 15:03:56 -0700 Subject: [PATCH 04/11] PROD-2437 #comment Bug Hunt form gets saved when clicking on Complete and Pay button #time 4h --- .../work-factory/work.factory.ts | 57 ++++++++++++++++--- .../challenge-metadata-name.enum.ts | 5 ++ .../work-store/challenge.model.ts | 17 +++--- .../work-functions/work-store/work.store.ts | 4 +- .../work-functions/work.functions.ts | 6 +- .../bug-hunt/BugHuntIntakeForm.tsx | 13 +++-- .../bug-hunt/bug-hunt.form.config.tsx | 12 ++-- 7 files changed, 84 insertions(+), 30 deletions(-) diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts index 865efb914..b2c661709 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts @@ -101,25 +101,29 @@ export function buildCreateBody(workTypeConfig: WorkTypeConfig): ChallengeCreate } } -export function buildUpdateBody(workTypeConfig: WorkTypeConfig, intakeForm: any): ChallengeUpdateBody { +export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Challenge, formData: any): ChallengeUpdateBody { + const type: WorkType = workTypeConfig.type - const form: any = JSON.parse(intakeForm)?.form - const data: ReadonlyArray = mapFormData( - type, - form?.basicInfo - ) + const intakeForm: ChallengeMetadata | undefined = findMetadata(challenge, ChallengeMetadataName.intakeForm) || undefined + const form: IntakeForm = !!intakeForm?.value ? JSON.parse(intakeForm.value)?.form : {} + form.basicInfo = formData const intakeMetadata: Array = [ { name: ChallengeMetadataName.intakeForm, - value: intakeForm, + value: JSON.stringify({ form }), }, ] // This is the Markdown string that gets displayed in Work Manager app and others const templateString: Array = [] + const data: ReadonlyArray = mapFormData( + type, + formData + ) + data.forEach((formDetail) => { if (Object.keys(formDetail).length <= 0) { return } @@ -140,8 +144,9 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, intakeForm: any) const body: ChallengeUpdateBody = { description: templateString.join(''), + id: challenge.id, metadata: intakeMetadata, - name: form?.basicInfo?.projectTitle?.value, + name: formData.projectTitle, phases: workTypeConfig.timeline, prizeSets: getPrizes(workTypeConfig), } @@ -186,10 +191,46 @@ export function mapFormData(type: string, formData: any): ReadonlyArray { + return [ + { + key: 'projectTitle', + title: 'Project Title', + value: formData.projectTitle, + }, + { + key: 'websiteURL', + title: 'Website URL', + value: formData.websiteURL, + }, + { + key: 'goals', + title: 'Bug Hunt Goals', + value: formData.goals, + }, + { + key: 'featuresToTest', + title: 'Features to Test', + value: formData.featuresToTest, + }, + { + key: 'deliveryType', + title: 'Bug Delivery', + value: `${formData.deliveryType}${formData.repositoryLink ? ': ' + formData.repositoryLink : ''}`, + }, + { + key: 'additionalInformation', + title: 'Additional Information', + value: formData.additionalInformation, + }, + ] +} function buildFormDataData(formData: any): ReadonlyArray { return [ diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts index 3cf69425e..69568fa40 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts @@ -1,11 +1,16 @@ export enum ChallengeMetadataName { + additionalInformation = 'additionalInformation', data = 'data', + deliveryType = 'deliveryType', deviceCount = 'basicInfo.numberOfDevices', description = 'websitePurpose.description', + featuresToTest = 'featuresToTest', feedback = 'customerFeedback', goal = 'goal', goals = 'goals', intakeForm = 'intake-form', pageCount = 'basicInfo.numberOfPages', projectTitle = 'projectTitle', + repositoryLink = 'repositoryLink', + websiteURL = 'websiteURL', } diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts index 3f839903a..8a8d12ceb 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge.model.ts @@ -9,12 +9,13 @@ export interface Challenge { description: string discussions?: Array<{ [key: string]: string }> id: string - legacy?: { [key: string]: any }, + legacy?: { [key: string]: any } metadata: Array name: string numOfRegistrants?: number numOfSubmissions?: number phases: Array + prizeSets?: Array status: string tags: Array timelineTemplateId?: string @@ -36,11 +37,13 @@ export type ChallengeCreateBody = Pick< 'typeId' > -export interface ChallengeUpdateBody { - description: string, - id?: string, // Maria do we include id here? - metadata: Array - name: string, +export type ChallengeUpdateBody = Pick< + Challenge, + 'description' | + 'id' | + 'metadata' | + 'name' | + 'prizeSets' +> & { phases: ReadonlyArray - prizeSets: Array } diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts index 59105553d..487d2e9a8 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work.store.ts @@ -29,6 +29,6 @@ export function getFilteredByStatus(work: ReadonlyArray, workStatusFilter? || w.status === WorkStatus[workStatusFilter as keyof typeof WorkStatus])) } -export async function updateAsync(workId: string, body: ChallengeUpdateBody): Promise { - return xhrPatchAsync(updateUrl(workId), JSON.stringify(body)) +export async function updateAsync(body: ChallengeUpdateBody): Promise { + return xhrPatchAsync(updateUrl(body.id), JSON.stringify(body)) } diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts index e54a19e28..501deabcf 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work.functions.ts @@ -95,10 +95,10 @@ export function getStatusFilter(filterKey?: string): WorkStatusFilter | undefine return !workStatusFilter ? undefined : WorkStatusFilter[workStatusFilter] } -export async function updateAsync(type: WorkType, workId: string, intakeForm: any): Promise { +export async function updateAsync(type: WorkType, challenge: Challenge, intakeForm: any): Promise { const workConfig: WorkTypeConfig = WorkTypeConfigs[type] - const body: ChallengeUpdateBody = workFactoryBuildUpdateBody(workConfig, intakeForm) - return workStoreUpdateAsync(workId, body) + const body: ChallengeUpdateBody = workFactoryBuildUpdateBody(workConfig, challenge, intakeForm) + return workStoreUpdateAsync(body) } async function getPageAsync(handle: string, page: Page): Promise> { diff --git a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx index 201c5848a..faa634fc0 100644 --- a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx +++ b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx @@ -1,7 +1,7 @@ import React, { Dispatch, SetStateAction, useEffect, useState } from 'react' import { Form, FormDefinition, formGetInputModel, FormInputModel, IconOutline } from '../../../../../lib' -import { Challenge, workCreateAsync, WorkType } from '../../../work-lib' +import { Challenge, workCreateAsync, WorkType, workUpdateAsync } from '../../../work-lib' import { bugHuntConfig } from '../../../work-lib/work-provider/work-functions/work-store/work-type.config' import { WorkServicePrice } from '../../../work-service-price' import { WorkTypeBanner } from '../../../work-type-banner' @@ -39,11 +39,11 @@ const BugHuntIntakeForm: React.FC = ({ workId }) => { const deliveryType: string = formGetInputModel(inputs, FormInputNames.deliveryType).value as string const repositoryLink: string = formGetInputModel(inputs, FormInputNames.repositoryLink).value as string const websiteURL: string = formGetInputModel(inputs, FormInputNames.websiteURL).value as string - const bugHuntGoals: string = formGetInputModel(inputs, FormInputNames.goals).value as string + const goals: string = formGetInputModel(inputs, FormInputNames.goals).value as string return { - bugHuntGoals, deliveryType, featuresToTest, + goals, projectTitle, repositoryLink, websiteURL, @@ -51,7 +51,12 @@ const BugHuntIntakeForm: React.FC = ({ workId }) => { } const onSave: (val: any) => Promise = (val: any) => { - return new Promise(() => { }).then(() => { }) + if (!challenge) { return Promise.resolve() } + + return workUpdateAsync(WorkType.bugHunt, challenge, val) + .then(() => { + console.log('Updated successfully') + }) } return ( diff --git a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/bug-hunt.form.config.tsx b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/bug-hunt.form.config.tsx index 6939f5172..38a93a053 100644 --- a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/bug-hunt.form.config.tsx +++ b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/bug-hunt.form.config.tsx @@ -6,7 +6,7 @@ export enum FormInputNames { additionalInformation = 'additionalInformation', title = 'projectTitle', features = 'featuresToTest', - goals = 'bugHuntGoals', + goals = 'goals', deliveryType = 'deliveryType', repositoryLink = 'repositoryLink', websiteURL = 'websiteURL', @@ -18,13 +18,13 @@ export const BugHuntFormConfig: FormDefinition = { { buttonStyle: 'secondary', label: 'Save for later', - onClick: () => {}, + onClick: () => { }, type: 'button', }, { buttonStyle: 'primary', label: 'Complete and pay', - onClick: () => {}, + onClick: () => { }, type: 'submit', }, ], @@ -32,7 +32,7 @@ export const BugHuntFormConfig: FormDefinition = { { buttonStyle: 'icon', icon: BackIcon, - onClick: () => {}, + onClick: () => { }, type: 'button', }, ], @@ -120,12 +120,12 @@ export const BugHuntFormConfig: FormDefinition = { { checked: false, children: } />, - id: 'github', + id: 'GitHub', }, { checked: false, children: } />, - id: 'gitlab', + id: 'GitLab', }, ], type: 'radio', From 225b76dba715eb49ff16ea56ffce9a09db22d6ce Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Mon, 18 Jul 2022 16:19:27 -0700 Subject: [PATCH 05/11] PROD-2437 #comment Added an enum for Challenge Metadata Titles #time 45m --- .../work-provider/work-functions/index.ts | 1 + .../work-factory/work.factory.ts | 30 ++++++++------ .../challenge-metadata-title.enum.ts | 8 ++++ .../work-functions/work-store/index.ts | 1 + .../bug-hunt/BugHuntIntakeForm.tsx | 16 ++++---- .../bug-hunt/bug-hunt.form.config.tsx | 39 +++++++------------ 6 files changed, 51 insertions(+), 44 deletions(-) create mode 100644 src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-title.enum.ts diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/index.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/index.ts index b6ff5b0a8..1f03d9da4 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/index.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/index.ts @@ -2,6 +2,7 @@ export * from './work-factory' export { type Challenge, ChallengeMetadataName, + ChallengeMetadataTitle, type Work, workPriceData, workPriceDesign, diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts index b2c661709..388cff579 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts @@ -6,6 +6,7 @@ import { ChallengeCreateBody, ChallengeMetadata, ChallengeMetadataName, + ChallengeMetadataTitle, ChallengePhase, ChallengePhaseName, ChallengeUpdateBody, @@ -109,6 +110,11 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall 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 + const intakeMetadata: Array = [ { name: ChallengeMetadataName.intakeForm, @@ -200,33 +206,33 @@ export function mapFormData(type: string, formData: any): ReadonlyArray { return [ { - key: 'projectTitle', - title: 'Project Title', + key: ChallengeMetadataName.projectTitle, + title: ChallengeMetadataTitle.projectTitle, value: formData.projectTitle, }, { - key: 'websiteURL', - title: 'Website URL', + key: ChallengeMetadataName.websiteURL, + title: ChallengeMetadataTitle.websiteURL, value: formData.websiteURL, }, { - key: 'goals', - title: 'Bug Hunt Goals', + key: ChallengeMetadataName.goals, + title: ChallengeMetadataTitle.bugHuntGoals, value: formData.goals, }, { - key: 'featuresToTest', - title: 'Features to Test', + key: ChallengeMetadataName.featuresToTest, + title: ChallengeMetadataTitle.featuresToTest, value: formData.featuresToTest, }, { - key: 'deliveryType', - title: 'Bug Delivery', + key: ChallengeMetadataName.deliveryType, + title: ChallengeMetadataTitle.bugDeliveryType, value: `${formData.deliveryType}${formData.repositoryLink ? ': ' + formData.repositoryLink : ''}`, }, { - key: 'additionalInformation', - title: 'Additional Information', + key: ChallengeMetadataName.additionalInformation, + title: ChallengeMetadataTitle.additionalInformation, value: formData.additionalInformation, }, ] diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-title.enum.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-title.enum.ts new file mode 100644 index 000000000..ff293deb9 --- /dev/null +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-title.enum.ts @@ -0,0 +1,8 @@ +export enum ChallengeMetadataTitle { + additionalInformation = 'Additional Information', + bugDeliveryType = 'Bug Delivery', + bugHuntGoals = 'Bug Hunt Goals', + featuresToTest = 'Features to Test', + projectTitle = 'Project Title', + websiteURL = 'Website URL', +} diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/index.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/index.ts index c091c26b2..9975ce3bd 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/index.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/index.ts @@ -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' diff --git a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx index faa634fc0..52b1dba72 100644 --- a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx +++ b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx @@ -1,12 +1,12 @@ import React, { Dispatch, SetStateAction, useEffect, useState } from 'react' import { Form, FormDefinition, formGetInputModel, FormInputModel, IconOutline } from '../../../../../lib' -import { Challenge, workCreateAsync, WorkType, workUpdateAsync } from '../../../work-lib' +import { Challenge, ChallengeMetadataName, workCreateAsync, WorkType, workUpdateAsync } from '../../../work-lib' import { bugHuntConfig } from '../../../work-lib/work-provider/work-functions/work-store/work-type.config' import { WorkServicePrice } from '../../../work-service-price' import { WorkTypeBanner } from '../../../work-type-banner' -import { BugHuntFormConfig, FormInputNames } from './bug-hunt.form.config' +import { BugHuntFormConfig } from './bug-hunt.form.config' import styles from './BugHunt.module.scss' interface BugHuntIntakeFormProps { @@ -34,12 +34,12 @@ const BugHuntIntakeForm: React.FC = ({ workId }) => { }, [workId]) const requestGenerator: (inputs: ReadonlyArray) => void = (inputs) => { - const projectTitle: string = formGetInputModel(inputs, FormInputNames.title).value as string - const featuresToTest: string = formGetInputModel(inputs, FormInputNames.features).value as string - const deliveryType: string = formGetInputModel(inputs, FormInputNames.deliveryType).value as string - const repositoryLink: string = formGetInputModel(inputs, FormInputNames.repositoryLink).value as string - const websiteURL: string = formGetInputModel(inputs, FormInputNames.websiteURL).value as string - const goals: string = formGetInputModel(inputs, FormInputNames.goals).value as string + const projectTitle: string = formGetInputModel(inputs, ChallengeMetadataName.projectTitle).value as string + const featuresToTest: string = formGetInputModel(inputs, ChallengeMetadataName.featuresToTest).value as string + const deliveryType: string = formGetInputModel(inputs, ChallengeMetadataName.deliveryType).value as string + const repositoryLink: string = formGetInputModel(inputs, ChallengeMetadataName.repositoryLink).value as string + const websiteURL: string = formGetInputModel(inputs, ChallengeMetadataName.websiteURL).value as string + const goals: string = formGetInputModel(inputs, ChallengeMetadataName.goals).value as string return { deliveryType, featuresToTest, diff --git a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/bug-hunt.form.config.tsx b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/bug-hunt.form.config.tsx index 38a93a053..095997648 100644 --- a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/bug-hunt.form.config.tsx +++ b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/bug-hunt.form.config.tsx @@ -1,16 +1,7 @@ import { ReactComponent as BackIcon } from '../../../../../../src/assets/images/icon-back-arrow.svg' import { FormDefinition, GithubIcon, GitlabIcon, RadioButton, validatorRequired } from '../../../../../lib' - -export enum FormInputNames { - additionalInformation = 'additionalInformation', - title = 'projectTitle', - features = 'featuresToTest', - goals = 'goals', - deliveryType = 'deliveryType', - repositoryLink = 'repositoryLink', - websiteURL = 'websiteURL', -} +import { ChallengeMetadataName, ChallengeMetadataTitle } from '../../../work-lib' export const BugHuntFormConfig: FormDefinition = { buttons: { @@ -43,7 +34,7 @@ export const BugHuntFormConfig: FormDefinition = { { hideInlineErrors: true, label: 'Project title', - name: FormInputNames.title, + name: ChallengeMetadataName.projectTitle, placeholder: 'Enter a descriptive title', type: 'text', validators: [ @@ -54,14 +45,14 @@ export const BugHuntFormConfig: FormDefinition = { }, ], instructions: 'Enter a title for your website bug hunt project.', - title: 'Project Title', + title: ChallengeMetadataTitle.projectTitle, }, { inputs: [ { hideInlineErrors: true, label: 'Website URL', - name: FormInputNames.websiteURL, + name: ChallengeMetadataName.websiteURL, placeholder: 'Enter a descriptive title', type: 'text', validators: [ @@ -72,14 +63,14 @@ export const BugHuntFormConfig: FormDefinition = { }, ], instructions: 'Enter a title for your website bug hunt project.', - title: 'Website URL', + title: ChallengeMetadataTitle.websiteURL, }, { inputs: [ { hideInlineErrors: true, - label: 'Project title', - name: FormInputNames.goals, + label: 'Bug hunt goals', + name: ChallengeMetadataName.goals, placeholder: 'Describe your goal', type: 'textarea', validators: [ @@ -93,13 +84,13 @@ export const BugHuntFormConfig: FormDefinition = { Do you have any specific goals for your website bug hunt?
For example: find bugs in my online shopping experience `, - title: 'Bug Hunt Goals', + title: ChallengeMetadataTitle.bugHuntGoals, }, { inputs: [ { label: 'Features to test (optional)', - name: FormInputNames.features, + name: ChallengeMetadataName.featuresToTest, placeholder: 'List the sepcific features', type: 'textarea', }, @@ -108,13 +99,13 @@ export const BugHuntFormConfig: FormDefinition = { Are there specific features we should focus on testing?
For example: [An example not used above] `, - title: 'Features to test', + title: ChallengeMetadataTitle.featuresToTest, }, { inputs: [ { hideInlineErrors: true, - name: FormInputNames.deliveryType, + name: ChallengeMetadataName.deliveryType, notTabbable: false, options: [ { @@ -137,19 +128,19 @@ export const BugHuntFormConfig: FormDefinition = { }, { label: 'Repository Link (Optional)', - name: FormInputNames.repositoryLink, + name: ChallengeMetadataName.repositoryLink, placeholder: 'www.example-share-link.com', type: 'text', }, ], instructions: 'How do you want your bugs delivered?', - title: 'Bug Delivery', + title: ChallengeMetadataTitle.bugDeliveryType, }, { inputs: [ { label: 'Additional information (optional)', - name: FormInputNames.additionalInformation, + name: ChallengeMetadataName.additionalInformation, placeholder: '[Suggestion text]', type: 'textarea', }, @@ -157,7 +148,7 @@ export const BugHuntFormConfig: FormDefinition = { instructions: ` Is there anything else we should know about testing your website? `, - title: 'Additional Information', + title: ChallengeMetadataTitle.additionalInformation, }, ], } From 27c7e9fefd4f95988f27f67d2f5b082f44e912bc Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Mon, 18 Jul 2022 16:47:41 -0700 Subject: [PATCH 06/11] PROD-2437 #comment Lint and code cleanup #time 10m --- .../work-functions/work-store/challenge-metadata-name.enum.ts | 2 -- .../work-functions/work-store/work-prices.config.ts | 4 ++-- .../intake-forms/bug-hunt/BugHuntIntakeForm.tsx | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts index 69568fa40..e7a006af9 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts @@ -1,12 +1,10 @@ export enum ChallengeMetadataName { additionalInformation = 'additionalInformation', - data = 'data', deliveryType = 'deliveryType', deviceCount = 'basicInfo.numberOfDevices', description = 'websitePurpose.description', featuresToTest = 'featuresToTest', feedback = 'customerFeedback', - goal = 'goal', goals = 'goals', intakeForm = 'intake-form', pageCount = 'basicInfo.numberOfPages', diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prices.config.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prices.config.ts index 801626aa1..76fbc3a6e 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prices.config.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-prices.config.ts @@ -8,13 +8,13 @@ export const WorkPricesConfig: WorkPricesType = { [WorkType.bugHunt]: { base: { placementDistributions: [0.2609, 0.2174, 0.1304], - price: 2, + price: 1599, reviewerDistributions: [0.0435, 0.0435], }, getPrice: getPriceDefault, promo: { placementDistributions: [0.348, 0.29, 0.174], - price: 1, + price: 1599, reviewerDistributions: [0.058, 0.058], }, usePromo: true, diff --git a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx index 52b1dba72..76557ea71 100644 --- a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx +++ b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/BugHuntIntakeForm.tsx @@ -55,7 +55,7 @@ const BugHuntIntakeForm: React.FC = ({ workId }) => { return workUpdateAsync(WorkType.bugHunt, challenge, val) .then(() => { - console.log('Updated successfully') + // TODO: Navigate to a different page (review, back to dashboard, etc) }) } From 2253597184dbd9656158a06645ebd3d21baef2ef Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Tue, 19 Jul 2022 08:48:36 -0700 Subject: [PATCH 07/11] PROD-2437 #comment Removed Lodash round in favor of Math.round #time 5m --- .../work-functions/work-factory/work.factory.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts index 388cff579..e76f66c85 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts @@ -1,4 +1,3 @@ -import _ from 'lodash' import moment from 'moment' import { @@ -462,7 +461,7 @@ function getPrizes(workTypeConfig: WorkTypeConfig): Array { description: 'Challenge Prizes', prizes: priceConfig.placementDistributions.map((percentage) => ({ type: 'USD', - value: _.round(percentage * priceConfig.price), + value: Math.round(percentage * priceConfig.price), })), type: 'placement', }, @@ -471,7 +470,7 @@ function getPrizes(workTypeConfig: WorkTypeConfig): Array { prizes: priceConfig.reviewerDistributions.map((percentage) => ({ type: 'USD', - value: _.round(percentage * priceConfig.price), + value: Math.round(percentage * priceConfig.price), })), type: 'reviewer', }, From 798fbefdf5e5db22908a4a9126050d367f31976e Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Tue, 19 Jul 2022 13:21:33 -0700 Subject: [PATCH 08/11] PROD-2437 #comment Added comments for clarification and save formData to metadata before formatting #time 30m --- .../work-factory/work.factory.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts index e76f66c85..602cc9cda 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts @@ -114,6 +114,7 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall // 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 = [ { name: ChallengeMetadataName.intakeForm, @@ -121,7 +122,15 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall }, ] - // This is the Markdown string that gets displayed in Work Manager app and others + 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 = [] const data: ReadonlyArray = mapFormData( @@ -133,11 +142,6 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall if (Object.keys(formDetail).length <= 0) { return } const formattedValue: string = formatFormDataOption(formDetail.value) - - intakeMetadata.push({ - name: ChallengeMetadataName[formDetail.key as keyof typeof ChallengeMetadataName], - value: formattedValue, - }) templateString.push(`### ${formDetail.title}\n\n${formattedValue}\n\n`) }) @@ -146,6 +150,7 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall '## Final Submission Guidelines \n\n Please submit a zip file containing your analysis/solution.' ) } + // ---- End Build Markdown string ---- // const body: ChallengeUpdateBody = { description: templateString.join(''), @@ -350,6 +355,11 @@ function buildFormDataProblem(formData: any): ReadonlyArray { ] } +/** + * 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 || From 9ee0585551b137462b1fab120d8c2c46ffd804a3 Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Tue, 19 Jul 2022 13:31:25 -0700 Subject: [PATCH 09/11] Added packageType to ChallangeMetadata --- .../work-functions/work-store/challenge-metadata-name.enum.ts | 1 + .../work-functions/work-store/challenge-metadata-title.enum.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts index e7a006af9..f997cd19b 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-name.enum.ts @@ -8,6 +8,7 @@ export enum ChallengeMetadataName { goals = 'goals', intakeForm = 'intake-form', pageCount = 'basicInfo.numberOfPages', + packageType = 'packageType', projectTitle = 'projectTitle', repositoryLink = 'repositoryLink', websiteURL = 'websiteURL', diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-title.enum.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-title.enum.ts index ff293deb9..8f8491ef7 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-title.enum.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/challenge-metadata-title.enum.ts @@ -2,6 +2,7 @@ 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', From 2b20e5b9eee9b572db8591819150fb449994894a Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Tue, 19 Jul 2022 16:07:31 -0700 Subject: [PATCH 10/11] PROD-2437 #comment Added a json file to hold string constants #time 30m --- src-ts/tools/work/work-lib/index.ts | 1 + src-ts/tools/work/work-lib/work-constants/index.ts | 1 + .../tools/work/work-lib/work-constants/strings.json | 5 +++++ .../work-functions/work-factory/work.factory.ts | 11 ++++++----- 4 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 src-ts/tools/work/work-lib/work-constants/index.ts create mode 100644 src-ts/tools/work/work-lib/work-constants/strings.json diff --git a/src-ts/tools/work/work-lib/index.ts b/src-ts/tools/work/work-lib/index.ts index a03454165..f0cda9934 100644 --- a/src-ts/tools/work/work-lib/index.ts +++ b/src-ts/tools/work/work-lib/index.ts @@ -1,3 +1,4 @@ +export * from './work-constants' export * from './work-images' export * from './work-pdfs' export * from './work-provider' diff --git a/src-ts/tools/work/work-lib/work-constants/index.ts b/src-ts/tools/work/work-lib/work-constants/index.ts new file mode 100644 index 000000000..05f2a6a0c --- /dev/null +++ b/src-ts/tools/work/work-lib/work-constants/index.ts @@ -0,0 +1 @@ +export { default as WorkStrings } from './strings.json' diff --git a/src-ts/tools/work/work-lib/work-constants/strings.json b/src-ts/tools/work/work-lib/work-constants/strings.json new file mode 100644 index 000000000..40ac3840d --- /dev/null +++ b/src-ts/tools/work/work-lib/work-constants/strings.json @@ -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" +} diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts index 5e2c703e7..64f5c0864 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts @@ -1,5 +1,6 @@ import moment from 'moment' +import { WorkStrings } from '../../../work-constants' import { Challenge, ChallengeCreateBody, @@ -78,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', @@ -125,7 +126,7 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall Object.keys(formData).forEach((key) => { intakeMetadata.push({ name: ChallengeMetadataName[key as keyof typeof ChallengeMetadataName], - value: formData[key], + value: formData[key] || '', }) }) // ---- End Build Metadata ---- // @@ -147,7 +148,7 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall if (getTypeCategory(type) === WorkTypeCategory.data) { templateString.push( - '## Final Submission Guidelines \n\n Please submit a zip file containing your analysis/solution.' + WorkStrings.MARKDOWN_SUBMISSION_GUIDELINES ) } // ---- End Build Markdown string ---- // @@ -160,7 +161,7 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall phases: workTypeConfig.timeline, prizeSets: getPrizes(workTypeConfig), } - + console.log(body) return body } @@ -414,7 +415,7 @@ function findPhase(challenge: Challenge, phases: Array): ChallengePhase } function formatFormDataOption(detail: Array | { [key: string]: any }): string { - const noInfoProvidedText: string = 'Not provided' + const noInfoProvidedText: string = WorkStrings.NOT_PROVIDED const isEmpty: boolean = checkFormDataOptionEmpty(detail) if (isEmpty) { From 473f89eca6e675945d511d50df6dcd41862e6691 Mon Sep 17 00:00:00 2001 From: Maria Mattlin Date: Tue, 19 Jul 2022 16:12:50 -0700 Subject: [PATCH 11/11] cleanup --- .../work-provider/work-functions/work-factory/work.factory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts index 64f5c0864..f5d9e370a 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-factory/work.factory.ts @@ -161,7 +161,7 @@ export function buildUpdateBody(workTypeConfig: WorkTypeConfig, challenge: Chall phases: workTypeConfig.timeline, prizeSets: getPrizes(workTypeConfig), } - console.log(body) + return body }