Skip to content

Commit 06714f6

Browse files
authored
feat(onboarding) - add engagement form for Germany (#946)
* feat(types) - update opeanpi types * fix onboarding form abstraction * more types * add hooks && types * changes for engagement * add functionality to preload default field * add submission * format * export payload type * fix types * fix type * fix type * fix type * recover data * fix step and title * fix inclusion of the form * fix agreement * fix tests * remove todo * remove code * add tests * add description * remove comments
1 parent cff2e59 commit 06714f6

21 files changed

Lines changed: 11528 additions & 30 deletions

File tree

example/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/src/Onboarding.tsx

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import {
1010
SelectCountrySuccess,
1111
SelectCountryFormPayload,
1212
NormalizedFieldError,
13+
EngagementAgreementDetailsFormPayload,
14+
ZendeskTriggerButton,
15+
zendeskArticles,
1316
} from '@remoteoss/remote-flows';
1417
import React, { useState } from 'react';
1518
import { ReviewOnboardingStep } from './ReviewOnboardingStep';
@@ -49,6 +52,7 @@ const MultiStepForm = ({ components, onboardingBag }: MultiStepFormProps) => {
4952
SubmitButton,
5053
BackButton,
5154
SelectCountryStep,
55+
EngagementAgreementDetailsStep,
5256
} = components;
5357
const [errors, setErrors] = useState<{
5458
apiError: string;
@@ -118,6 +122,35 @@ const MultiStepForm = ({ components, onboardingBag }: MultiStepFormProps) => {
118122
</div>
119123
</>
120124
);
125+
case 'engagement_agreement_details':
126+
return (
127+
<>
128+
<EngagementAgreementDetailsStep
129+
onSubmit={(payload: EngagementAgreementDetailsFormPayload) =>
130+
console.log('payload', payload)
131+
}
132+
onSuccess={(data: SuccessResponse) => console.log('data', data)}
133+
onError={({ error, fieldErrors }) =>
134+
setErrors({ apiError: error.message, fieldErrors })
135+
}
136+
/>
137+
<AlertError errors={errors} />
138+
<div className='buttons-container'>
139+
<BackButton
140+
className='back-button'
141+
onClick={() => setErrors({ apiError: '', fieldErrors: [] })}
142+
>
143+
Previous Step
144+
</BackButton>
145+
<SubmitButton
146+
className='submit-button'
147+
onClick={() => setErrors({ apiError: '', fieldErrors: [] })}
148+
>
149+
Continue
150+
</SubmitButton>
151+
</div>
152+
</>
153+
);
121154
case 'contract_details':
122155
return (
123156
<>
@@ -208,6 +241,42 @@ const MultiStepForm = ({ components, onboardingBag }: MultiStepFormProps) => {
208241
'Review & Invite',
209242
];
210243
*/
244+
245+
const getStepTitle = (
246+
step: OnboardingRenderProps['onboardingBag']['steps'][number],
247+
selectedCountryCode: string | null,
248+
) => {
249+
if (
250+
selectedCountryCode === 'DEU' &&
251+
step.name === 'engagement_agreement_details'
252+
) {
253+
return 'Labor leasing in Germany';
254+
}
255+
return step.label;
256+
};
257+
258+
const getStepDescription = (
259+
step: OnboardingRenderProps['onboardingBag']['steps'][number],
260+
selectedCountryCode: string | null,
261+
) => {
262+
if (
263+
selectedCountryCode === 'DEU' &&
264+
step.name === 'engagement_agreement_details'
265+
) {
266+
return (
267+
<>
268+
Provide some details about your <strong>current workforce</strong> to
269+
make sure this employee is hired compliantly according to Germany’s AÜG
270+
labor leasing model.
271+
<ZendeskTriggerButton zendeskId={zendeskArticles.germanyLaborLeasing}>
272+
Learn more
273+
</ZendeskTriggerButton>
274+
</>
275+
);
276+
}
277+
return '';
278+
};
279+
211280
const OnBoardingRender = ({
212281
onboardingBag,
213282
components,
@@ -217,12 +286,20 @@ const OnBoardingRender = ({
217286
// When using dynamic_steps feature, you need to filter and use step.index for comparison
218287
// Otherwise, you can use the steps array directly with sequential indices
219288
//const stepTitle = STEPS[currentStepIndex];
220-
const stepTitle = onboardingBag.steps[currentStepIndex].label;
289+
const stepTitle = getStepTitle(
290+
onboardingBag.steps[currentStepIndex],
291+
onboardingBag.selectedCountry?.code ?? null,
292+
);
221293

222294
if (onboardingBag.isLoading) {
223295
return <p>Loading...</p>;
224296
}
225297

298+
const stepDescription = getStepDescription(
299+
onboardingBag.steps[currentStepIndex],
300+
onboardingBag.selectedCountry?.code ?? null,
301+
);
302+
226303
return (
227304
<>
228305
<div className='steps-navigation'>
@@ -242,14 +319,22 @@ const OnBoardingRender = ({
242319
key={step.name}
243320
className={`step-item ${step.index === currentStepIndex ? 'active' : ''}`}
244321
>
245-
{index + 1}. {step.label}
322+
{index + 1}.{' '}
323+
{getStepTitle(
324+
step,
325+
onboardingBag.selectedCountry?.code ?? null,
326+
)}
246327
</li>
247328
))}
248329
</ul>
249330
</div>
250331

251332
<div className='card' style={{ marginBottom: '20px' }}>
252333
<h1 className='heading'>{stepTitle}</h1>
334+
335+
{stepDescription && (
336+
<p className='text-sm text-[#71717A]'>{stepDescription}</p>
337+
)}
253338
<MultiStepForm onboardingBag={onboardingBag} components={components} />
254339
</div>
255340
</>

example/src/ReviewOnboardingStep.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,17 @@ export const ReviewOnboardingStep = ({
243243
>
244244
Edit Basic Information
245245
</button>
246+
<h2 className='title'>Engagement Agreement Details</h2>
247+
<ReviewMeta
248+
meta={onboardingBag.meta.fields.engagement_agreement_details}
249+
/>
250+
<button
251+
className='back-button'
252+
onClick={() => onboardingBag.goTo('engagement_agreement_details')}
253+
disabled={onboardingBag.isEmploymentReadOnly}
254+
>
255+
Edit Engagement Agreement Details
256+
</button>
246257
<h2 className='title'>Contract Details</h2>
247258
<ReviewMeta meta={onboardingBag.meta.fields.contract_details} />
248259
<button

src/common/api/fixtures/countries.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,11 @@ export const countriesMock = {
1212
eor_onboarding: true,
1313
contractor_products_available: ['standard', 'plus', 'cor'],
1414
},
15+
{
16+
code: 'DEU',
17+
name: 'Germany',
18+
eor_onboarding: true,
19+
contractor_products_available: ['standard', 'plus', 'cor'],
20+
},
1521
],
1622
};

src/components/shared/zendesk-drawer/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ export const zendeskArticles = {
2323
* https://support.remote.com/hc/en-us/articles/4466822781709
2424
*/
2525
extraPayments: 4466822781709,
26+
/**
27+
* Germany Labor Leasing
28+
* Access: Private (Need Remote account to access)
29+
* https://support.remote.com/hc/en-us/articles/43002165606541
30+
*/
31+
germanyLaborLeasing: 43002165606541,
2632
/**
2733
* International Pricing
2834
* Access: Public (Everyone can access)

src/flows/Onboarding/OnboardingFlow.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { BenefitsStep } from '@/src/flows/Onboarding/components/BenefitsStep';
1111
import { SelectCountryStep } from '@/src/flows/Onboarding/components/SelectCountryStep';
1212
import { ReviewStep } from '@/src/flows/Onboarding/components/ReviewStep';
1313
import { SaveDraftButton } from '@/src/flows/Onboarding/components/SaveDraftButton';
14+
import { EngagementAgreementDetailsStep } from '@/src/flows/Onboarding/components/EngagementAgreementDetailsStep';
1415

1516
export const OnboardingFlow = ({
1617
employmentId,
@@ -56,6 +57,7 @@ export const OnboardingFlow = ({
5657
onboardingBag,
5758
components: {
5859
BasicInformationStep: BasicInformationStep,
60+
EngagementAgreementDetailsStep: EngagementAgreementDetailsStep,
5961
ContractDetailsStep: ContractDetailsStep,
6062
BenefitsStep: BenefitsStep,
6163
SubmitButton: OnboardingSubmit,

src/flows/Onboarding/api.ts

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ import {
55
ConvertCurrencyParams,
66
CreateContractEligibilityParams,
77
EmploymentCreateParams,
8+
EmploymentEngagementAgreementDetailsParams,
89
EmploymentFullParams,
910
getIndexBenefitOffer,
1011
getShowCompany,
1112
getShowCompanyEmploymentOnboardingReservesStatus,
13+
getShowEmploymentEngagementAgreementDetails,
14+
getShowEngagementAgreementDetailsCountry,
1215
getShowFormCountry,
1316
getShowSchema,
1417
patchUpdateEmployment2,
@@ -19,13 +22,17 @@ import {
1922
postCreateRiskReserve,
2023
postInviteEmploymentInvitation,
2124
PostInviteEmploymentInvitationData,
25+
postUpdateEmploymentEngagementAgreementDetails,
2226
putUpdateBenefitOffer,
2327
UnifiedEmploymentUpsertBenefitOffersRequest,
2428
} from '@/src/client';
2529

2630
import { useClient } from '@/src/context';
2731
import { selectCountryStepSchema } from '@/src/flows/Onboarding/json-schemas/selectCountryStep';
28-
import { OnboardingFlowProps } from '@/src/flows/Onboarding/types';
32+
import {
33+
OnboardingFlowProps,
34+
OnboardingJsfModify,
35+
} from '@/src/flows/Onboarding/types';
2936
import {
3037
JSONSchemaFormResultWithFieldsets,
3138
JSONSchemaFormType,
@@ -106,6 +113,36 @@ export const useBenefitOffers = (employmentId: string | undefined) => {
106113
),
107114
});
108115
};
116+
117+
export const useEmploymentEngagementAgreementDetails = (
118+
employmentId: string | undefined,
119+
queryOptions?: { enabled?: boolean },
120+
) => {
121+
const { client } = useClient();
122+
return useQuery({
123+
queryKey: ['employment-engagement-agreement-details', employmentId],
124+
retry: false,
125+
enabled: queryOptions?.enabled ?? !!employmentId,
126+
queryFn: async () => {
127+
return getShowEmploymentEngagementAgreementDetails({
128+
client: client as Client,
129+
headers: {
130+
Authorization: ``,
131+
},
132+
path: {
133+
employment_id: employmentId as string,
134+
},
135+
}).then((response) => {
136+
if (response.error || !response.data) {
137+
throw new Error('Failed to fetch engagement agreement details');
138+
}
139+
return response;
140+
});
141+
},
142+
select: ({ data }) => data?.data?.details,
143+
});
144+
};
145+
109146
/**
110147
* Use this hook to invite an employee to the onboarding flow
111148
* @returns
@@ -306,6 +343,30 @@ export const useUpdateEmployment = (
306343
});
307344
};
308345

346+
export const useUpdateEmploymentEngagementAgreementDetails = () => {
347+
const { client } = useClient();
348+
349+
return useMutation({
350+
mutationFn: ({
351+
employmentId,
352+
...payload
353+
}: EmploymentEngagementAgreementDetailsParams & {
354+
employmentId: string;
355+
}) => {
356+
return postUpdateEmploymentEngagementAgreementDetails({
357+
client: client as Client,
358+
headers: {
359+
Authorization: ``,
360+
},
361+
body: payload,
362+
path: {
363+
employment_id: employmentId,
364+
},
365+
});
366+
},
367+
});
368+
};
369+
309370
export const useUpdateBenefitsOffers = (
310371
options?: OnboardingFlowProps['options'],
311372
) => {
@@ -459,3 +520,40 @@ export const useEmploymentOnboardingReservesStatus = (
459520
select: ({ data }) => data?.data?.status,
460521
});
461522
};
523+
524+
export const useEngagementAgreementDetailsSchema = (
525+
countryCode: string,
526+
fieldValues: FieldValues,
527+
options?: {
528+
jsfModify?: OnboardingJsfModify;
529+
queryOptions?: { enabled?: boolean };
530+
},
531+
) => {
532+
const { client } = useClient();
533+
return useQuery({
534+
queryKey: ['engagement-agreement-details', countryCode],
535+
retry: false,
536+
enabled: options?.queryOptions?.enabled ?? !!countryCode,
537+
queryFn: async () => {
538+
const response = await getShowEngagementAgreementDetailsCountry({
539+
client: client as Client,
540+
path: {
541+
country_code: countryCode,
542+
},
543+
});
544+
545+
if (response.error || !response.data) {
546+
throw new Error('Failed to fetch engagement agreement details');
547+
}
548+
549+
return response;
550+
},
551+
select: ({ data }) => {
552+
const jsfSchema = data?.data?.schema || {};
553+
554+
return createHeadlessForm(jsfSchema, fieldValues, {
555+
jsfModify: options?.jsfModify?.engagement_agreement_details,
556+
});
557+
},
558+
});
559+
};

0 commit comments

Comments
 (0)