-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: email <> storage mode parity (#7350)
* feat: add basic email notifications page * feat: update storage form types * feat: update validation rules and add helper fns * rename email notifications page name * refactor tab rendering logic * fix(admin-form): update Joi validation wrt emails and publicKey fields Fixes #2264 by disallowing publicKey field for email mode forms and disallowing emails field if not Email or Encrypt mode. * feat(model): add emails field to encrypt forms * fix(frontend): fix issue when getValues returns undefined * refactor: make dataCollationData optional and add common types * feat(encrypt-submission): update encrypt submissions to send email notifs * fix: replace deprecated opaque type with tagged * refactor: move email notifications and show payments tab by default * fix: update mutations to fix failing validation at form wizard * fix: remove unused type predicates * feat(frontend): exclude email notifications from payment forms * fix: move tabConfig to top level and separate label from path * refactor: remove redundant useMemo and add EmailNotificationsHeader * fix: update encrypt form validation to have string[] only * fix(admin-form): enforce emails to be empty when duplicating to encrypt * fix(test:backend): add and modify tests for emails field in encrypt form * fix(test): ensure processDuplicateOverrideProps returns empty emails for encrypt * fix(test): update ENCRYPT_FORM_DEFAULTS to have emails field * fix: add exhaustive switch for enums * fix: move boolean calc out and fix inline message in payments page for test env * fix: update form encrypt schema * fix: add PaymentsNotAllowed component * fix: update comment for /settings controller and remove emails from duplicate dto * fix(admin-form): validate that payment forms don't have emails and vice versa * fix: add helper to extract emails from form types * fix: cleanup * fix: update use-template mutations * fix: update payment form and emails to be mutually exclusive * fix: check payments_field.enabled instead of making stripe call * fix: check both PaymentChannel and enabled field for payment forms * feat: move email notifications into a new tab * feat: reduce opacity at component level and add stories for email notifs * fix: add common payment fields to fix chromatic tests * fix: update wrong link and remove padding * fix: fix lodash merge array bug for chromatic test * fix: lodash merge should only overwrite if override arr is empty * fix: fix chromatic reviews * fix: fix tag input UI * fix: ensure non-zero admin emails length before sending * fix: move invalid payment config check to svc instead of controller * fix: fix incorrect error thrown and add jest test case for invalid payment update * fix: remove unused import and move jest test * test: update e2e test for email notification in encrypt form * fix: fix failing backend jest tests * fix: check for null + undefined and fix style * fix: improve rendering of tabs to avoid inserting via idx * fix: render null if not email or encrypt form * fix: increase encrypt-submission timeout for checking for emails * fix(test): fix e2e tests for new email notifications tab
- Loading branch information
Showing
44 changed files
with
1,285 additions
and
277 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
169 changes: 169 additions & 0 deletions
169
frontend/src/features/admin-form/settings/SettingsEmailsPage.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
import { Meta, Story } from '@storybook/react' | ||
|
||
import { PaymentChannel, PaymentType } from '~shared/types' | ||
import { FormResponseMode, FormSettings, FormStatus } from '~shared/types/form' | ||
|
||
import { | ||
getAdminFormSettings, | ||
patchAdminFormSettings, | ||
} from '~/mocks/msw/handlers/admin-form' | ||
|
||
import { | ||
getMobileViewParameters, | ||
StoryRouter, | ||
viewports, | ||
} from '~utils/storybook' | ||
|
||
import { SettingsEmailsPage } from './SettingsEmailsPage' | ||
|
||
const PAYMENTS_ENABLED = { | ||
payments_channel: { | ||
channel: PaymentChannel.Stripe, | ||
target_account_id: 'target-account-id', | ||
publishable_key: 'publishable-key', | ||
payment_methods: [], | ||
}, | ||
payments_field: { | ||
enabled: true, | ||
description: 'description', | ||
name: 'name', | ||
amount_cents: 1, | ||
min_amount: 1, | ||
max_amount: 1, | ||
payment_type: PaymentType.Products, | ||
global_min_amount_override: 0, | ||
gst_enabled: true, | ||
products: [], | ||
products_meta: { | ||
multi_product: false, | ||
}, | ||
}, | ||
} | ||
|
||
const PAYMENTS_DISABLED = { | ||
payments_channel: { | ||
channel: PaymentChannel.Unconnected, | ||
target_account_id: '', | ||
publishable_key: '', | ||
payment_methods: [], | ||
}, | ||
payments_field: { | ||
enabled: false, | ||
description: '', | ||
name: '', | ||
amount_cents: 0, | ||
min_amount: 0, | ||
max_amount: 0, | ||
payment_type: PaymentType.Products, | ||
global_min_amount_override: 0, | ||
gst_enabled: true, | ||
products: [], | ||
products_meta: { | ||
multi_product: false, | ||
}, | ||
}, | ||
} | ||
|
||
const buildMswRoutes = ({ | ||
overrides, | ||
mode, | ||
delay, | ||
}: { | ||
overrides?: Partial<FormSettings> | ||
mode?: FormResponseMode | ||
delay?: number | 'infinite' | ||
} = {}) => [ | ||
getAdminFormSettings({ overrides, mode, delay }), | ||
patchAdminFormSettings({ overrides, mode, delay }), | ||
] | ||
|
||
export default { | ||
title: 'Pages/AdminFormPage/Settings/Emails', | ||
component: SettingsEmailsPage, | ||
decorators: [StoryRouter({ initialEntries: ['/12345'], path: '/:formId' })], | ||
parameters: { | ||
// Required so skeleton "animation" does not hide content. | ||
chromatic: { pauseAnimationAtEnd: true }, | ||
msw: buildMswRoutes(), | ||
}, | ||
} as Meta | ||
|
||
const Template: Story = () => <SettingsEmailsPage /> | ||
|
||
export const PrivateStorageForm = Template.bind({}) | ||
PrivateStorageForm.parameters = { | ||
msw: buildMswRoutes({ | ||
mode: FormResponseMode.Encrypt, | ||
overrides: { | ||
status: FormStatus.Private, | ||
emails: [], // has one email by default | ||
...PAYMENTS_DISABLED, | ||
}, | ||
}), | ||
} | ||
|
||
export const PrivateEmailForm = Template.bind({}) | ||
PrivateEmailForm.parameters = { | ||
msw: buildMswRoutes({ | ||
mode: FormResponseMode.Email, | ||
overrides: { | ||
status: FormStatus.Private, | ||
}, | ||
}), | ||
} | ||
|
||
export const PublicForm = Template.bind({}) | ||
PublicForm.parameters = { | ||
msw: buildMswRoutes({ | ||
mode: FormResponseMode.Encrypt, | ||
overrides: { | ||
status: FormStatus.Public, | ||
emails: [], | ||
...PAYMENTS_DISABLED, | ||
}, | ||
}), | ||
} | ||
|
||
export const PaymentForm = Template.bind({}) | ||
PaymentForm.parameters = { | ||
msw: buildMswRoutes({ | ||
mode: FormResponseMode.Encrypt, | ||
overrides: { | ||
status: FormStatus.Private, | ||
emails: [], | ||
...PAYMENTS_ENABLED, | ||
}, | ||
}), | ||
} | ||
|
||
export const Loading = Template.bind({}) | ||
Loading.parameters = { | ||
msw: buildMswRoutes({ delay: 'infinite' }), | ||
} | ||
|
||
export const NoEmailsAddedForm = Template.bind({}) | ||
NoEmailsAddedForm.parameters = { | ||
msw: buildMswRoutes({ | ||
mode: FormResponseMode.Encrypt, | ||
overrides: { | ||
status: FormStatus.Private, | ||
emails: [], | ||
...PAYMENTS_DISABLED, | ||
}, | ||
}), | ||
} | ||
|
||
export const Mobile = Template.bind({}) | ||
Mobile.parameters = { | ||
...NoEmailsAddedForm, | ||
...getMobileViewParameters(), | ||
} | ||
|
||
export const Tablet = Template.bind({}) | ||
Tablet.parameters = { | ||
...NoEmailsAddedForm, | ||
viewport: { | ||
defaultViewport: 'tablet', | ||
}, | ||
chromatic: { viewports: [viewports.md] }, | ||
} |
49 changes: 49 additions & 0 deletions
49
frontend/src/features/admin-form/settings/SettingsEmailsPage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { FormControl, Skeleton } from '@chakra-ui/react' | ||
|
||
import { FormResponseMode } from '~shared/types' | ||
|
||
import FormLabel from '~components/FormControl/FormLabel' | ||
import { TagInput } from '~components/TagInput' | ||
|
||
import { CategoryHeader } from './components/CategoryHeader' | ||
import { EmailFormSection } from './components/EmailFormSection' | ||
import { useAdminFormSettings } from './queries' | ||
|
||
const AdminEmailSection = () => { | ||
const { data: settings } = useAdminFormSettings() | ||
|
||
if (!settings) { | ||
return <EmailFormSectionSkeleton /> | ||
} | ||
|
||
const isEmailOrStorageMode = | ||
settings?.responseMode === FormResponseMode.Email || | ||
settings?.responseMode === FormResponseMode.Encrypt | ||
|
||
// should render null | ||
if (!isEmailOrStorageMode) { | ||
return false | ||
} | ||
|
||
return <EmailFormSection settings={settings} /> | ||
} | ||
|
||
const EmailFormSectionSkeleton = (): JSX.Element => { | ||
return ( | ||
<FormControl isRequired> | ||
<FormLabel>Send an email copy of new responses</FormLabel> | ||
<Skeleton> | ||
<TagInput placeholder="me@example.com" isDisabled /> | ||
</Skeleton> | ||
</FormControl> | ||
) | ||
} | ||
|
||
export const SettingsEmailsPage = (): JSX.Element => { | ||
return ( | ||
<> | ||
<CategoryHeader>Email notifications</CategoryHeader> | ||
<AdminEmailSection /> | ||
</> | ||
) | ||
} |
Oops, something went wrong.