@@ -17,14 +17,13 @@ import {
1717 PricingPlanDataProps ,
1818 corProductIdentifier ,
1919 eorProductIdentifier ,
20- useDiscardEmploymentMutation ,
20+ $TSFixMe ,
2121} from '@remoteoss/remote-flows' ;
2222import {
2323 Card ,
2424 Tabs ,
2525 TabsTrigger ,
2626 TabsList ,
27- cn ,
2827} from '@remoteoss/remote-flows/internals' ;
2928import Flag from 'react-flagpack' ;
3029import React , { useState } from 'react' ;
@@ -36,32 +35,75 @@ import { EngagingContractorsModal } from './components/PricingPlanModals';
3635import './css/main.css' ;
3736import './css/contractor-onboarding.css' ;
3837
38+ const groupOptionsBySeparator = ( options : $TSFixMe [ ] ) => {
39+ const groups : $TSFixMe [ ] [ ] = [ ] ;
40+ let currentGroup : $TSFixMe [ ] = [ ] ;
41+
42+ options ?. forEach ( ( option ) => {
43+ if ( option . meta ?. groupSeparator ?. show && currentGroup . length > 0 ) {
44+ groups . push ( currentGroup ) ;
45+ currentGroup = [ option ] ;
46+ } else {
47+ currentGroup . push ( option ) ;
48+ }
49+ } ) ;
50+
51+ if ( currentGroup . length > 0 ) {
52+ groups . push ( currentGroup ) ;
53+ }
54+
55+ return groups ;
56+ } ;
57+
3958const PricingPlanCards = ( {
4059 field,
4160 fieldData,
4261 fieldState,
4362 showPrice = true ,
4463} : PricingPlanComponentProps & { showPrice ?: boolean } ) => {
4564 const hasError = ! ! fieldState . error ;
46- const items = fieldData . options ?. length ;
65+
66+ // Group options by separator
67+ const groups = groupOptionsBySeparator ( fieldData . options ) ;
4768
4869 return (
49- < div className = { cn ( 'grid gap-2' , `grid-cols-${ items ?? 3 } ` ) } >
50- { fieldData . options ?. map ( ( option ) => (
51- < PricingPlanCard
52- key = { option . value }
53- title = { option . label }
54- description = { option . description }
55- features = { option . meta ?. features as string [ ] }
56- price = { option . meta ?. price }
57- value = { option . value }
58- selected = { field . value === option . value }
59- disabled = { option . disabled }
60- showPrice = { showPrice }
61- onSelect = { ( value : string ) => {
62- field . onChange ( value ) ;
63- } }
64- />
70+ < div className = 'flex flex-col gap-6' >
71+ { groups . map ( ( group , groupIndex ) => (
72+ < React . Fragment key = { groupIndex } >
73+ { /* Render separator if first option in group has one */ }
74+ { group [ 0 ] ?. meta ?. groupSeparator ?. show && (
75+ < div className = 'mt-4 mb-2' >
76+ < h2 className = 'text-xl font-bold text-[#22863a]' >
77+ Other available hiring plans
78+ </ h2 >
79+ < p className = 'text-sm text-[#71717A] mt-1' >
80+ Based on the responses in your questionnaire, this individual
81+ may also be eligible for our Employer of Record plan. For any
82+ questions, please contact help@remote.com
83+ </ p >
84+ </ div >
85+ ) }
86+
87+ { /* Render all cards in this group in a single grid */ }
88+ < div className = 'grid gap-2 grid-cols-3' >
89+ { group . map ( ( option ) => (
90+ < PricingPlanCard
91+ key = { option . value }
92+ title = { option . label }
93+ description = { option . description }
94+ features = { option . meta ?. features as string [ ] }
95+ price = { option . meta ?. price }
96+ value = { option . value }
97+ selected = { field . value === option . value }
98+ disabled = { option . disabled }
99+ showPrice = { showPrice }
100+ onSelect = { ( value : string ) => {
101+ field . onChange ( value ) ;
102+ } }
103+ />
104+ ) ) }
105+ </ div >
106+ </ React . Fragment >
65107 ) ) }
66108 { hasError && < p className = 'error-message' > { fieldState . error ?. message } </ p > }
67109 </ div >
@@ -103,7 +145,6 @@ const MultiStepForm = ({
103145 SelectCountryStep,
104146 PricingPlanStep,
105147 EligibilityQuestionnaireStep,
106- ChooseAlternativePlanStep,
107148 ContractDetailsStep,
108149 ContractPreviewStep,
109150 ContractReviewButton,
@@ -115,8 +156,6 @@ const MultiStepForm = ({
115156 apiError : '' ,
116157 fieldErrors : [ ] ,
117158 } ) ;
118- const { mutateAsync : discardEmployment } = useDiscardEmploymentMutation ( ) ;
119-
120159 switch ( contractorOnboardingBag . stepState . currentStep . name ) {
121160 case 'select_country' :
122161 return (
@@ -263,9 +302,12 @@ const MultiStepForm = ({
263302 ) ;
264303 } ,
265304 } }
266- onSubmit = { ( payload : PricingPlanFormPayload ) =>
267- console . log ( 'payload' , payload )
268- }
305+ onSubmit = { ( payload : PricingPlanFormPayload ) => {
306+ console . log ( 'payload' , payload ) ;
307+ if ( payload . subscription === eorProductIdentifier ) {
308+ window . location . href = '?demo=onboarding-basic' ;
309+ }
310+ } }
269311 onSuccess = { ( response : PricingPlanResponse ) =>
270312 console . log ( 'response' , response )
271313 }
@@ -310,9 +352,9 @@ const MultiStepForm = ({
310352 < EligibilityQuestionnaireStep
311353 onSubmit = { ( payload ) => console . log ( 'payload' , payload ) }
312354 onSuccess = { ( response ) => console . log ( 'response' , response ) }
313- onError = { ( { error, fieldErrors } ) =>
314- setErrors ( { apiError : error . message , fieldErrors } )
315- }
355+ onError = { ( { error, fieldErrors } ) => {
356+ setErrors ( { apiError : error . message , fieldErrors } ) ;
357+ } }
316358 />
317359 < AlertError errors = { errors } />
318360 < div className = 'contractor-onboarding-buttons-container' >
@@ -332,70 +374,6 @@ const MultiStepForm = ({
332374 </ div >
333375 ) ;
334376
335- case 'choose_alternative_plan' :
336- return (
337- < div className = 'pricing-plan-form-layout' >
338- < div className = 'flex flex-col gap-2 text-center mb-6' >
339- < h1 className = 'text-2xl font-bold text-[#000000]' >
340- Choose Your Plan
341- </ h1 >
342- < p className = 'text-sm text-[#71717A]' >
343- This individual is not eligible for Contractor of Record. The
344- engagement terms imply an employer-employee relationship. We
345- suggest the plans below and recommend a legal review before
346- deciding. For any questions, contact help@remote.com.
347- </ p >
348- </ div >
349- < div className = 'mb-6' >
350- < ChooseAlternativePlanStep
351- components = { {
352- radio : ( { field, fieldData, fieldState } ) => {
353- return (
354- < PricingPlanCards
355- fieldData = { fieldData as PricingPlanDataProps }
356- fieldState = { fieldState }
357- field = { field }
358- />
359- ) ;
360- } ,
361- } }
362- onSubmit = { ( payload ) => {
363- console . log (
364- 'submitted choose alternative plan payload' ,
365- payload ,
366- ) ;
367- } }
368- onSuccess = { async ( response ) => {
369- if ( response . subscription === eorProductIdentifier ) {
370- try {
371- await discardEmployment ( {
372- employmentId :
373- contractorOnboardingBag . employmentId as string ,
374- } ) ;
375- } catch ( error ) {
376- console . error ( 'error discarding employment' , error ) ;
377- } finally {
378- window . location . href = '?demo=onboarding-basic' ;
379- }
380- }
381- } }
382- onError = { ( { error, fieldErrors } ) =>
383- setErrors ( { apiError : error . message , fieldErrors } )
384- }
385- />
386- </ div >
387- < AlertError errors = { errors } />
388- < div className = 'contractor-onboarding-buttons-container' >
389- < SubmitButton
390- className = 'submit-button'
391- onClick = { ( ) => setErrors ( { apiError : '' , fieldErrors : [ ] } ) }
392- >
393- Continue
394- </ SubmitButton >
395- </ div >
396- </ div >
397- ) ;
398-
399377 case 'review' : {
400378 return (
401379 < div className = 'contractor-onboarding-form-layout' >
0 commit comments