Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/admin/BulkUserCreationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ const BulkUserCreationPage: FC = () => {
});

const fieldError = (key: keyof FormFields) =>
form.submitCount > 0 && form.errors[key] ? <Text>{form.errors[key]}</Text> : null;
(form.submitCount > 0 || form.touched[key]) && form.errors[key] ? (
<Text variant="validation">{form.errors[key]}</Text>
) : null;

return (
<>
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,6 @@
"addTestToIdentifierPage.form.identifier.invalid.magicLink": "Please check the email address",
"addTestToIdentifierPage.form.identifier.invalid.estonianId": "Please check the identification code",
"addTestToIdentifierPage.button": "Add test result",
"addTestToIdentifierPage.success": "Test result for {{ identifier }} added."
"addTestToIdentifierPage.success": "Test result for {{ identifier }} added.",
"testFields.error.generic": "Please check the input"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly odd phrase. Perhaps something more like "Invalid value, please try again"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, tried to follow the Please x phrasing of the other messages, but it ended up weird.

}
3 changes: 2 additions & 1 deletion src/i18n/et.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,6 @@
"addTestToIdentifierPage.form.identifier.invalid.magicLink": "Palun kontrolli meiliaadressi",
"addTestToIdentifierPage.form.identifier.invalid.estonianId": "Palun kontrolli isikukoodi",
"addTestToIdentifierPage.button": "Lisa testitulemus",
"addTestToIdentifierPage.success": "Testitulemus isikule {{ identifier }} lisatud."
"addTestToIdentifierPage.success": "Testitulemus isikule {{ identifier }} lisatud.",
"testFields.error.generic": "Palun kontrolli sisestatud väärtust"
}
4 changes: 3 additions & 1 deletion src/identity/AddressForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export const AddressForm = ({ onComplete }: { onComplete: (address: Address) =>
});

const fieldError = (key: keyof AddressFormFields) =>
form.touched[key] && form.errors[key] ? <Text>{form.errors[key]}</Text> : null;
(form.submitCount > 0 || form.touched[key]) && form.errors[key] ? (
<Text variant="validation">{form.errors[key]}</Text>
) : null;

const field = (name: keyof AddressFormFields, label: string) => {
const id = `identity-${name}`;
Expand Down
4 changes: 3 additions & 1 deletion src/identity/ProfileForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ export const ProfileForm = ({ onComplete }: { onComplete: (profile: Profile) =>
});

const fieldError = (key: keyof ProfileFormFields) =>
form.touched[key] && form.errors[key] ? <Text>{form.errors[key]}</Text> : null;
(form.submitCount > 0 || form.touched[key]) && form.errors[key] ? (
<Text variant="validation">{form.errors[key]}</Text>
) : null;

return (
<AnyBox as="form" sx={{ display: 'grid', gridGap: 4 }} onSubmit={form.handleSubmit}>
Expand Down
22 changes: 5 additions & 17 deletions src/testing/AddTestToIdentifierPage.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import { screen, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import nock, { Scope } from 'nock';

Expand All @@ -25,35 +25,23 @@ describe(AddTestToIdentifierPage, () => {
expect(identifierInput()).toHaveFocus();
});

it('only allows submitting the form once the identifier is valid and required test fields are filled, showing validation errors', async () => {
it('creates a user and adds a PCR test for that user only when identifier is valid and required test fields are filled', async () => {
mockHttp().get('/api/v1/test-types').reply(200, [aTestType()]);
renderWrapped(<AddTestToIdentifierPage />);

const positiveOption = await screen.findByRole('radio', { name: 'Positive' });
const negativeOption = await screen.findByRole('radio', { name: 'Negative' });
const positiveOption = screen.getByRole('radio', { name: 'Positive' });

userEvent.type(identifierInput(), '79210030814'); // invalid id code
submit();
await screen.findByText(/check the identification code/i); // validation error

userEvent.type(identifierInput(), '39210030814'); // valid id code
submit();
await waitForElementToBeRemoved(screen.queryByText(/check the identification code/i)); // no validation error

await userEvent.type(notesInput(), 'Some notes');
expect(submitButton()).toBeDisabled(); // as a radio option has not been selected

userEvent.click(positiveOption);
await waitFor(() => expect(submitButton()).not.toBeDisabled());
});

it('creates a user and and adds a PCR test for that user', async () => {
mockHttp().get('/api/v1/test-types').reply(200, [aTestType()]);
renderWrapped(<AddTestToIdentifierPage />);

const negativeOption = await screen.findByRole('radio', { name: 'Negative' });
const positiveOption = screen.getByRole('radio', { name: 'Positive' });

userEvent.type(identifierInput(), '39210030814');
await userEvent.type(notesInput(), 'Some notes');
userEvent.click(negativeOption);
userEvent.click(positiveOption); // to confirm the latest value is sent

Expand Down
6 changes: 4 additions & 2 deletions src/testing/AddTestToIdentifierPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ export const AddTestToIdentifierPage: FC = () => {
});

const fieldError = (key: keyof FormFields) =>
form.touched[key] && form.errors[key] ? <Text>{form.errors[key]}</Text> : null;
(form.submitCount > 0 || form.touched[key]) && form.errors[key] ? (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seen this logic three times now, maybe you should move to a library?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, will see if I can create a type-safe component 👍

<Text variant="validation">{form.errors[key]}</Text>
) : null;

return (
<>
Expand Down Expand Up @@ -128,7 +130,7 @@ export const AddTestToIdentifierPage: FC = () => {

{selectedTestType && <TestFields form={form} testType={selectedTestType} />}

<Button variant="block" type="submit" disabled={!form.isValid || creating}>
<Button variant="block" type="submit" disabled={creating}>
<Message>addTestToIdentifierPage.button</Message>
</Button>
</AnyBox>
Expand Down
6 changes: 5 additions & 1 deletion src/testing/TestFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ interface TestFieldsProps {

export const TestFields: FC<TestFieldsProps> = ({ form, testType }) => {
const fieldError = (key: keyof TestType['resultsSchema']['properties']) =>
form.touched[key] && form.errors[key] ? <Text>{form.errors[key]}</Text> : null;
(form.submitCount > 0 || form.touched[key]) && form.errors[key] ? (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 :-)

<Text variant="validation">
<Message>testFields.error.generic</Message>
</Text>
) : null;

// TODO: Extract generic JSON schema generator
return (
Expand Down
12 changes: 10 additions & 2 deletions src/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const theme = {
colors: {
...baseTheme.colors,
primary: '#096DD9',
success: '#52c41a', // Primary green from https://ant.design/docs/spec/colors
error: '#f5222d', // Primary red from https://ant.design/docs/spec/colors
},
sizes: {
pageWidth: '600px',
Expand Down Expand Up @@ -102,10 +104,10 @@ const theme = {
paddingRight: 4,
},
success: {
background: '#52c41a', // Primary green from https://ant.design/docs/spec/colors
backgroundColor: 'success',
},
error: {
background: '#f5222d', // Primary red from https://ant.design/docs/spec/colors
backgroundColor: 'error',
},
},
badges: {
Expand Down Expand Up @@ -148,6 +150,12 @@ const theme = {
borderBottom: '1px solid #DEDEDE',
},
},
text: {
validation: {
color: 'error',
fontSize: 1,
},
},
};

export default theme;