diff --git a/src-ts/.eslintrc.js b/src-ts/.eslintrc.js index 0514d2944..ce2af1929 100644 --- a/src-ts/.eslintrc.js +++ b/src-ts/.eslintrc.js @@ -54,16 +54,6 @@ module.exports = { '@typescript-eslint/no-inferrable-types': 'off', '@typescript-eslint/no-shadow': 'error', '@typescript-eslint/no-unused-vars': 'error', - '@typescript-eslint/strict-boolean-expressions': [ - 'error', - { - allowAny: true, - allowNullableBoolean: true, - allowNullableObject: true, - allowNullableNumber: true, - allowNullableString: true - } - ], '@typescript-eslint/typedef': [ 'error', { diff --git a/src-ts/lib/form/Form.tsx b/src-ts/lib/form/Form.tsx index 07de469e4..c5b954062 100644 --- a/src-ts/lib/form/Form.tsx +++ b/src-ts/lib/form/Form.tsx @@ -95,7 +95,7 @@ const Form: (props: }, []) function checkIfFormIsValid(formInputFields: Array): void { - setFormInvalid(formInputFields.filter(item => !!item.error).length > 0) + setFormInvalid(formInputFields.some(item => !!item.error)) } function onBlur(event: FocusEvent): void { diff --git a/src-ts/lib/form/form-groups/form-card-set/FormCardSet.module.scss b/src-ts/lib/form/form-groups/form-card-set/FormCardSet.module.scss index f9cf29bd2..706d32606 100644 --- a/src-ts/lib/form/form-groups/form-card-set/FormCardSet.module.scss +++ b/src-ts/lib/form/form-groups/form-card-set/FormCardSet.module.scss @@ -17,9 +17,10 @@ flex: 1 1 0; margin-right: $space-xl; border-radius: $space-xs; - padding: $space-lg 0; + padding: $space-xxl 0px 0px; background-color: $black-5; position: relative; + height: calc($space-xl * 30); .popular-card { display: flex; @@ -61,19 +62,17 @@ align-items: center; h3 { - margin: $space-lg; + margin: $space-xxl $space-lg; font-weight: 500; - font-size: $space-mx; + font-size: calc($space-mx + $space-xs); line-height: $space-mx; - margin-top: $space-xxl; } &.feature { visibility: hidden; h3 { - margin: $space-lg; - margin-top: $space-xxl; + margin: $space-xxl $space-lg; font-size: $space-xxxxl; } } @@ -82,7 +81,7 @@ h3 { font-size: $space-xxxxl; line-height: $space-xxxxl; - margin-top: $space-md; + margin-top: $space-sm; margin-bottom: $space-xxl; } } @@ -97,10 +96,18 @@ } .card-section { - margin: $space-lg 0; + margin: $space-mx 0; .row { height: auto; + + &:last-child { + .row-divider { + &:last-child { + display: block; + } + } + } } .row-divider { @@ -108,13 +115,17 @@ border-bottom: $border solid $black-10; width: auto; margin: 0; + + &:last-child { + display: none; + } } .card-row { display: flex; padding: $space-md; align-items: center; - min-height: calc($space-lg + $space-mx); + min-height: calc($space-lg + $space-mx - 2px); position: relative; .card-row-col { @@ -148,14 +159,24 @@ } .info-icon { + @include icon-lg; margin-left: $space-sm; color: $turq-160; cursor: pointer; outline: none; } + + .check-icon { + @include icon-xxl; + @include ltemd { + @include icon-lg; + } + } } } &.mobile { + margin-bottom: 0; + margin-top: $space-xxl; .feature-name { width: 100%; } @@ -164,13 +185,14 @@ } } &.feature { - margin: calc($space-lg - 0.2px) 0; + margin-top: $space-mx; } } &.feature { background-color: $tc-white; margin-right: 0; + flex-grow: 0.9; .card-row-col:nth-child(2) { display: none; @@ -188,9 +210,12 @@ } svg.card-row-icon { - height: 14px; - width: 14px; + @include icon-xxl; display: inline; margin-right: 6px; + + @include ltemd { + @include icon-lg; + } } } diff --git a/src-ts/lib/form/form-groups/form-card-set/FormCardSet.tsx b/src-ts/lib/form/form-groups/form-card-set/FormCardSet.tsx index 4f87d118b..d1973d80e 100644 --- a/src-ts/lib/form/form-groups/form-card-set/FormCardSet.tsx +++ b/src-ts/lib/form/form-groups/form-card-set/FormCardSet.tsx @@ -56,39 +56,82 @@ const FormCardSet: React.FC = (props: FormCardSetProps) => { const formattedPrice: string | undefined = textFormatMoneyLocaleString(card.price) const selected: boolean = props.value === card.id return ( -
+
{card.mostPopular &&
MOST POPULAR
} -
-
{card.title}
+
+
{card.title}

{formattedPrice}

{getButton(card, selected)}
- {card.sections.map((section, sectionIndex: number) => ( -
- {section.rows.map((row, rowIndex: number) => ( + {card.sections.map(section => ( +
+ {section.rows.map(row => (
-
+
{((isMobile) || (index === 0)) && ( - + {row.icon && iconFromName(row.icon)} {row.label - ? {row.label} + ? ( + + {row.label} + + ) : {row.text}} {row.infoIcon && ( } + trigger={( + + )} /> )} )} {row.valueIcon - ? + ? : {row.text}}
+
))}
diff --git a/src-ts/tools/work/work-detail-details/work-detail-details-pane/WorkDetailDetailsPane.tsx b/src-ts/tools/work/work-detail-details/work-detail-details-pane/WorkDetailDetailsPane.tsx index d3e4968ef..2f5ee8384 100644 --- a/src-ts/tools/work/work-detail-details/work-detail-details-pane/WorkDetailDetailsPane.tsx +++ b/src-ts/tools/work/work-detail-details/work-detail-details-pane/WorkDetailDetailsPane.tsx @@ -1,12 +1,15 @@ +/* eslint-disable react/destructuring-assignment */ import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react' import { Link } from 'react-router-dom' import _ from 'lodash' import cn from 'classnames' -import { currencyFormat } from '../../../../../src/utils' -import { ArrowIcon, FormCard, LoadingSpinner } from '../../../../lib' -import { ChallengeMetadataName, workFactoryMapFormData } from '../../work-lib' -import BugHuntPricingConfig from '../../work-self-service/intake-forms/bug-hunt/bug-hunt.form.pricing-config' +import { ArrowIcon, LoadingSpinner } from '../../../../lib' +import { + ChallengeMetadataName, + workFactoryMapFormData, + workGetSelectedPackageFormatted, +} from '../../work-lib' import styles from './WorkDetailDetailsPane.module.scss' @@ -24,12 +27,21 @@ interface FormDetail { value: any } -const WorkDetailDetailsPane: FC = ({ collapsible, defaultOpen = false, formData, isReviewPage = false, redirectUrl = '' }: WorkDetailDetailsPaneProps) => { - const [details, setDetails]: [ReadonlyArray, Dispatch>>] = useState>([]) - const [isOpen, setOpen]: [boolean, Dispatch>] = useState(collapsible ? defaultOpen : true) +const WorkDetailDetailsPane: FC = ({ + collapsible, + defaultOpen = false, + formData, + isReviewPage = false, + redirectUrl = '', +}: WorkDetailDetailsPaneProps) => { + + const [details, setDetails]: [ReadonlyArray, Dispatch>>] + = useState>([]) + const [isOpen, setOpen]: [boolean, Dispatch>] + = useState(collapsible ? defaultOpen : true) useEffect(() => { - if (!!formData?.basicInfo) { + if (!!formData.basicInfo) { setDetails(workFactoryMapFormData(formData?.workType?.selectedWorkType, formData.basicInfo)) } }, [formData]) @@ -69,7 +81,7 @@ const WorkDetailDetailsPane: FC = ({ collapsible, de

{detail.title}

{detail.key === ChallengeMetadataName.packageType ? ( -

{getSelectedPackageFormatted(detail.value)}

+

{workGetSelectedPackageFormatted(detail.value)}

) : (

{formatOption(detail.value)}

)} @@ -88,7 +100,7 @@ function formatOption(detail: Array | {} | string): string | Array (
{val}
)) + .map(val => (
{val}
)) } if (_.isObject(detail)) { @@ -115,15 +127,4 @@ function checkIsEmpty(detail: Array | {} | string): boolean { .filter(val => val?.trim().length > 0).length === 0) } -const getSelectedPackageFormatted: (packageId: string) => string = packageId => { - const currentPackage: FormCard | undefined = BugHuntPricingConfig.find(pricingConfig => pricingConfig.id === packageId) - if (currentPackage) { - const deviceType: string = currentPackage.sections?.[0]?.rows?.[3]?.text || '' - const noOfTesters: string = `${currentPackage.sections?.[0]?.rows?.[2]?.text || 0} testers` - return `${currentPackage.title} - ${currencyFormat(currentPackage.price)} - ${deviceType} - ${noOfTesters}` - } - - return packageId -} - export default WorkDetailDetailsPane 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 1a474fd7e..2831d36a6 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 @@ -32,6 +32,7 @@ export { getByWorkIdAsync as workGetByWorkIdAsync, getGroupedByStatus as workGetGroupedByStatus, getPricesConfig as workGetPricesConfig, + getSelectedPackageFormatted as workGetSelectedPackageFormatted, getStatusFilter as workGetStatusFilter, updateAsync as workUpdateAsync, } from './work.functions' 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 2ec0526ba..ff0b2128e 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,7 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import moment from 'moment' +import { workGetSelectedPackageFormatted } from '..' import { WorkConfigConstants, WorkStrings } from '../../../work-constants' import { ActivateWorkRequest, @@ -129,12 +131,17 @@ export function buildCustomerPaymentRequest( } } -export function buildUpdateRequest(workTypeConfig: WorkTypeConfig, challenge: Challenge, formData: any): UpdateWorkRequest { +export function buildUpdateRequest( + workTypeConfig: WorkTypeConfig, + challenge: Challenge, + formData: any, +): UpdateWorkRequest { const type: WorkType = workTypeConfig.type const priceConfig: WorkPrice = workTypeConfig.priceConfig - const intakeForm: ChallengeMetadata | undefined = findMetadata(challenge, ChallengeMetadataName.intakeForm) || undefined + const intakeForm: ChallengeMetadata | undefined + = findMetadata(challenge, ChallengeMetadataName.intakeForm) || undefined const form: IntakeForm = !!intakeForm?.value ? JSON.parse(intakeForm.value)?.form : {} form.basicInfo = formData @@ -181,7 +188,8 @@ export function buildUpdateRequest(workTypeConfig: WorkTypeConfig, challenge: Ch // then update the duration for that phase to the correct value const timeline: Array = workTypeConfig.timeline.map(phase => { if (workTypeConfig.submissionPhaseDuration && phase.phaseId === WorkConfigConstants.PHASE_ID_SUBMISSION) { - phase.duration = workTypeConfig.submissionPhaseDuration[formData[ChallengeMetadataName.packageType] as PricePackageName] || 0 + const packageName: PricePackageName = formData[ChallengeMetadataName.packageType] as PricePackageName + phase.duration = workTypeConfig.submissionPhaseDuration[packageName] || 0 } return phase @@ -237,9 +245,11 @@ export function getStatus(challenge: Challenge): WorkStatus { case ChallengeStatus.draft: return WorkStatus.active - case ChallengeStatus.completed: - const customerFeedback: ChallengeMetadata | undefined = findMetadata(challenge, ChallengeMetadataName.feedback) + case ChallengeStatus.completed: { + const customerFeedback: ChallengeMetadata | undefined + = findMetadata(challenge, ChallengeMetadataName.feedback) return !customerFeedback ? WorkStatus.ready : WorkStatus.done + } case ChallengeStatus.cancelled: case ChallengeStatus.cancelledPaymentFailed: @@ -304,7 +314,7 @@ function buildFormDataBugHunt(formData: any): ReadonlyArray { { key: ChallengeMetadataName.packageType, title: ChallengeMetadataTitle.bugHuntPackage, - value: formData.packageType, + value: workGetSelectedPackageFormatted(formData.packageType), }, ] } @@ -449,8 +459,9 @@ function findOpenPhase(challenge: Challenge): ChallengePhase | undefined { // sort the phases descending by start date const sortedPhases: Array = challenge.phases .sort((a, b) => new Date(b.actualStartDate) - .getTime() - new Date(a.actualStartDate) - .getTime()) + .getTime() + - new Date(a.actualStartDate) + .getTime()) const now: Date = new Date() // if we have an open phase, just use that @@ -518,7 +529,8 @@ function getCost(challenge: Challenge, priceConfig: WorkPrice, type: WorkType): case WorkType.bugHunt: { // get the selected package from the intake form - const intakeFormBH: ChallengeMetadata | undefined = findMetadata(challenge, ChallengeMetadataName.intakeForm) + const intakeFormBH: ChallengeMetadata | undefined + = findMetadata(challenge, ChallengeMetadataName.intakeForm) const formBH: IntakeForm = !!intakeFormBH?.value ? JSON.parse(intakeFormBH.value)?.form : undefined return priceConfig.getPrice(priceConfig, formBH?.basicInfo?.packageType) } @@ -538,6 +550,9 @@ function getDescription(challenge: Challenge, type: WorkType): string | undefine case WorkType.design: case WorkType.designLegacy: return findMetadata(challenge, ChallengeMetadataName.description)?.value + + default: + return undefined } } @@ -596,7 +611,7 @@ function getProgressStepActive(challenge: Challenge, workStatus: WorkStatus): nu switch (challenge.status) { case ChallengeStatus.active: - case ChallengeStatus.approved: + case ChallengeStatus.approved: { const openPhase: ChallengePhase | undefined = findOpenPhase(challenge) // if we don't have an open phase, just return submitted @@ -612,6 +627,7 @@ function getProgressStepActive(challenge: Challenge, workStatus: WorkStatus): nu default: return 2 } + } case ChallengeStatus.completed: return workStatus === WorkStatus.ready ? 3 : 4 @@ -698,7 +714,7 @@ function getType(challenge: Challenge): WorkType { // parse the form const form: { form: IntakeForm } = JSON.parse(intakeForm.value) const workTypeKey: (keyof typeof WorkType) | undefined = Object.entries(WorkType) - .find(([key, value]) => value === form.form?.workType?.selectedWorkType) + .find(([, value]) => value === form.form?.workType?.selectedWorkType) ?.[0] as keyof typeof WorkType const output: WorkType = !!workTypeKey ? WorkType[workTypeKey] : WorkType.unknown diff --git a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-type.config.ts b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-type.config.ts index f330d6fe2..dbd1cb510 100644 --- a/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-type.config.ts +++ b/src-ts/tools/work/work-lib/work-provider/work-functions/work-store/work-type.config.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-len */ import { bugHuntTileImg } from '../../../work-images' import { ChallengeTag } from './challenge-tag.enum' @@ -12,9 +13,7 @@ export const WorkTypeConfigs: { [workType: string]: WorkTypeConfig } = { [WorkType.bugHunt]: { about: 'Expert QA testers will verify that all of the pages on your website are working correctly from the end-user perspective. The testing will stress functional issues, but also includes security issues, user interface issues, usability issues and more. Test on desktop, tablet, and mobile, to uncover bugs before your customers encounter them.', bgImage: bugHuntTileImg, - deliverablesDescription: `You will receive thorough testing of your website, and at the conclusion will be provided - a detailed report of bugs which have steps to reproduce, screenshots / videos if applicable, - details of the bug, and severity of the issue.`, + deliverablesDescription: 'You will receive thorough testing of your website by QA experts, and an actionable report extremely quickly. Our experts will deliver a detailed list of bugs found, with steps to reproduce, including screenshots, videos, and the information you need to fix them.', description: 'Execute thorough bug hunts exceptionally fast. Receive a detailed list of bugs and instructions on exactly how to fix them.', duration: { advanced: 6, 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 77c1fd122..5111589cd 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 @@ -1,6 +1,10 @@ import { PaymentMethodResult, Stripe, StripeCardNumberElement } from '@stripe/stripe-js' -import { GenericDataObject, Page, UserProfile } from '../../../../../lib' +import { FormCard, GenericDataObject, Page, textFormatMoneyLocaleString, UserProfile } from '../../../../../lib' +// this has to be imported directly from the file bc the order of operations +// that items are loaded in the barrel file this config is empty and throws an error +// eslint-disable-next-line ordered-imports/ordered-imports +import BugHuntPricingConfig from '../../../work-self-service/intake-forms/bug-hunt/bug-hunt.form.pricing-config' import { WorkByStatus } from './work-by-status.model' import { @@ -171,3 +175,16 @@ async function getPageAsync(handle: string, page: Page): Promise> { .map(challenge => workFactoryCreate(challenge, workGetPricesConfig())) .filter(work => work.status !== WorkStatus.deleted && work.type !== WorkType.unknown) } + +export function getSelectedPackageFormatted(packageId: string): string { + const currentPackage: FormCard | undefined + = BugHuntPricingConfig.find(pricingConfig => pricingConfig.id === packageId) + if (currentPackage) { + const deviceType: string = currentPackage.sections?.[0]?.rows?.[3]?.text || '' + const noOfTesters: string = `${currentPackage.sections?.[0]?.rows?.[2]?.text || 0} testers` + const price: string | undefined = textFormatMoneyLocaleString(currentPackage.price) + return `${currentPackage.title} - ${price} - ${deviceType} - ${noOfTesters}` + } + + return packageId +} 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 758e40723..50759068e 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,5 +1,6 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { NavigateFunction, useNavigate, useParams } from 'react-router-dom' -import React, { Dispatch, SetStateAction, useContext, useEffect, useState } from 'react' +import React, { Dispatch, SetStateAction, useCallback, useContext, useEffect, useState } from 'react' import { Form, @@ -49,6 +50,8 @@ const BugHuntIntakeForm: React.FC = () => { const [loading, setLoading]: [boolean, Dispatch>] = useState(false) const [saveSuccess, setSaveSuccess]: [boolean, Dispatch>] = useState(false) + const defaultPackage: PricePackageName = 'standard' + BugHuntFormConfig.buttons.primaryGroup[0].onClick = () => { setAction('save') } BugHuntFormConfig.buttons.primaryGroup[0].hidden = !isLoggedIn BugHuntFormConfig.buttons.primaryGroup[1].onClick = () => { setAction('submit') } @@ -66,19 +69,21 @@ const BugHuntIntakeForm: React.FC = () => { BugHuntFormConfig.buttons.primaryGroup[1].label = 'Complete and pay' } - const [challenge, setChallenge]: [Challenge | undefined, Dispatch>] = useState() + const [challenge, setChallenge]: [Challenge | undefined, Dispatch>] + = useState() const [formDef]: [FormDefinition, Dispatch>] = useState({ ...BugHuntFormConfig }) const [formValues, setFormValues]: [any, Dispatch] = useState({ currentStep: 'basicInfo', - [ChallengeMetadataName.packageType]: 'standard', + [ChallengeMetadataName.packageType]: defaultPackage, }) const [selectedPackage, setSelectedPackage]: [PricePackageName, Dispatch>] = useState(formValues?.packageType) - const [disableSaveForLater, setDisableSaveForLater]: [boolean, Dispatch>] = useState(true) + const [disableSaveForLater, setDisableSaveForLater]: [boolean, Dispatch>] + = useState(true) useEffect(() => { @@ -111,44 +116,64 @@ const BugHuntIntakeForm: React.FC = () => { if (formData?.packageType) { setSelectedPackage(formData.packageType) + } else { + setFormValues({ + ...formValues, + [ChallengeMetadataName.packageType]: defaultPackage, + }) } } setLoading(true) getAndSetWork() .finally(() => setLoading(false)) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ isLoggedIn, workId, ]) + const handleSaveSuccess: () => void = () => { + if (action === 'save') { + navigate(`${dashboardRoute}/draft`) + } else if (action === 'submit') { + const nextUrl: string = `${WorkIntakeFormRoutes[WorkType.bugHunt].review}/${workId || challenge?.id}` + navigate(nextUrl) + } + } + useEffect(() => { if (!loading && saveSuccess) { handleSaveSuccess() } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [loading, saveSuccess]) - const requestGenerator: (inputs: ReadonlyArray) => void = inputs => { - 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 - const packageType: string = formGetInputModel(inputs, ChallengeMetadataName.packageType).value as string - return { - deliveryType, - featuresToTest, - goals, - packageType, - projectTitle, - repositoryLink, - websiteURL, - } - } + const requestGenerator: (inputs: ReadonlyArray) => any + = useCallback((inputs: ReadonlyArray) => { + 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 + const packageType: string = formGetInputModel(inputs, ChallengeMetadataName.packageType).value as string + return { + deliveryType, + featuresToTest, + goals, + packageType, + projectTitle, + repositoryLink, + websiteURL, + } + }, []) const onChange: (inputs: ReadonlyArray) => void = inputs => { - const packageType: PricePackageName = formGetInputModel(inputs, ChallengeMetadataName.packageType).value as PricePackageName + const packageType: PricePackageName + = formGetInputModel(inputs, ChallengeMetadataName.packageType).value as PricePackageName if (packageType !== selectedPackage) { setSelectedPackage(packageType) @@ -159,6 +184,18 @@ const BugHuntIntakeForm: React.FC = () => { setDisableSaveForLater(!title?.trim()) } + const goToLoginStep: (formData: any) => void = (formData: any) => { + if (localStorage) { + localStorage.setItem('challengeInProgress', JSON.stringify(formData)) + localStorage.setItem('challengeInProgressType', WorkType.bugHunt) + } + + const returnUrl: string + = encodeURIComponent(`${window.location.origin}${WorkIntakeFormRoutes[WorkType.bugHunt].saveAfterLogin}`) + const loginPromptUrl: string = `${WorkIntakeFormRoutes[WorkType.bugHunt].loginPrompt}/${returnUrl}` + navigate(loginPromptUrl) + } + const onSave: (val: any) => Promise = val => { if (!isLoggedIn) { goToLoginStep(val) @@ -178,45 +215,28 @@ const BugHuntIntakeForm: React.FC = () => { .finally(() => setLoading(false)) } - const handleSaveSuccess: () => void = () => { - if (action === 'save') { - navigate(`${dashboardRoute}/draft`) - } else if (action === 'submit') { - const nextUrl: string = `${WorkIntakeFormRoutes[WorkType.bugHunt].review}/${workId || challenge?.id}` - navigate(nextUrl) - } - } - const onSaveSuccess: () => void = () => { setSaveSuccess(true) } - const goToLoginStep: (formData: any) => void = (formData: any) => { - if (localStorage) { - localStorage.setItem('challengeInProgress', JSON.stringify(formData)) - localStorage.setItem('challengeInProgressType', WorkType.bugHunt) - } - - const returnUrl: string = encodeURIComponent(`${window.location.origin}${WorkIntakeFormRoutes[WorkType.bugHunt].saveAfterLogin}`) - const loginPromptUrl: string = `${WorkIntakeFormRoutes[WorkType.bugHunt].loginPrompt}/${returnUrl}` - navigate(loginPromptUrl) - } - /** * This function is used to decide whether SAVE FOR LATER button should be enabled or not * @param isPrimaryGroup whether its a primary group or not * @param index the index of the button * @returns true or false depending on whether its SAVE FOR LATER */ - function shouldDisableButton(isPrimaryGroup: boolean, index: number): boolean { - // SAVE FOR LATER belongs to primary group and its index is 0, we are interested only for that particular case - // else return false which means not disabled from this function - if (isPrimaryGroup && index === 0) { - return disableSaveForLater - } + const shouldDisableButton: (isPrimaryGroup: boolean, index: number) => boolean + = useCallback((isPrimaryGroup: boolean, index: number) => { + + // SAVE FOR LATER belongs to primary group and its index is 0, + // we are interested only for that particular case + // else return false which means not disabled from this function + if (isPrimaryGroup && index === 0) { + return disableSaveForLater + } - return false - } + return false + }, [disableSaveForLater]) return ( <> diff --git a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/index.tsx b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/index.tsx index 5d269208e..fa139e46e 100644 --- a/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/index.tsx +++ b/src-ts/tools/work/work-self-service/intake-forms/bug-hunt/index.tsx @@ -1,3 +1,4 @@ +export { default as BugHuntPricingConfig } from './bug-hunt.form.pricing-config' export * from './BugHuntIntakeForm' export { default as BugHuntIntakeForm } from './BugHuntIntakeForm' export * from './deliverables-info-card'