diff --git a/apps/frontend/src/features/admin-form/assistance/mutations.ts b/apps/frontend/src/features/admin-form/assistance/mutations.ts
index 0898c993c8..47b3c3a129 100644
--- a/apps/frontend/src/features/admin-form/assistance/mutations.ts
+++ b/apps/frontend/src/features/admin-form/assistance/mutations.ts
@@ -1,3 +1,4 @@
+import { useTranslation } from 'react-i18next'
import { useMutation, useQueryClient } from 'react-query'
import { useParams } from 'react-router-dom'
@@ -12,11 +13,13 @@ import { useMagicFormBuilderStore } from '../create/builder-and-design/MagicForm
export const useAssistanceMutations = () => {
const { formId } = useParams()
+ const { t } = useTranslation()
if (!formId) {
- throw new Error('Form ID is required')
+ throw new Error(
+ t('features.common.adminFormMutations.errors.missingFormId'),
+ )
}
-
const queryClient = useQueryClient()
const toast = useToast({ status: 'success', isClosable: true })
@@ -33,7 +36,9 @@ export const useAssistanceMutations = () => {
queryClient.invalidateQueries(adminFormKeys.id(formId))
toast.closeAll()
toast({
- description: 'Fields created successfully',
+ description: t(
+ 'features.adminForm.assistance.toasts.fieldsCreatedSuccess',
+ ),
status: 'success',
})
}
diff --git a/apps/frontend/src/features/admin-form/common/components/PreviewFormBanner/PreviewFormBanner.tsx b/apps/frontend/src/features/admin-form/common/components/PreviewFormBanner/PreviewFormBanner.tsx
index 755b65c081..e315795cee 100644
--- a/apps/frontend/src/features/admin-form/common/components/PreviewFormBanner/PreviewFormBanner.tsx
+++ b/apps/frontend/src/features/admin-form/common/components/PreviewFormBanner/PreviewFormBanner.tsx
@@ -1,5 +1,5 @@
import { useCallback, useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
+import { Trans, useTranslation } from 'react-i18next'
import { BiArrowBack, BiDotsHorizontalRounded, BiShow } from 'react-icons/bi'
import { Link as ReactLink } from 'react-router-dom'
import { Waypoint } from 'react-waypoint'
@@ -99,7 +99,9 @@ export const PreviewFormBanner = ({
mr={{ base: '0.5rem', md: '1rem' }}
/>
- {isTemplate ? 'Template Preview' : 'Form Preview'}
+ {isTemplate
+ ? t('features.common.previewFormBanner.title.template')
+ : t('features.common.previewFormBanner.title.form')}
{isTemplate ? (
@@ -111,24 +113,30 @@ export const PreviewFormBanner = ({
>
- Back to FormSG
+ {t('features.common.previewFormBanner.actions.backToFormSG')}
}
/>
@@ -165,7 +173,7 @@ export const PreviewFormBanner = ({
isFullWidth={true}
{...mobileDrawerButtonProps}
>
- Use this template
+ {t('features.common.previewFormBanner.actions.useTemplate')}
}
{...mobileDrawerButtonProps}
>
- Back to FormSG
+ {t('features.common.previewFormBanner.actions.backToFormSG')}
@@ -184,16 +192,18 @@ export const PreviewFormBanner = ({
{secretEnv === 'production' ? (
- To test your payment form, replicate this form on our{' '}
-
- testing platform.
-
+
+ ),
+ }}
+ />
) : (
- You will not be able to make a test payment, or view submitted
- answers or attachments in Form Preview mode. Open your form to
- make a test payment or form submission.
+ {t('features.common.previewFormBanner.payment.nonProduction')}
)}
@@ -202,8 +212,7 @@ export const PreviewFormBanner = ({
{!(secretEnv === 'production') && (
- You will not be able to view submitted answers or attachments in
- Form Preview mode. Open your form to test a form submission.
+ {t('features.common.previewFormBanner.nonPayment.nonProduction')}
)}
diff --git a/apps/frontend/src/features/admin-form/common/mutations.ts b/apps/frontend/src/features/admin-form/common/mutations.ts
index e9631d8ae9..0b95312f9b 100644
--- a/apps/frontend/src/features/admin-form/common/mutations.ts
+++ b/apps/frontend/src/features/admin-form/common/mutations.ts
@@ -1,4 +1,5 @@
import { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
import { useMutation, useQueryClient } from 'react-query'
import { useNavigate, useParams } from 'react-router-dom'
@@ -79,7 +80,12 @@ enum FormCollaboratorAction {
export const useMutateCollaborators = () => {
const { formId } = useCollaboratorWizard()
- if (!formId) throw new Error('No formId provided to useMutateCollaborators')
+ const { t } = useTranslation()
+ if (!formId) {
+ throw new Error(
+ t('features.common.adminFormMutations.errors.missingFormId'),
+ )
+ }
const navigate = useNavigate()
const queryClient = useQueryClient()
@@ -103,51 +109,59 @@ export const useMutateCollaborators = () => {
[formId, queryClient],
)
- const getMappedBadRequestErrorMessage = (
- formCollaboratorAction: FormCollaboratorAction,
- originalErrorMessage: string,
- ): string => {
- let badRequestErrorMessage
- switch (formCollaboratorAction) {
- case FormCollaboratorAction.ADD:
- badRequestErrorMessage = `The collaborator was unable to be added or edited. Please try again or refresh the page.`
- break
- case FormCollaboratorAction.TRANSFER_OWNERSHIP:
- badRequestErrorMessage = originalErrorMessage
- break
- default:
- badRequestErrorMessage = `Sorry, an error occurred. Please refresh the page and try again later.`
- }
-
- return badRequestErrorMessage
- }
+ const getMappedBadRequestErrorMessage = useCallback(
+ (
+ formCollaboratorAction: FormCollaboratorAction,
+ originalErrorMessage: string,
+ ): string => {
+ switch (formCollaboratorAction) {
+ case FormCollaboratorAction.ADD:
+ return t(
+ 'features.common.adminFormMutations.collaborators.errors.badRequestAddOrEdit',
+ )
+ case FormCollaboratorAction.TRANSFER_OWNERSHIP:
+ return originalErrorMessage
+ default:
+ return t(
+ 'features.common.adminFormMutations.collaborators.errors.badRequestGeneric',
+ )
+ }
+ },
+ [t],
+ )
- const getMappedDefaultErrorMessage = (
- formCollaboratorAction: FormCollaboratorAction,
- ): string => {
- let defaultErrorMessage
- switch (formCollaboratorAction) {
- case FormCollaboratorAction.ADD:
- defaultErrorMessage = 'Error adding collaborator.'
- break
- case FormCollaboratorAction.UPDATE:
- defaultErrorMessage = 'Error updating collaborator.'
- break
- case FormCollaboratorAction.REMOVE:
- defaultErrorMessage = 'Error removing collaborator.'
- break
- case FormCollaboratorAction.REMOVE_SELF:
- defaultErrorMessage = 'Error removing self.'
- break
- case FormCollaboratorAction.TRANSFER_OWNERSHIP:
- defaultErrorMessage = 'Error transfering form ownership.'
- break
- //should not reach
- default:
- defaultErrorMessage = 'Error.'
- }
- return defaultErrorMessage
- }
+ const getMappedDefaultErrorMessage = useCallback(
+ (formCollaboratorAction: FormCollaboratorAction): string => {
+ switch (formCollaboratorAction) {
+ case FormCollaboratorAction.ADD:
+ return t(
+ 'features.common.adminFormMutations.collaborators.errors.add',
+ )
+ case FormCollaboratorAction.UPDATE:
+ return t(
+ 'features.common.adminFormMutations.collaborators.errors.update',
+ )
+ case FormCollaboratorAction.REMOVE:
+ return t(
+ 'features.common.adminFormMutations.collaborators.errors.remove',
+ )
+ case FormCollaboratorAction.REMOVE_SELF:
+ return t(
+ 'features.common.adminFormMutations.collaborators.errors.removeSelf',
+ )
+ case FormCollaboratorAction.TRANSFER_OWNERSHIP:
+ return t(
+ 'features.common.adminFormMutations.collaborators.errors.transferOwnership',
+ )
+ //should not reach
+ default:
+ return t(
+ 'features.common.adminFormMutations.collaborators.errors.generic',
+ )
+ }
+ },
+ [t],
+ )
const getMappedErrorMessage = useCallback(
(
@@ -161,8 +175,15 @@ export const useMutateCollaborators = () => {
switch (error.code) {
case 422:
errorMessage = requestEmail
- ? `${requestEmail} is not part of a whitelisted agency`
- : `An unexpected error 422 happened`
+ ? t(
+ 'features.common.adminFormMutations.collaborators.errors.notWhitelistedAgency',
+ {
+ email: requestEmail,
+ },
+ )
+ : t(
+ 'features.common.adminFormMutations.collaborators.errors.unexpected422',
+ )
break
case 400:
errorMessage = getMappedBadRequestErrorMessage(
@@ -178,7 +199,7 @@ export const useMutateCollaborators = () => {
// if error is not of type HttpError return the error message encapsulated in Error object
return error.message
},
- [],
+ [getMappedBadRequestErrorMessage, getMappedDefaultErrorMessage, t],
)
const handleSuccess = useCallback(
@@ -232,7 +253,9 @@ export const useMutateCollaborators = () => {
)
if (index === -1)
throw new Error(
- 'Collaborator to update does not seem to exist. Refresh and try again.',
+ t(
+ 'features.common.adminFormMutations.collaborators.collaboratorNotFound',
+ ),
)
const permissionListToUpdate = currentPermissions.slice()
// Replace old permissions with new permission.
@@ -242,9 +265,13 @@ export const useMutateCollaborators = () => {
},
{
onSuccess: (newData, { permissionToUpdate }) => {
- const toastDescription = `${
- permissionToUpdate.email
- } has been updated to the ${permissionsToRole(permissionToUpdate)} role`
+ const toastDescription = t(
+ 'features.common.adminFormMutations.collaborators.success.updatedToRole',
+ {
+ email: permissionToUpdate.email,
+ role: permissionsToRole(permissionToUpdate),
+ },
+ )
handleSuccess({ newData, toastDescription })
},
onError: (error: Error, { permissionToUpdate }) => {
@@ -264,9 +291,13 @@ export const useMutateCollaborators = () => {
},
{
onSuccess: (newData, { newPermission }) => {
- const toastDescription = `${
- newPermission.email
- } has been added as a ${permissionsToRole(newPermission)}`
+ const toastDescription = t(
+ 'features.common.adminFormMutations.collaborators.success.addedAs',
+ {
+ email: newPermission.email,
+ role: permissionsToRole(newPermission),
+ },
+ )
handleSuccess({ newData, toastDescription })
},
onError: (error: Error, { newPermission }) => {
@@ -288,7 +319,13 @@ export const useMutateCollaborators = () => {
{
onSuccess: (newData, { permissionToRemove }) => {
// TODO: Decide if we want to allow redo (via readding permission)
- const toastDescription = `${permissionToRemove.email} has been removed as a collaborator`
+
+ const toastDescription = t(
+ 'features.common.adminFormMutations.collaborators.success.removed',
+ {
+ email: permissionToRemove.email,
+ },
+ )
handleSuccess({ newData, toastDescription })
},
onError: (error: Error) => {
@@ -304,7 +341,12 @@ export const useMutateCollaborators = () => {
toast.closeAll()
// Show toast on success.
toast({
- description: `${newData.form.admin.email} is now the owner of this form`,
+ description: t(
+ 'features.common.adminFormMutations.collaborators.success.newOwner',
+ {
+ email: newData.form.admin.email,
+ },
+ ),
})
// Update cached data.
@@ -328,8 +370,9 @@ export const useMutateCollaborators = () => {
{
onSuccess: () => {
toast({
- description:
- 'You have removed yourself as a collaborator from the form.',
+ description: t(
+ 'features.common.adminFormMutations.collaborators.success.removeSelf',
+ ),
})
// Remove all related queries from cache.
@@ -356,7 +399,12 @@ export const useMutateCollaborators = () => {
export const useMutateFormPage = () => {
const { formId } = useParams()
- if (!formId) throw new Error('No formId provided')
+ const { t } = useTranslation()
+ if (!formId) {
+ throw new Error(
+ t('features.common.adminFormMutations.errors.missingFormId'),
+ )
+ }
const queryClient = useQueryClient()
const toast = useToast({ status: 'success', isClosable: true })
@@ -383,7 +431,9 @@ export const useMutateFormPage = () => {
oldData ? { ...oldData, startPage: newData } : undefined,
)
toast({
- description: 'The form header and instructions were updated.',
+ description: t(
+ 'features.common.adminFormMutations.formPage.headerAndInstructionsUpdated',
+ ),
})
},
onError: handleError,
@@ -400,7 +450,9 @@ export const useMutateFormPage = () => {
(oldData) => (oldData ? { ...oldData, endPage: newData } : undefined),
)
toast({
- description: 'The Thank you page was updated.',
+ description: t(
+ 'features.common.adminFormMutations.formPage.thankYouPageUpdated',
+ ),
})
},
onError: handleError,
@@ -419,7 +471,9 @@ export const useMutateFormPage = () => {
oldData ? { ...oldData, payments_field: newData } : undefined,
)
toast({
- description: 'The payment was updated.',
+ description: t(
+ 'features.common.adminFormMutations.formPage.paymentUpdated',
+ ),
})
},
onError: handleError,
@@ -446,7 +500,9 @@ export const useMutateFormPage = () => {
: undefined,
)
toast({
- description: 'Payments product was updated.',
+ description: t(
+ 'features.common.adminFormMutations.formPage.paymentsProductUpdated',
+ ),
})
},
onError: handleError,
@@ -496,6 +552,8 @@ export const usePreviewFormMutations = (formId: string) => {
}
export const useFormFeedbackMutations = (headers: string[]) => {
+ const { t } = useTranslation()
+
const toast = useToast({ status: 'success', isClosable: true })
const handleError = useCallback(
@@ -515,7 +573,9 @@ export const useFormFeedbackMutations = (headers: string[]) => {
{
onSuccess: () => {
toast({
- description: 'Form feedback download started',
+ description: t(
+ 'features.common.adminFormMutations.downloads.feedbackStarted',
+ ),
})
},
onError: handleError,
@@ -526,6 +586,8 @@ export const useFormFeedbackMutations = (headers: string[]) => {
}
export const useFormIssueMutations = (headers: string[]) => {
+ const { t } = useTranslation()
+
const toast = useToast({ status: 'success', isClosable: true })
const handleError = useCallback(
@@ -545,7 +607,9 @@ export const useFormIssueMutations = (headers: string[]) => {
{
onSuccess: () => {
toast({
- description: 'Form issues download started',
+ description: t(
+ 'features.common.adminFormMutations.downloads.issuesStarted',
+ ),
})
},
onError: handleError,
@@ -556,6 +620,8 @@ export const useFormIssueMutations = (headers: string[]) => {
}
export const useFormRemindersMutations = () => {
+ const { t } = useTranslation()
+
const toast = useToast({ status: 'success', isClosable: true })
const handleError = useCallback(
(error: Error) => {
@@ -587,7 +653,7 @@ export const useFormRemindersMutations = () => {
{
onSuccess: () => {
toast({
- description: 'Your reminder has been sent',
+ description: t('features.common.adminFormMutations.reminders.sent'),
})
},
onError: handleError,
diff --git a/apps/frontend/src/i18n/locales/features/admin-form/assistance/en-sg.ts b/apps/frontend/src/i18n/locales/features/admin-form/assistance/en-sg.ts
new file mode 100644
index 0000000000..794870c0b6
--- /dev/null
+++ b/apps/frontend/src/i18n/locales/features/admin-form/assistance/en-sg.ts
@@ -0,0 +1,7 @@
+import { Assistance } from '.'
+
+export const enSG: Assistance = {
+ toasts: {
+ fieldsCreatedSuccess: 'Fields created successfully',
+ },
+}
diff --git a/apps/frontend/src/i18n/locales/features/admin-form/assistance/index.ts b/apps/frontend/src/i18n/locales/features/admin-form/assistance/index.ts
new file mode 100644
index 0000000000..9f405e1983
--- /dev/null
+++ b/apps/frontend/src/i18n/locales/features/admin-form/assistance/index.ts
@@ -0,0 +1,7 @@
+export * from './en-sg'
+
+export interface Assistance {
+ toasts: {
+ fieldsCreatedSuccess: string
+ }
+}
diff --git a/apps/frontend/src/i18n/locales/features/admin-form/en-sg.ts b/apps/frontend/src/i18n/locales/features/admin-form/en-sg.ts
index c44fb4ba27..1b14be3dd2 100644
--- a/apps/frontend/src/i18n/locales/features/admin-form/en-sg.ts
+++ b/apps/frontend/src/i18n/locales/features/admin-form/en-sg.ts
@@ -2,6 +2,7 @@ import { enSG as responsesCharts } from './responses/charts'
import { enSG as responsesComponents } from './responses/components'
import { enSG as responsesIndividualResponse } from './responses/individual-response'
import { enSG as responsesResponsesPage } from './responses/responses-page'
+import { enSG as assistance } from './assistance'
import { enSG as collaborator } from './collaborator'
import { enSG as featureTour } from './feature-tour'
import { enSG as feedback } from './feedback'
@@ -14,6 +15,7 @@ import { enSG as sidebar } from './sidebar'
import { enSG as toasts } from './toasts'
export const enSG = {
+ assistance,
responses: {
charts: responsesCharts,
components: responsesComponents,
diff --git a/apps/frontend/src/i18n/locales/features/admin-form/index.ts b/apps/frontend/src/i18n/locales/features/admin-form/index.ts
index b7bbfc0cbc..62f14ad516 100644
--- a/apps/frontend/src/i18n/locales/features/admin-form/index.ts
+++ b/apps/frontend/src/i18n/locales/features/admin-form/index.ts
@@ -1,3 +1,4 @@
+export { type Assistance } from './assistance'
export { type Collaborator } from './collaborator'
export * from './en-sg'
export { type FeatureTour } from './feature-tour'
diff --git a/apps/frontend/src/i18n/locales/features/common/en-sg.ts b/apps/frontend/src/i18n/locales/features/common/en-sg.ts
index 713557d06c..33330ec1a1 100644
--- a/apps/frontend/src/i18n/locales/features/common/en-sg.ts
+++ b/apps/frontend/src/i18n/locales/features/common/en-sg.ts
@@ -93,6 +93,29 @@ export const enSG: Common = {
text: 'Edit form',
ariaLabel: 'Click to edit the form',
},
+ previewFormBanner: {
+ title: {
+ template: 'Template Preview',
+ form: 'Form Preview',
+ },
+ actions: {
+ backToFormSG: 'Back to FormSG',
+ useTemplate: 'Use this template',
+ templatePreviewActions: 'Template preview actions',
+ returnToDashboard: 'Click to return to the admin dashboard',
+ useTemplateAria: 'Click to use this template',
+ },
+ payment: {
+ production:
+ 'To test your payment form, replicate this form on our testing platform.',
+ nonProduction:
+ 'You will not be able to make a test payment, or view submitted answers or attachments in Form Preview mode. Open your form to make a test payment or form submission.',
+ },
+ nonPayment: {
+ nonProduction:
+ 'You will not be able to view submitted answers or attachments in Form Preview mode. Open your form to test a form submission.',
+ },
+ },
moreOptions: 'More options',
betaBadgeLabel: 'Beta',
average: 'Average',
@@ -107,4 +130,49 @@ export const enSG: Common = {
completed: 'Completed',
approved: 'Approved',
notApproved: 'Not approved',
+ adminFormMutations: {
+ errors: {
+ missingFormId: 'Form ID is required',
+ },
+ collaborators: {
+ errors: {
+ badRequestAddOrEdit:
+ 'The collaborator was unable to be added or edited. Please try again or refresh the page.',
+ badRequestGeneric:
+ 'Sorry, an error occurred. Please refresh the page and try again later.',
+ add: 'Error adding collaborator.',
+ update: 'Error updating collaborator.',
+ remove: 'Error removing collaborator.',
+ removeSelf: 'Error removing self.',
+ transferOwnership: 'Error transferring form ownership.',
+ generic: 'Error.',
+ notWhitelistedAgency: '{email} is not part of a whitelisted agency',
+ unexpected422: 'An unexpected error 422 happened',
+ },
+ collaboratorNotFound:
+ 'Collaborator to update does not seem to exist. Refresh and try again.',
+ success: {
+ updatedToRole: '{email} has been updated to the {role} role',
+ addedAs: '{email} has been added as a {role}',
+ removed: '{email} has been removed as a collaborator',
+ newOwner: '{email} is now the owner of this form',
+ removeSelf:
+ 'You have removed yourself as a collaborator from the form.',
+ },
+ },
+ formPage: {
+ headerAndInstructionsUpdated:
+ 'The form header and instructions were updated.',
+ thankYouPageUpdated: 'The Thank you page was updated.',
+ paymentUpdated: 'The payment was updated.',
+ paymentsProductUpdated: 'Payments product was updated.',
+ },
+ downloads: {
+ feedbackStarted: 'Form feedback download started',
+ issuesStarted: 'Form issues download started',
+ },
+ reminders: {
+ sent: 'Your reminder has been sent',
+ },
+ },
}
diff --git a/apps/frontend/src/i18n/locales/features/common/index.ts b/apps/frontend/src/i18n/locales/features/common/index.ts
index e5cd6d3e9d..c40e77c430 100644
--- a/apps/frontend/src/i18n/locales/features/common/index.ts
+++ b/apps/frontend/src/i18n/locales/features/common/index.ts
@@ -93,6 +93,26 @@ export interface Common {
text: string
ariaLabel: string
}
+ previewFormBanner: {
+ title: {
+ template: string
+ form: string
+ }
+ actions: {
+ backToFormSG: string
+ useTemplate: string
+ templatePreviewActions: string
+ returnToDashboard: string
+ useTemplateAria: string
+ }
+ payment: {
+ production: string
+ nonProduction: string
+ }
+ nonPayment: {
+ nonProduction: string
+ }
+ }
moreOptions: string
betaBadgeLabel: string
average: string
@@ -107,4 +127,44 @@ export interface Common {
completed: string
approved: string
notApproved: string
+ adminFormMutations: {
+ errors: {
+ missingFormId: string
+ }
+ collaborators: {
+ errors: {
+ badRequestAddOrEdit: string
+ badRequestGeneric: string
+ add: string
+ update: string
+ remove: string
+ removeSelf: string
+ transferOwnership: string
+ generic: string
+ notWhitelistedAgency: string
+ unexpected422: string
+ }
+ collaboratorNotFound: string
+ success: {
+ updatedToRole: string
+ addedAs: string
+ removed: string
+ newOwner: string
+ removeSelf: string
+ }
+ }
+ formPage: {
+ headerAndInstructionsUpdated: string
+ thankYouPageUpdated: string
+ paymentUpdated: string
+ paymentsProductUpdated: string
+ }
+ downloads: {
+ feedbackStarted: string
+ issuesStarted: string
+ }
+ reminders: {
+ sent: string
+ }
+ }
}
diff --git a/apps/frontend/src/i18n/locales/features/index.ts b/apps/frontend/src/i18n/locales/features/index.ts
index 473ac08a9f..550a4d7547 100644
--- a/apps/frontend/src/i18n/locales/features/index.ts
+++ b/apps/frontend/src/i18n/locales/features/index.ts
@@ -1,4 +1,5 @@
export {
+ type Assistance,
type Collaborator,
type FeatureTour,
type Feedback,
diff --git a/apps/frontend/src/i18n/locales/types.ts b/apps/frontend/src/i18n/locales/types.ts
index 69f1e20fb4..c5451b6cf7 100644
--- a/apps/frontend/src/i18n/locales/types.ts
+++ b/apps/frontend/src/i18n/locales/types.ts
@@ -4,6 +4,7 @@ import { Pagination } from './components'
import { ValidationConstants } from './constants'
import {
App,
+ Assistance,
Collaborator,
Common,
EmergencyContact,
@@ -37,6 +38,7 @@ interface Translation {
translation: {
features: {
adminForm?: {
+ assistance?: Assistance
sidebar?: {
fields?: Fields
headerAndInstructions?: HeaderAndInstructions