Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[chore] address feedback for onboarding #90

Merged
merged 8 commits into from
May 24, 2024
20 changes: 17 additions & 3 deletions src/app/onboarding/availability/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { FormControl, FormField, FormItem, FormLabel } from '@/components/Form';
import Icon from '@/components/Icon';
import TextAreaInput from '@/components/TextAreaInput';
import TextInput from '@/components/TextInput';
import { availabilitySchema } from '@/data/formSchemas';
import { availabilitySchema, CHAR_LIMIT_MSG } from '@/data/formSchemas';
import { CardForm, Flex } from '@/styles/containers';
import { H1Centered } from '@/styles/text';
import {
Expand All @@ -31,6 +31,8 @@ export default function Page() {
const onboarding = useGuardedOnboarding();
const { backlinkHref, ebbTo, pageProgress } = useOnboardingNavigation();
const { push } = useRouter();
const [availabilityError, setAvailabilityError] = useState('');
const [hoursError, setHoursError] = useState('');

// scroll to top
useScrollToTop();
Expand Down Expand Up @@ -106,7 +108,7 @@ export default function Page() {
</FormLabel>
<FormControl>
<TextInput
errorText={fieldState.error?.message}
errorText={fieldState.error?.message ?? hoursError}
placeholder="x hours per month"
inputMode="numeric"
defaultValue={
Expand All @@ -118,12 +120,21 @@ export default function Page() {
onboarding.updateProfile({
hours_per_month: undefined,
});
setHoursError('');
return;
}

const toNum = z.coerce.number().safeParse(newValue);
const num = toNum.success ? toNum.data : undefined;

if (num === undefined) {
setHoursError('Hours per month must be a number.');
} else if (num < 0) {
setHoursError('Hours per month cannot be negative.');
} else {
setHoursError('');
}

field.onChange(num);
onboarding.updateProfile({
hours_per_month: num,
Expand Down Expand Up @@ -184,8 +195,11 @@ export default function Page() {
<TextAreaInput
placeholder="I won't be available from..."
defaultValue={field.value ?? ''}
error={fieldState.error?.message}
error={fieldState.error?.message ?? availabilityError}
onChange={newValue => {
setAvailabilityError(
newValue.length > 400 ? CHAR_LIMIT_MSG : '',
);
onboarding.updateProfile({
availability_description: newValue,
});
Expand Down
108 changes: 91 additions & 17 deletions src/app/onboarding/legal-credentials/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { useEffect, useMemo } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useRouter } from 'next/navigation';
import { FormProvider, useForm } from 'react-hook-form';
Expand All @@ -17,9 +17,10 @@ import {
import Icon from '@/components/Icon';
import InputDropdown from '@/components/InputDropdown';
import RadioGroup from '@/components/RadioGroup';
import TextAreaInput from '@/components/TextAreaInput';
import TextInput from '@/components/TextInput';
import { usStates } from '@/data/citiesAndStates';
import { attorneyCredentialSchema } from '@/data/formSchemas';
import { attorneyCredentialSchema, CHAR_LIMIT_MSG } from '@/data/formSchemas';
import { CardForm, Flex } from '@/styles/containers';
import { H1Centered } from '@/styles/text';
import { formatTruthy, identity } from '@/utils/helpers';
Expand All @@ -34,6 +35,7 @@ export default function Page() {
const onboarding = useGuardedOnboarding();
const { backlinkHref, ebbTo, pageProgress } = useOnboardingNavigation();
const { push } = useRouter();
const [commentError, setCommentError] = useState('');

// scroll to top
useScrollToTop();
Expand All @@ -45,14 +47,18 @@ export default function Page() {
stateBarred: onboarding.profile.state_barred ?? undefined,
barNumber: onboarding.profile.bar_number ?? undefined,
eoirRegistered: onboarding.profile.eoir_registered ?? undefined,
legalCredentialComment:
onboarding.profile.legal_credential_comment ?? undefined,
barred: onboarding.profile.has_bar_number ?? undefined,
},
});

const formValues = form.watch();
const isEmpty = useMemo(
() =>
!(formValues.stateBarred && formValues.barNumber) ||
formValues.eoirRegistered === undefined,
formValues.eoirRegistered === undefined ||
(!formValues.barred && !formValues.legalCredentialComment),
[formValues],
);

Expand Down Expand Up @@ -108,8 +114,8 @@ export default function Page() {
/>
</FormControl>
<FormDescription>
If you are barred in multiple states, choose your preferred
state
If you are barred in multiple states, please choose your
preferred state
</FormDescription>
<FormMessage />
</FormItem>
Expand All @@ -118,30 +124,65 @@ export default function Page() {

<FormField
control={form.control}
name="barNumber"
name="barred"
render={({ field, fieldState }) => (
<FormItem>
<FormLabel>
What is your attorney bar number in this state?
</FormLabel>
<FormLabel>Do you have a bar number in this state?</FormLabel>
<FormControl>
<TextInput
errorText={fieldState.error?.message}
placeholder="123456"
type="text"
defaultValue={field.value}
<RadioGroup
name="barred"
defaultValue={formatTruthy(
field.value,
'Yes',
'No',
undefined,
)}
options={['Yes', 'No']}
error={fieldState.error?.message}
onChange={newValue => {
const bool = newValue === 'Yes';
const barNum = bool ? '' : 'N/A';
onboarding.updateProfile({
bar_number: newValue,
has_bar_number: bool,
bar_number: barNum,
});
field.onChange(newValue);
form.setValue('barNumber', barNum);
field.onChange(bool);
}}
/>
</FormControl>
</FormItem>
)}
/>

{formValues.barred && (
<FormField
control={form.control}
name="barNumber"
render={({ field, fieldState }) => (
<FormItem>
<FormLabel>
What is your attorney bar number in this state?
</FormLabel>
<FormControl>
<TextInput
errorText={fieldState.error?.message}
placeholder="123456"
type="text"
defaultValue={field.value}
onChange={newValue => {
onboarding.updateProfile({
bar_number: newValue,
});
field.onChange(newValue);
}}
/>
</FormControl>
</FormItem>
)}
/>
)}

<FormField
control={form.control}
name="eoirRegistered"
Expand All @@ -153,7 +194,7 @@ export default function Page() {
</FormLabel>
<FormControl>
<RadioGroup
name="registered"
name="eoirRegistered"
defaultValue={formatTruthy(
field.value,
'Yes',
Expand All @@ -173,6 +214,39 @@ export default function Page() {
)}
/>

<FormField
control={form.control}
name="legalCredentialComment"
render={({ field, fieldState }) => (
<FormItem>
<FormLabel $required={!formValues.barred}>
Is there anything about your bar status we should know?
{formValues.barred && ' (optional)'}
</FormLabel>
<FormControl>
<TextAreaInput
placeholder="There are some extenuating circumstances with..."
defaultValue={field.value ?? ''}
error={fieldState.error?.message ?? commentError}
onChange={newValue => {
setCommentError(
newValue.length > 400 ? CHAR_LIMIT_MSG : '',
);
onboarding.updateProfile({
legal_credential_comment: newValue,
});
field.onChange(newValue);
}}
/>
</FormControl>
<FormDescription>
For example, if you were formerly barred but are not
currently; or, if your state does not have a bar number.
</FormDescription>
</FormItem>
)}
/>

<Flex $gap="40px">
<BigButton type="button" onClick={() => ebbTo(backlinkHref)}>
Back
Expand Down
18 changes: 16 additions & 2 deletions src/app/onboarding/review/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,18 @@ export default function Page() {
</Flex>
<Flex>
<Styles.SectionField>
<H4>What is your attorney bar number?</H4>
<P>{onboarding.profile.bar_number || 'N/A'}</P>
<H4>Do you have a bar number in this state?</H4>
<P>{onboarding.profile.has_bar_number ? 'Yes' : 'No'}</P>
</Styles.SectionField>
</Flex>
{onboarding.profile.has_bar_number && (
<Flex>
<Styles.SectionField>
<H4>What is your attorney bar number?</H4>
<P>{onboarding.profile.bar_number || 'N/A'}</P>
</Styles.SectionField>
</Flex>
)}
<Flex>
<Styles.SectionField>
<H4>
Expand All @@ -173,6 +181,12 @@ export default function Page() {
</P>
</Styles.SectionField>
</Flex>
<Flex>
<Styles.SectionField>
<H4>Is there anything about your bar status we should know?</H4>
<P>{onboarding.profile.legal_credential_comment ?? 'N/A'}</P>
</Styles.SectionField>
</Flex>
</Styles.SectionBox>
)}

Expand Down
1 change: 1 addition & 0 deletions src/app/onboarding/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const SectionField = styled.div<{ $optional?: boolean }>`
flex-direction: column;
gap: 16px;
width: 100%;
overflow-wrap: break-word;

& > h4 {
${({ $optional }) =>
Expand Down
9 changes: 5 additions & 4 deletions src/components/Buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ interface ButtonProps {
const ButtonStyles = css<ButtonProps>`
${sans.style}
appearance: none;
color: ${({ $primaryColor }) => ($primaryColor ? 'white' : COLORS.blueMid)};
color: ${({ $primaryColor, $secondaryColor }) =>
$primaryColor ? 'white' : $secondaryColor || COLORS.blueMid};
background: ${({ $primaryColor }) => $primaryColor || 'white'};
padding: 10px 20px;
border-radius: 5px;
Expand Down Expand Up @@ -85,9 +86,9 @@ const ButtonStyles = css<ButtonProps>`
}

&:active {
color: ${COLORS.greyMid};
border-color: ${COLORS.greyLight};
background: ${COLORS.greyLight};
color: ${COLORS.greyMid} !important;
border-color: ${COLORS.greyLight} !important;
background: ${COLORS.greyLight} !important;
}
`
: null};
Expand Down
8 changes: 4 additions & 4 deletions src/components/RadioGroup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ export default function RadioGroup({
)}
<GroupContainer>
{options.map(o => (
<RadioLabel key={o} htmlFor={o}>
<RadioLabel key={o} htmlFor={`${name}${o}`}>
<RadioInput
type="radio"
id={o}
id={`${name}${o}`}
name={name}
value={value}
checked={value ? value === o : undefined}
value={`${name}${o}`}
checked={value ? value === `${name}${o}` : undefined}
defaultChecked={defaultValue === o}
onChange={() => handleChange(o)}
/>
Expand Down
13 changes: 10 additions & 3 deletions src/components/SettingsSection/AvailabilitySection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { FormProvider, useForm } from 'react-hook-form';
import { z } from 'zod';
import { availabilitySchema } from '@/data/formSchemas';
import { availabilitySchema, CHAR_LIMIT_MSG } from '@/data/formSchemas';
import { Box } from '@/styles/containers';
import { Profile } from '@/types/schema';
import {
Expand Down Expand Up @@ -37,6 +37,7 @@ export default function AvailabilitySection() {
const [startDate, setStartDate] = useState<string>(
getDateDefault(profile.profileData ?? {}),
);
const [availabilityError, setAvailabilityError] = useState('');

const form = useForm<z.infer<typeof availabilitySchema>>({
resolver: zodResolver(availabilitySchema),
Expand Down Expand Up @@ -65,6 +66,7 @@ export default function AvailabilitySection() {
setIsEditing(false);
form.reset(getFormDefaults(profile.profileData ?? {}));
setStartDate(getDateDefault(profile.profileData ?? {}));
setAvailabilityError('');
}}
isSubmitting={form.formState.isSubmitting}
>
Expand Down Expand Up @@ -123,8 +125,13 @@ export default function AvailabilitySection() {
<TextAreaInput
placeholder="I won't be available from..."
defaultValue={field.value ?? ''}
error={fieldState.error?.message}
onChange={field.onChange}
error={fieldState.error?.message ?? availabilityError}
onChange={newValue => {
setAvailabilityError(
newValue.length > 400 ? CHAR_LIMIT_MSG : '',
);
field.onChange(newValue);
}}
/>
)}
/>
Expand Down
Loading
Loading