Translation support completed

This commit is contained in:
Colin Dawson 2026-01-31 19:32:45 +00:00
parent 83cf83b6fc
commit 6181fe48aa
62 changed files with 589 additions and 898 deletions

47
Translate-Locale.ps1 Normal file
View File

@ -0,0 +1,47 @@
#You will need Microsoft Copilot CLI installed to run this script use this to install the command line tool:
# winget install Microsoft.Copilot
# pwsh ./Translate-Locale.ps1 `
# -SourceFile "./public/locales/en-GB/common.json" `
# -TargetLocale "fr-FR" `
# -OutputFile "./public/locales/fr-FR/common.json"
# pwsh ./Translate-Locale.ps1 `
# -SourceFile "./public/locales/en-GB/common.json" `
# -TargetLocale "en-US" `
# -OutputFile "./public/locales/en-US/common.json"
# pwsh ./Translate-Locale.ps1 `
# -SourceFile "./public/locales/en-GB/common.json" `
# -TargetLocale "fr-CA" `
# -OutputFile "./public/locales/fr-CA/common.json"
param(
[Parameter(Mandatory=$true)]
[string]$SourceFile, # en-GB.json
[Parameter(Mandatory=$true)]
[string]$TargetLocale, # fr-FR, fr-CA, en-US, etc.
[Parameter(Mandatory=$true)]
[string]$OutputFile # output JSON file
)
# Load the source JSON
$sourceJson = Get-Content $SourceFile -Raw
# Build the translation prompt
$prompt = @"
Translate the following JSON values into $TargetLocale.
Keep the keys exactly the same.
Return valid JSON only.
$sourceJson
"@
# Call Copilot CLI
$translated = copilot $prompt
# Save the result
$translated | Out-File $OutputFile -Encoding UTF8
Write-Host "Generated $TargetLocale translation: $OutputFile"

View File

@ -1,4 +1,10 @@
{
"AuthorizationEndpoint": "Authorization Endpoint",
"ConfirmEmailResent": "Confirmation email resent",
"OccuredAt": "Occurred At"
"OccuredAt": "Occurred At",
"Organisation": "Organization",
"OrganisationEdited": "Organization edited",
"Mail": "Email",
"MailTemplates": "Email Templates",
"LoggingOut": "Signing out"
}

View File

@ -1,5 +1,6 @@
{
"Activate": "Activate",
"Active": "Active",
"Add": "Add",
"AddDomain": "Add Domain",
"Address": "Address",
@ -10,92 +11,185 @@
"AnErrorOccurred": "An error occurred",
"Application": "Application",
"Applications": "Applications",
"AuthorizationEndpoint": "Authorisation Endpoint",
"AuditLog": "Audit Logs",
"AuditLogs": "Audit Logs",
"Authenticate": "Authenticate",
"AuthenticationCode": "Authentication code",
"BlockedIPAddresses": "Blocked IP addresses",
"BlockedIPs": "Blocked IPs",
"Blocked": "Blocked",
"Cancel": "Cancel",
"Changes": "Changes",
"ClientDomainManager": "Client Domain Manager",
"ClientDomains": "Client Domains",
"Close": "Close",
"ClientId": "Client Id",
"ClientSecret": "Client Secret",
"Comment": "Comment",
"Confirm": "Confirm",
"ConfirmEmailResent": "Confirm e-mail resent",
"ConfirmPassword": "Confirm Password",
"Continuous": "Continuous",
"Created": "Created",
"CustomField": "Custom Field",
"CustomFieldEdited": "Custom Field edited",
"CustomFieldForChildEntries": "Custom field for child entries",
"CustomFieldManager": "Custom Field Manager",
"CustomFields": "Custom Fields",
"Day": "Day",
"DefaultValue": "Default Value",
"DefaultMustBeGreaterThanOrEqualToMinimumValue": "\"Default Value\" must be greater than or equal to \"Minimum Value\"",
"DefaultMustBeLessThanOrEqualToMaximumValue": "\"Default Value\" must be less than or equal to \"Maximum Value\"",
"Definition": "Definition",
"DisableAuthenticator": "Disable Authenticator",
"DisplayName": "Display Name",
"Domain": "Domain",
"DomainEdited": "Domain edited",
"Disabled": "Disabled",
"Enabled": "Enabled",
"e-print": "e-print",
"e-suite": "e-suite",
"e-suiteLogo": "e-suite logo",
"Edit": "Edit",
"EditDomain": "Edit Domain",
"EditUser": "Edit User",
"EFlowAppId": "e-flow AppId",
"EFlowCategoryId": "e-flow CategoryId",
"EFlowHostname": "e-flow hostname",
"Email": "Email",
"EmailTemplateSaved": "Email Template saved",
"EntityDisplayName": "Entity Display Name",
"ErrorLogs": "Error Logs",
"ExceptionJson": "Exception JSON",
"ExceptionLogs": "Exception Logs",
"FailedToDisableAuthenticator": "Failed to disable authenticator:",
"Field": "Field",
"FailedToSaveFormInstance": "Failed to save form instance",
"FieldType": "Field Type",
"ForgottenPassword": "Forgotten Password",
"FirstName": "First name",
"Form": "Form",
"Forms": "Forms",
"FormTemplate": "Form Template",
"FormTemplateEdited": "Form template edited",
"FormTemplateManager": "Form Template Manager",
"General": "General",
"Glossaries": "Glossaries",
"Glossary": "Glossary",
"GlossaryItem": "Glossary Item",
"GlossaryItemEdited": "Glossary Item edited",
"GlossaryManager": "Glossary Manager",
"Group": "Group",
"Home": "Home",
"Id": "Id",
"Increment": "Increment",
"IsPublic": "Is Public",
"IPAddress": "IP Address",
"IPAddressUnblocked": "IP Address '{{ip}}' unblocked.",
"Items": "Items",
"LastUpdated": "Last Updated",
"Loading": "Loading",
"LoggingOut": "Logging out",
"LastName": "Last name",
"Mail": "Mail",
"MailTemplates": "Mail Templates",
"MaxEntriesEmptyUnlimited": "Max Entries (empty=unlimited)",
"MaximumValue": "Maximum Value",
"Message": "Message",
"MinEntries": "Min Entries",
"MinimumValue": "Minimum Value",
"MiddleNames": "Middle names",
"Month": "Month",
"MultiLine": "Multi-line",
"Name": "Name",
"NewCustomFieldAdded": "New Custom Field added",
"NewDomainAdded": "New Domain added",
"NewFormTemplateAdded": "New Form Template added",
"NewGlossaryItemAdded": "New Glossary Item added",
"NewOrganisationAdded": "New Organisation added",
"NewPassword": "New Password",
"NewRoleAdded": "New Role added",
"NewSequenceAdded": "New sequence added",
"NewSpecificationsAdded": "New Specifications added",
"NewSiteAdded": "New site added",
"NewSsoProviderAdded": "New Sso Provider added",
"NewUserAdded": "New User added",
"NewValue": "New Value",
"NotFound": "Not found",
"Number": "Number",
"NumberOfAttempts": "Number Of Attempts",
"OccuredAt": "Occured At",
"OldValue": "Old Value",
"Organisation": "Organisation",
"OrganisationEdited": "Organisation edited",
"Password": "Password",
"PasswordIsRequired": "Password is required",
"PasswordMinLength": "Password must be at least {{minPasswordLength}} characters",
"PasswordsMustMatch": "You need to confirm by typing exactly the same as the new password",
"Pattern": "Pattern",
"Pending": "Pending",
"PressAgainToDelete": "Press again to delete",
"PressAgainToUnblock": "Press again to unblock",
"PrintSpecification": "Print Specification",
"Profile": "Profile",
"ResendConfirm": "Resend Confirm",
"Required": "Required",
"ResetPassword": "Reset Password",
"RolloverType": "Rollover Type",
"Role": "Role",
"RoleAccess": "Role Access",
"RoleAccessUpdated": "Role access updated successfully.",
"RoleEdited": "Role edited",
"Save": "Save",
"SaveAndClose": "Save and close",
"SecurityRoles": "Security Roles",
"Seed": "Seed",
"Sequence": "Sequence",
"SequenceEdited": "Sequence edited",
"SequenceFormGlossary": "Sequence/Form/Glossary",
"SequenceManager": "Sequence Manager",
"ShowJSON": "Show JSON",
"ShowStackTrace": "Show stack trace",
"SigmaId": "Sigma Id",
"Site": "Site",
"SiteEdited": "Site edited",
"SiteManager": "Site Manager",
"SpecificationManager": "Specification Manager",
"Specifications": "Specifications",
"SpecificationsEdited": "Specifications edited",
"SsoManager": "Sso Manager",
"SsoProvider": "Sso Provider",
"SsoProviderEdited": "Sso Provider edited",
"StackTrace": "Stack Trace",
"Status": "Status",
"Step": "Step",
"Subject": "Subject",
"Support": "Support",
"SupportingData": "Supporting Data",
"TemplateIdCannotBeNull": "Template Id cannot be null",
"TemplateUnknown": "Template unknown",
"Text": "Text",
"TheDetailsBelowAreLoadedFromMasterTemplate": "The details below are loaded from the master template. Saving this template will mean that any changes to the master template will not automatically appear here.",
"ThereAreErrorsOnTheForm": "There are errors on the form",
"ThisTemplateIsCustomForThisDomainOnly": "This template is custom for this domain only",
"Timing": "Timing",
"TokenEndpoint": "Token Endpoint",
"TwoFactorAuthentication": "2 Factor Authentication",
"Type": "Type",
"UnblockedInMinutes": "Unblocked In (Minutes)",
"Up": "Up",
"User": "User",
"UserAddedToRole": "User added to role",
"UserManager": "User Manager",
"UserName": "User Name",
"UsernameIsRequired": "Username is required",
"UsernameMustBeValidEmail": "Username must be a valid email",
"Users": "Users",
"Version": "Version"
"UserEdited": "User edited",
"ValidIssuer": "Valid Issuer",
"Version": "Version",
"VersionCannotBeNull": "Version cannot be null",
"Year": "Year",
"YourProfileSettingsHaveBeenSaved": "Your profile settings have been saved"
}

View File

@ -1,7 +1,11 @@
{
"Email": "Courriel",
"AnEmailWithPasswordResetLinkHasBeenSent": "Un courriel contenant un lien pour réinitialiser le mot de passe a été envoyé.",
"ConfirmEmailResent": "Courriel de confirmation renvoyé",
"Email": "Courriel",
"EmailTemplateSaved": "Modèle de courriel enregistré",
"LoggingOut": "Fermeture de session",
"Mail": "Courriel",
"MailTemplates": "Modèles de courriels",
"Support": "Soutien",
"LoggingOut": "Fermeture de session"
"PressAgainToDelete": "Appuyer de nouveau pour supprimer",
"PressAgainToUnblock": "Appuyer de nouveau pour débloquer"
}

View File

@ -1,5 +1,6 @@
{
"Activate": "Activer",
"Active": "Actif",
"Add": "Ajouter",
"AddDomain": "Ajouter un domaine",
"Address": "Adresse",
@ -10,92 +11,185 @@
"AnErrorOccurred": "Une erreur s'est produite",
"Application": "Application",
"Applications": "Applications",
"AuthorizationEndpoint": "Point de terminaison dautorisation",
"AuditLog": "Journaux daudit",
"AuditLogs": "Journaux daudit",
"Authenticate": "Authentifier",
"AuthenticationCode": "Code dauthentification",
"BlockedIPAddresses": "Adresses IP bloquées",
"BlockedIPs": "IPs bloquées",
"Blocked": "Bloqué",
"Cancel": "Annuler",
"Changes": "Modifications",
"ClientDomainManager": "Gestionnaire de domaines clients",
"ClientDomains": "Domaines clients",
"Close": "Fermer",
"ClientId": "Identifiant client",
"ClientSecret": "Secret client",
"Comment": "Commentaire",
"Confirm": "Confirmer",
"ConfirmEmailResent": "E-mail de confirmation renvoyé",
"ConfirmPassword": "Confirmer le mot de passe",
"Continuous": "Continu",
"Created": "Créé",
"CustomField": "Champ personnalisé",
"CustomFieldEdited": "Champ personnalisé modifié",
"CustomFieldForChildEntries": "Champ personnalisé pour les entrées enfants",
"CustomFieldManager": "Gestionnaire de champs personnalisés",
"CustomFields": "Champs personnalisés",
"Day": "Jour",
"DefaultValue": "Valeur par défaut",
"DefaultMustBeGreaterThanOrEqualToMinimumValue": "\"Valeur par défaut\" doit être supérieure ou égale à \"Valeur minimale\"",
"DefaultMustBeLessThanOrEqualToMaximumValue": "\"Valeur par défaut\" doit être inférieure ou égale à \"Valeur maximale\"",
"Definition": "Définition",
"DisableAuthenticator": "Désactiver lauthentificateur",
"DisplayName": "Nom daffichage",
"Domain": "Domaine",
"DomainEdited": "Domaine modifié",
"Disabled": "Désactivé",
"Enabled": "Activé",
"e-print": "e-print",
"e-suite": "e-suite",
"e-suiteLogo": "Logo e-suite",
"Edit": "Modifier",
"EditDomain": "Modifier le domaine",
"EditUser": "Modifier lutilisateur",
"EFlowAppId": "ID dapplication e-flow",
"EFlowCategoryId": "ID de catégorie e-flow",
"EFlowHostname": "Nom dhôte e-flow",
"Email": "E-mail",
"EmailTemplateSaved": "Modèle de-mail enregistré",
"EntityDisplayName": "Nom daffichage de lentité",
"ErrorLogs": "Journaux derreurs",
"ExceptionJson": "Exception JSON",
"ExceptionLogs": "Journaux dexceptions",
"FailedToDisableAuthenticator": "Échec de la désactivation de lauthentificateur :",
"Field": "Champ",
"FailedToSaveFormInstance": "Échec de lenregistrement de linstance du formulaire",
"FieldType": "Type de champ",
"ForgottenPassword": "Mot de passe oublié",
"FirstName": "Prénom",
"Form": "Formulaire",
"Forms": "Formulaires",
"FormTemplate": "Modèle de formulaire",
"FormTemplateEdited": "Modèle de formulaire modifié",
"FormTemplateManager": "Gestionnaire de modèles de formulaires",
"General": "Général",
"Glossaries": "Glossaires",
"Glossary": "Glossaire",
"GlossaryItem": "Élément de glossaire",
"GlossaryItemEdited": "Élément de glossaire modifié",
"GlossaryManager": "Gestionnaire de glossaires",
"Group": "Groupe",
"Home": "Accueil",
"Id": "Id",
"Increment": "Incrément",
"IsPublic": "Public",
"IPAddress": "Adresse IP",
"IPAddressUnblocked": "Adresse IP '{{ip}}' débloquée.",
"Items": "Éléments",
"LastUpdated": "Dernière mise à jour",
"Loading": "Chargement",
"LoggingOut": "Déconnexion",
"LastName": "Nom de famille",
"Mail": "Courrier",
"MailTemplates": "Modèles de-mails",
"MaxEntriesEmptyUnlimited": "Entrées max (vide = illimité)",
"MaximumValue": "Valeur maximale",
"Message": "Message",
"MinEntries": "Entrées min",
"MinimumValue": "Valeur minimale",
"MiddleNames": "Deuxième prénom",
"Month": "Mois",
"MultiLine": "Multiligne",
"Name": "Nom",
"NewCustomFieldAdded": "Nouveau champ personnalisé ajouté",
"NewDomainAdded": "Nouveau domaine ajouté",
"NewFormTemplateAdded": "Nouveau modèle de formulaire ajouté",
"NewGlossaryItemAdded": "Nouvel élément de glossaire ajouté",
"NewOrganisationAdded": "Nouvelle organisation ajoutée",
"NewPassword": "Nouveau mot de passe",
"NewRoleAdded": "Nouveau rôle ajouté",
"NewSequenceAdded": "Nouvelle séquence ajoutée",
"NewSpecificationsAdded": "Nouvelles spécifications ajoutées",
"NewSiteAdded": "Nouveau site ajouté",
"NewSsoProviderAdded": "Nouveau fournisseur SSO ajouté",
"NewUserAdded": "Nouvel utilisateur ajouté",
"NewValue": "Nouvelle valeur",
"NotFound": "Introuvable",
"Number": "Nombre",
"NumberOfAttempts": "Nombre de tentatives",
"OccuredAt": "Survenu à",
"OldValue": "Ancienne valeur",
"Organisation": "Organisation",
"OrganisationEdited": "Organisation modifiée",
"Password": "Mot de passe",
"PasswordIsRequired": "Le mot de passe est requis",
"PasswordMinLength": "Le mot de passe doit contenir au moins {{minPasswordLength}} caractères",
"PasswordsMustMatch": "Vous devez confirmer en saisissant exactement le même nouveau mot de passe",
"Pattern": "Motif",
"Pending": "En attente",
"PressAgainToDelete": "Appuyez de nouveau pour supprimer",
"PressAgainToUnblock": "Appuyez de nouveau pour débloquer",
"PrintSpecification": "Imprimer la spécification",
"Profile": "Profil",
"ResendConfirm": "Renvoyer la confirmation",
"Required": "Requis",
"ResetPassword": "Réinitialiser le mot de passe",
"RolloverType": "Type de report",
"Role": "Rôle",
"RoleAccess": "Accès par rôle",
"RoleAccessUpdated": "Accès par rôle mis à jour avec succès.",
"RoleEdited": "Rôle modifié",
"Save": "Enregistrer",
"SaveAndClose": "Enregistrer et fermer",
"SecurityRoles": "Rôles de sécurité",
"Seed": "Graine",
"Sequence": "Séquence",
"SequenceEdited": "Séquence modifiée",
"SequenceFormGlossary": "Séquence/Formulaire/Glossaire",
"SequenceManager": "Gestionnaire de séquences",
"ShowJSON": "Afficher le JSON",
"ShowStackTrace": "Afficher la trace de pile",
"SiteManager": "Gestionnaire de site",
"SigmaId": "ID Sigma",
"Site": "Site",
"SiteEdited": "Site modifié",
"SiteManager": "Gestionnaire de sites",
"SpecificationManager": "Gestionnaire de spécifications",
"Specifications": "Spécifications",
"SpecificationsEdited": "Spécifications modifiées",
"SsoManager": "Gestionnaire SSO",
"SsoProvider": "Fournisseur SSO",
"SsoProviderEdited": "Fournisseur SSO modifié",
"StackTrace": "Trace de pile",
"Status": "Statut",
"Step": "Étape",
"Subject": "Sujet",
"Support": "Support",
"SupportingData": "Données de support",
"TemplateIdCannotBeNull": "LID du modèle ne peut pas être nul",
"TemplateUnknown": "Modèle inconnu",
"Text": "Texte",
"TheDetailsBelowAreLoadedFromMasterTemplate": "Les détails ci-dessous sont chargés depuis le modèle maître. Enregistrer ce modèle signifie que les modifications du modèle maître napparaîtront plus automatiquement ici.",
"ThereAreErrorsOnTheForm": "Il y a des erreurs dans le formulaire",
"ThisTemplateIsCustomForThisDomainOnly": "Ce modèle est personnalisé uniquement pour ce domaine",
"Timing": "Timing",
"TokenEndpoint": "Point de terminaison du jeton",
"TwoFactorAuthentication": "Authentification à deux facteurs",
"Type": "Type",
"UnblockedInMinutes": "Débloqué dans (minutes)",
"Up": "Haut",
"User": "Utilisateur",
"UserAddedToRole": "Utilisateur ajouté au rôle",
"UserManager": "Gestionnaire dutilisateurs",
"UserName": "Nom dutilisateur",
"UsernameIsRequired": "Le nom dutilisateur est requis",
"UsernameMustBeValidEmail": "Le nom dutilisateur doit être une adresse e-mail valide",
"Users": "Utilisateurs",
"Version": "Version"
"UserEdited": "Utilisateur modifié",
"ValidIssuer": "Émetteur valide",
"Version": "Version",
"VersionCannotBeNull": "La version ne peut pas être nulle",
"Year": "Année",
"YourProfileSettingsHaveBeenSaved": "Vos paramètres de profil ont été enregistrés"
}

View File

@ -288,7 +288,7 @@ function GetSecureRoutes() {
path="/domains/add"
element={
<Mainframe title={t("ClientDomainManager")}>
<DomainsDetails editMode={false} />
<DomainsDetails isEditMode={false} />
</Mainframe>
}
/>
@ -296,7 +296,7 @@ function GetSecureRoutes() {
path="/domains/edit/:domainId/addRole"
element={
<Mainframe title={t("ClientDomainManager")}>
<RolesDetails editMode={false} />
<RolesDetails isEditMode={false} />
</Mainframe>
}
/>
@ -304,7 +304,7 @@ function GetSecureRoutes() {
path="/domains/edit/:domainId/editRole/:roleId"
element={
<Mainframe title={t("ClientDomainManager")}>
<RolesDetails editMode={true} />
<RolesDetails isEditMode={true} />
</Mainframe>
}
/>
@ -312,7 +312,7 @@ function GetSecureRoutes() {
path="/domains/edit/:domainId/editRole/:roleId/addUserToRole"
element={
<Mainframe title={t("ClientDomainManager")}>
<AddUserToRole editMode={false} />
<AddUserToRole isEditMode={false} />
</Mainframe>
}
/>
@ -320,7 +320,7 @@ function GetSecureRoutes() {
path="/domains/edit/:domainId"
element={
<Mainframe title={t("ClientDomainManager")}>
<DomainsDetails editMode={true} />
<DomainsDetails isEditMode={true} />
</Mainframe>
}
/>

View File

@ -1,5 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../i18n/i18n";
import deepFind from "../../utils/deepfind";
import Column from "./columns";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -47,7 +48,7 @@ export default function TableBody<T>({
onSelectRow,
showSecondaryAudit,
}: TableBodyProps<T>): JSX.Element {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const resolvePath = (path: string, args: string[]) => {
let modifiedPath = path;
let index = 0;

View File

@ -17,6 +17,8 @@ import Loading from "./Loading";
import { useForm } from "./useForm";
import { renderCustomField } from "./formHelpers";
import { CustomFieldValue } from "../../modules/manager/glossary/services/glossaryService";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../i18n/i18n";
interface TemplateFillerProps {
templateId?: GeneralIdRef;
@ -204,20 +206,22 @@ const TemplateFiller = forwardRef<TemplateFillerHandle, TemplateFillerProps>(
return Object.keys(form.state.errors).length > 0;
}, [form.state.errors]);
const { t } = useTranslation(Namespaces.Common);
const Save = useCallback(async () => {
const { errors } = form.state;
if (Object.keys(errors).length > 0) {
toast.error("There are errors on the form");
throw new Error("There are errors on the form");
toast.error(t("ThereAreErrorsOnTheForm"));
throw new Error(t("ThereAreErrorsOnTheForm") as string);
}
const customFieldValues = form.CustomFieldValues();
if (formInstanceId !== undefined) {
if (template.templateId === undefined)
throw Error("TemplateId cannot be null");
throw Error(t("TemplateIdCannotBeNull") as string);
if (template.version === undefined)
throw Error("Version cannot be null");
throw Error(t("VersionCannotBeNull") as string);
const editFormInstance: EditFormInstance = {
formInstanceId,
@ -238,9 +242,9 @@ const TemplateFiller = forwardRef<TemplateFillerHandle, TemplateFillerProps>(
};
return await formsService.postFormInstance(formInstance);
}
throw new Error("template unknown");
throw new Error(t("TemplateUnknown") as string);
}
}, [form, template, formInstanceId]);
}, [form, template, formInstanceId, t]);
useImperativeHandle(ref, () => ({
hasValidationErrors,

View File

@ -1,644 +0,0 @@
export * from "./formHelpers.tsx";
/*
import React from "react";
import Input, { InputType } from "./Input";
import ToggleSlider from "./ToggleSlider";
import Select from "./Select";
import Option from "./option";
import { GeneralIdRef } from "../../utils/GeneralIdRef";
import SequencePicker from "../pickers/SequencePicker";
import GlossaryPicker from "../pickers/GlossaryPicker";
import CustomFieldsEditor, { CustomFieldEditorAdd, CustomFieldEditorDelete } from "./CustomFieldsEditor";
import { CustomField, numberParams, textParams } from "../../modules/manager/customfields/services/customFieldsService";
import FormTemplatePicker from "../pickers/FormTemplatePicker";
import { CustomFieldValue } from "../../modules/manager/glossary/services/glossaryService";
import TemplateEditor from "./TemplateEditor";
import DomainPicker from "../pickers/DomainPicker";
import UserPicker from "../pickers/UserPicker";
import Button, { ButtonType } from "./Button";
import Expando from "./expando";
import ErrorBlock from "./ErrorBlock";
import SsoProviderPicker from "../pickers/SsoProviderPicker";
import { FormData, FormError } from "./useForm";
export const renderButton = (
label: string,
errors: FormError,
name?: string,
onClick?: (keyValue: any) => void,
testid?: string,
enabled: boolean = true,
buttonType: ButtonType = ButtonType.primary,
overrideErrorChecking: boolean = false
) => {
let disabled = !enabled || Object.keys(errors).filter((x) => !x.startsWith("_")).length > 0;
if (overrideErrorChecking) disabled = !enabled;
return (
<Button testid={testid} disabled={disabled} name={name ?? label} buttonType={buttonType} onClick={onClick}>
{label}
</Button>
);
};
export const renderError = (name: string, errors: FormError) => {
return <ErrorBlock error={errors[name]} />;
};
export const renderInput = (
name: string,
label: string,
data: FormData,
errors: FormError,
type: InputType = InputType.text,
readOnly = false,
defaultValue: string = "",
placeHolder: string = "",
maxLength: number = 0,
visible: boolean = true,
autoComplete: string | undefined = undefined,
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
) => {
let value = data[name];
let cleanValue: string | undefined;
if (value === undefined) {
cleanValue = defaultValue;
} else if (typeof value === "string") {
cleanValue = value as string;
} else if (typeof value === "number") {
cleanValue = String(value);
} else if (typeof value === "boolean") {
cleanValue = String(value);
} else if (value as CustomFieldValue) {
cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
}
if (readOnly) {
return (
<Input
includeLabel={true}
type={type}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
maxLength={maxLength}
readOnly
placeHolder={placeHolder}
hidden={!visible}
autoComplete={autoComplete}
/>
);
} else {
return (
<Input
includeLabel={true}
type={type}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
maxLength={maxLength}
onChange={onChange}
placeHolder={placeHolder}
hidden={!visible}
autoComplete={autoComplete}
/>
);
}
};
export const renderInputWithChangeEvent = (
name: string,
label: string,
data: FormData,
errors: FormError,
type: InputType = InputType.text,
readOnly = false,
handleChangeEvent?: (e: React.ChangeEvent<HTMLInputElement>) => void,
defaultValue: string = "",
placeHolder: string = "",
maxLength: number = 0
) => {
let value = data[name];
let cleanValue: string | undefined;
if (value === undefined) {
cleanValue = defaultValue;
} else if (typeof value === "string") {
cleanValue = value as string;
} else if (typeof value === "number") {
cleanValue = String(value);
} else if (typeof value === "boolean") {
cleanValue = String(value);
} else if (value as CustomFieldValue) {
cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
}
if (readOnly) {
return (
<Input
includeLabel={true}
type={type}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
maxLength={maxLength}
readOnly
placeHolder={placeHolder}
/>
);
} else {
return (
<Input
includeLabel={true}
type={type}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
maxLength={maxLength}
onChange={handleChangeEvent}
placeHolder={placeHolder}
/>
);
}
};
export const renderInputNumber = (
name: string,
label: string,
data: FormData,
errors: FormError,
readOnly = false,
defaultValue: string = "",
min?: number,
max?: number,
step: number = 1,
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
) => {
let value = data[name];
let cleanValue: string | undefined;
if (value === undefined) {
cleanValue = defaultValue;
} else if (typeof value === "string") {
cleanValue = value as string;
} else if (typeof value === "number") {
cleanValue = String(value);
} else if (typeof value === "boolean") {
cleanValue = String(value);
} else if (value as CustomFieldValue) {
cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
}
if (readOnly) {
return <Input includeLabel={true} type={InputType.number} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
} else {
return (
<Input
includeLabel={true}
type={InputType.number}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
min={min}
max={max}
step={step}
onChange={onChange}
/>
);
}
};
export const renderInputTextarea = (
includeLabel: boolean,
name: string,
label: string,
data: FormData,
errors: FormError,
readOnly = false,
defaultValue: string = "",
onTextAreaChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void
) => {
let value = data[name];
let cleanValue: string | undefined;
if (value === undefined) {
cleanValue = defaultValue;
} else if (typeof value === "string") {
cleanValue = value as string;
}
if (readOnly) {
return (
<Input
includeLabel={includeLabel}
type={InputType.textarea}
key={name}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
readOnly
/>
);
} else {
return (
<Input
includeLabel={includeLabel}
type={InputType.textarea}
key={name}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
onTextAreaChange={onTextAreaChange}
/>
);
}
};
export const renderCustomFieldInput = (
includeLabel: boolean,
name: string,
label: string,
data: FormData,
errors: FormError,
type: InputType = InputType.text,
readOnly = false,
defaultValue: string = "",
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
) => {
let value = data[name];
let cleanValue: string | undefined;
if (value === undefined) {
cleanValue = defaultValue;
} else if (typeof value === "string") {
cleanValue = value as string;
} else if (typeof value === "number") {
cleanValue = String(value);
} else if (typeof value === "boolean") {
cleanValue = String(value);
} else if (value as CustomFieldValue) {
const customFieldValue = value as CustomFieldValue[];
cleanValue = customFieldValue[0].displayValue ?? customFieldValue[0].value?.toString();
}
if (readOnly) {
return <Input includeLabel={includeLabel} type={type} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
} else {
return (
<Input
includeLabel={includeLabel}
type={type}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
onChange={onChange}
/>
);
}
};
export const renderCustomFieldNumber = (
includeLabel: boolean,
name: string,
label: string,
data: FormData,
errors: FormError,
readOnly = false,
defaultValue: string = "",
min?: number,
max?: number,
step: number = 1,
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
) => {
let values: CustomFieldValue[] = data[name] as CustomFieldValue[];
let value: CustomFieldValue | undefined = undefined;
if (values) {
if (values.length > 0) {
value = values[0];
}
}
let cleanValue: string | undefined;
if (value === undefined) {
cleanValue = defaultValue;
} else if (typeof value === "string") {
cleanValue = value as string;
} else if (typeof value === "number") {
cleanValue = String(value);
} else if (value as CustomFieldValue) {
cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value?.toString();
}
if (readOnly) {
return <Input includeLabel={includeLabel} type={InputType.number} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
} else {
return (
<Input
includeLabel={includeLabel}
type={InputType.number}
name={name}
label={label}
value={cleanValue}
error={errors[name]}
min={min}
max={max}
step={step}
onChange={onChange}
/>
);
}
};
export const renderTemplateEditor = (
className: string,
name: string,
label: string,
data: FormData,
allowCustomFields: boolean,
onChange?: (name: string, value: string) => void
) => {
let value = data[name] as string;
return (
<div>
<label htmlFor={name}>{label}</label>
<TemplateEditor className={className} name={name} data={value} onChange={onChange} showFields={allowCustomFields} />
</div>
);
};
export const renderSelect = (
name: string,
label: string,
data: FormData,
errors: FormError,
options: Option[],
onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void
) => {
return <Select name={name} label={label} value={data[name]} options={options} error={errors[name]} onChange={onChange} />;
};
export const renderToggle = (
name: string,
label: string,
data: FormData,
errors: FormError,
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
) => {
return <ToggleSlider name={name} label={label} defaultChecked={Boolean(data[name])} error={errors[name]} onChange={onChange} />;
};
export const renderSequencePicker = (
includeLabel: boolean,
name: string,
label: string,
data: FormData,
errors: FormError,
onChange?: (name: string, value: GeneralIdRef) => void
) => {
return (
<SequencePicker includeLabel={includeLabel} name={name} label={label} value={data[name]} error={errors[name]} onChange={onChange} />
);
};
export const renderGlossaryPicker = (
includeLabel: boolean,
name: string,
label: string,
data: FormData,
errors: FormError,
maxEntries?: number,
refElementId?: GeneralIdRef,
onChange?: (name: string, values: CustomFieldValue[]) => void
) => {
const glossaryValues: CustomFieldValue[] | undefined = data[name] as any as CustomFieldValue[];
return (
<GlossaryPicker
includeLabel={includeLabel}
name={name}
label={label}
maxEntries={maxEntries}
values={glossaryValues}
error={errors[name]}
rootItem={refElementId}
onChange={onChange}
/>
);
};
export const renderDomainPicker = (
includeLabel: boolean,
name: string,
label: string,
data: FormData,
errors: FormError,
minEntries: number,
maxEntries?: number,
onChange?: (name: string, values: CustomFieldValue[]) => void
) => {
const domainValues: CustomFieldValue[] | undefined = data[name] as any as CustomFieldValue[];
return (
<DomainPicker
includeLabel={includeLabel}
name={name}
label={label}
minEntries={minEntries}
maxEntries={maxEntries}
values={domainValues}
error={errors[name]}
onChange={onChange}
/>
);
};
export const renderTemplatePicker = (
includeLabel: boolean,
name: string,
label: string,
data: FormData,
errors: FormError,
onChange?: (name: string, value: GeneralIdRef) => void
) => {
const templateValue: GeneralIdRef = data[name] as any as GeneralIdRef;
return (
<FormTemplatePicker
includeLabel={includeLabel}
name={name}
label={label}
value={templateValue}
error={errors[name]}
onChange={onChange}
/>
);
};
export const renderUserPicker = (
name: string,
label: string,
data: FormData,
errors: FormError,
onChange?: (name: string, value: GeneralIdRef) => void
) => {
const glossaryValue: GeneralIdRef | undefined = data[name] as any as GeneralIdRef;
return <UserPicker name={name} label={label} value={glossaryValue} error={errors[name]} onChange={onChange} />;
};
export const renderSsoProviderPicker = (
name: string,
label: string,
data: FormData,
errors: FormError,
onChange?: (name: string, value: GeneralIdRef) => void
) => {
const glossaryValue: GeneralIdRef | undefined = data[name] as any as GeneralIdRef;
return <SsoProviderPicker name={name} label={label} value={glossaryValue} error={errors[name]} onChange={onChange} />;
};
export const renderCustomFieldsEditor = (
name: string,
label: string,
data: FormData,
errors: FormError,
selected: CustomField[],
onAdd: CustomFieldEditorAdd,
onDelete: CustomFieldEditorDelete
) => {
return (
<CustomFieldsEditor name={name} label={label} value={data[name] as []} error={errors[name]} exclude={selected} onAdd={onAdd} onDelete={onDelete} />
);
};
export const renderCustomField = (
customField: CustomField,
includeLabel: boolean,
data: FormData,
errors: FormError,
onChange: (e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void,
onPickerChange: (name: string, value: GeneralIdRef | CustomFieldValue[]) => void,
getCustomFieldType: (field: CustomFieldValue, customFields: CustomField[]) => string
) => {
switch (customField.fieldType.toLowerCase()) {
case "text":
const textParameters: textParams = JSON.parse(customField.parameters!);
if (textParameters.multiLine) {
return renderInputTextarea(
includeLabel,
"customfield_" + customField.id,
customField.name,
data,
errors,
false,
customField.defaultValue,
onChange as (e: React.ChangeEvent<HTMLTextAreaElement>) => void
);
} else {
return renderCustomFieldInput(
includeLabel,
"customfield_" + customField.id,
customField.name,
data,
errors,
InputType.text,
false,
customField.defaultValue,
onChange as (e: React.ChangeEvent<HTMLInputElement>) => void
);
}
case "sequence":
return renderCustomFieldInput(includeLabel, "customfield_" + customField.id, customField.name, data, errors, InputType.text, true);
case "formtemplate":
return renderTemplatePicker(
includeLabel,
"customfield_" + customField.id,
customField.name,
data,
errors,
(name, value) => onPickerChange(name, value)
);
case "glossary":
return renderGlossaryPicker(
includeLabel,
"customfield_" + customField.id,
customField.name,
data,
errors,
customField.maxEntries,
customField.refElementId,
(name, values) => onPickerChange(name, values)
);
case "number":
const numberParameters: numberParams = JSON.parse(customField.parameters!);
return renderCustomFieldNumber(
includeLabel,
"customfield_" + customField.id,
customField.name,
data,
errors,
false,
customField.defaultValue,
numberParameters.minValue ? Number(numberParameters.minValue) : undefined,
numberParameters.maxValue ? Number(numberParameters.maxValue) : undefined,
numberParameters.step ? Number(numberParameters.step) : undefined,
onChange as (e: React.ChangeEvent<HTMLInputElement>) => void
);
case "domain":
return renderDomainPicker(
includeLabel,
"customfield_" + customField.id,
customField.name,
data,
errors,
customField.minEntries,
customField.maxEntries,
(name, values) => onPickerChange(name, values)
);
default:
return <>{customField.name + " " + customField.fieldType}</>;
}
};
export const renderCustomFields = (
customFields: CustomField[] | undefined,
data: FormData,
errors: FormError,
onChange: (e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void,
onPickerChange: (name: string, value: GeneralIdRef | CustomFieldValue[]) => void,
getCustomFieldType: (field: CustomFieldValue, customFields: CustomField[]) => string
) => {
if (customFields === undefined) return <></>;
let customFieldsBlock: JSX.Element[] = [];
for (const customField of customFields) {
customFieldsBlock.push(
renderCustomField(customField, true, data, errors, onChange, onPickerChange, getCustomFieldType)
);
}
return <>{customFieldsBlock.map((x) => x)}</>;
};
export const renderDropSection = (name: string, title: JSX.Element, content: JSX.Element, errors: FormError) => {
return (
<Expando name={name} title={title} error={errors[name]}>
{content}
</Expando>
);
};
*/

View File

@ -5,6 +5,8 @@ import AuditTable from "./components/auditTable";
import auditService, { AuditLogEntry } from "./services/auditService";
import Loading from "../../components/common/Loading";
import { useLocation, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../i18n/i18n";
const useQuery = () => new URLSearchParams(useLocation().search);
@ -12,6 +14,7 @@ export default function Audit() {
const location = useLocation();
const params = useParams();
const query = useQuery();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] = useState<Paginated<AuditLogEntry>>({
@ -24,7 +27,7 @@ export default function Audit() {
const [sortColumn, setSortColumn] = useState<Column<AuditLogEntry>>({
key: "dateTime",
label: "Timing",
label: t("Timing"),
order: "desc",
});
@ -95,12 +98,12 @@ export default function Audit() {
setSortColumn({
key: "dateTime",
label: "Timing",
label: t("Timing"),
order: "desc",
});
setLoaded(false);
}, [location.search, params.auditId]);
}, [location.search, params.auditId, t]);
return (
<Loading loaded={loaded}>

View File

@ -47,7 +47,7 @@ const ErrorLogs = (): JSX.Element => {
useEffect(() => {
loadErrorLogs(pagedData.page, pagedData.pageSize, sortColumn, filters);
}, [loadErrorLogs]);
}, [filters, loadErrorLogs, pagedData.page, pagedData.pageSize, sortColumn]);
const changePage = useCallback(
async (page: number, pageSize: number) => {

View File

@ -5,7 +5,6 @@ import { InputType } from "../../../components/common/Input";
import Input from "../../../components/common/Input";
import Button, { ButtonType } from "../../../components/common/Button";
import ErrorBlock from "../../../components/common/ErrorBlock";
import { FormData } from "../../../components/common/Form";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";

View File

@ -1,7 +1,6 @@
import React, { useState } from "react";
import authentication from "../services/authenticationService";
import { IEmailUserAction } from "../models/IEmailUserAction";
import { FormData } from "../../../components/common/Form";
import Button, { ButtonType } from "../../../components/common/Button";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";

View File

@ -2,7 +2,6 @@ import React, { useState } from "react";
import { InputType } from "../../../components/common/Input";
import { IEmailUserAction } from "../models/IEmailUserAction";
import authentication from "../services/authenticationService";
import { FormData } from "../../../components/common/Form";
import Input from "../../../components/common/Input";
import Button, { ButtonType } from "../../../components/common/Button";
import ErrorBlock from "../../../components/common/ErrorBlock";

View File

@ -1,5 +1,4 @@
import React, { useState } from "react";
import { FormData } from "../../../components/common/Form";
import authentication from "../services/authenticationService";
import Input, { InputType } from "../../../components/common/Input";
import Button, { ButtonType } from "../../../components/common/Button";

View File

@ -10,8 +10,11 @@ import {
renderError,
renderInput,
} from "../../../components/common/formHelpers";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
const LoginForm: React.FC = () => {
const { t } = useTranslation<typeof Namespaces.Common>();
const [isInNextStage, setIsInNextStage] = useState(false);
const [emailSent, setEmailSent] = useState(false);
const passwordMaxLength = 255;
@ -33,11 +36,11 @@ const LoginForm: React.FC = () => {
username: Joi.string()
.required()
.email({ tlds: { allow: false } })
.label("Email"),
password: Joi.string().required().label("Password"),
.label(t("Email")),
password: Joi.string().required().label(t("Password")),
tfaNeeded: Joi.boolean().required(),
requestTfaRemoval: Joi.boolean().required(),
securityCode: Joi.string().allow("").label("Authenticate"),
securityCode: Joi.string().allow("").label(t("Authenticate")),
};
form.schema = schema;
@ -137,7 +140,7 @@ const LoginForm: React.FC = () => {
InputType.text,
isInNextStage,
"",
"Email",
t("Email") as string,
0,
true,
"username",
@ -151,7 +154,7 @@ const LoginForm: React.FC = () => {
InputType.password,
emailSent,
"",
"Password",
t("Password") as string,
passwordMaxLength,
isInNextStage,
"current-password",
@ -159,7 +162,7 @@ const LoginForm: React.FC = () => {
)}
{!isInNextStage &&
renderButton(
"Next",
t("Next"),
form.state.errors,
"next",
handleNextClick,
@ -184,7 +187,7 @@ const LoginForm: React.FC = () => {
{isInNextStage && (
<div className="forgottenLink">
{renderButton(
"Forgotten Password",
t("ForgottenPassword") as string,
form.state.errors,
"forgot-password",
handleForgetPassword,
@ -209,7 +212,7 @@ const LoginForm: React.FC = () => {
{renderError("_general", form.state.errors)}
{renderInput(
"securityCode",
"Authenticate",
t("Authenticate") as string,
form.state.data,
form.state.errors,
InputType.text,
@ -221,7 +224,7 @@ const LoginForm: React.FC = () => {
undefined,
form.handleChange,
)}
{renderButton("Authenticate", form.state.errors, "authenticate")}
{renderButton(t("Authenticate"), form.state.errors, "authenticate")}
<Link to="#" onClick={authenticationWorkAround}>
My Authenticator is not working
</Link>

View File

@ -1,9 +1,10 @@
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import authentication from "../services/authenticationService";
const Logout: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
useEffect(() => {
authentication.logout();

View File

@ -1,8 +1,9 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
const NotFound: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
return <h1>{t("NotFound")}</h1>;
};

View File

@ -1,8 +1,9 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../i18n/i18n";
const HomePage: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const redirect = () => {
window.location.href = "/organisations";

View File

@ -1,5 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -10,7 +11,7 @@ import { CustomField } from "../services/customFieldsService";
const CustomFieldsTable: React.FC<PublishedTableProps<CustomField>> = (
props,
) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<CustomField>[] = [
{ key: "name", label: t("Name"), order: "asc" },

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { InputType } from "../../../components/common/Input";
import { useForm } from "../../../components/common/useForm";
import {
@ -35,21 +37,22 @@ const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
editMode = false,
}) => {
const { customFieldId } = useParams<{ customFieldId: string }>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelFieldType = "Field Type";
const labelMultiLine = "Multi-line";
const labelDefaultValue = "Default Value";
const labelMinValue = "Minimum Value";
const labelMaxValue = "Maximum Value";
const labelStep = "Step";
const labelRequired = "Required";
const labelMinEntries = "Min Entries";
const labelMaxEntries = "Max Entries (empty=unlimited)";
let labelRefElementId = "Sequence/Form/Glossary";
const labelName = t("Name");
const labelFieldType = t("FieldType");
const labelMultiLine = t("MultiLine");
const labelDefaultValue = t("DefaultValue");
const labelMinValue = t("MinimumValue");
const labelMaxValue = t("MaximumValue");
const labelStep = t("Step");
const labelRequired = t("Required");
const labelMinEntries = t("MinEntries");
const labelMaxEntries = t("MaxEntriesEmptyUnlimited");
let labelRefElementId = t("SequenceFormGlossary");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -111,22 +114,14 @@ const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
then: Joi.number(),
otherwise: Joi.number()
.min(Joi.ref("minValue"))
.message(
'"Default Value" must be greater than or equal to "' +
labelMinValue +
'"',
),
.message(t("DefaultMustBeGreaterThanOrEqualToMinimumValue")),
})
.when("maxValue", {
is: Joi.any().valid(null, ""),
then: Joi.number(),
otherwise: Joi.number()
.max(Joi.ref("maxValue"))
.message(
'"Default Value" must be less than or equal to "' +
labelMaxValue +
'"',
),
.message(t("DefaultMustBeLessThanOrEqualToMaximumValue")),
})
.allow(""),
otherwise: Joi.string().allow(""),
@ -305,7 +300,7 @@ const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
params,
);
if (response) {
toast.info("Custom Field edited");
toast.info(t("CustomFieldEdited"));
}
} else {
const response = await customFieldsService.postField(
@ -318,7 +313,7 @@ const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
params,
);
if (response) {
toast.info("New Custom Field added");
toast.info(t("NewCustomFieldAdded"));
}
}
@ -337,33 +332,35 @@ const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
const { fieldType } = form.state.data;
const fieldTypeValue = typeof fieldType === "string" ? fieldType : "";
let mode = "Add";
if (isEditMode()) mode = "Edit";
let mode = t("Add");
if (isEditMode()) mode = t("Edit");
const fieldTypeOptions: Option[] = [
{ _id: "Text", name: "Text" },
{ _id: "Number", name: "Number" },
{ _id: "Sequence", name: "Sequence" },
{ _id: "FormTemplate", name: "Form Template" },
{ _id: "Glossary", name: "Glossary" },
{ _id: "Domain", name: "Domain" },
{ _id: "Text", name: t("Text") },
{ _id: "Number", name: t("Number") },
{ _id: "Sequence", name: t("Sequence") },
{ _id: "FormTemplate", name: t("FormTemplate") },
{ _id: "Glossary", name: t("Glossary") },
{ _id: "Domain", name: t("Domain") },
];
switch (fieldTypeValue) {
case "Sequence":
labelRefElementId = "Sequence";
labelRefElementId = t("Sequence");
break;
case "FormTemplate":
labelRefElementId = "Form";
labelRefElementId = t("Form");
break;
case "Glossary":
labelRefElementId = "Glossary";
labelRefElementId = t("Glossary");
break;
}
return (
<Loading loaded={form.state.loaded}>
<h1>{mode} Custom Field</h1>
<h1>
{mode} {t("CustomField")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,5 +1,6 @@
import React, { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import Column from "../../../components/common/columns";
import { Paginated } from "../../../services/Paginated";
import CustomFieldsTable from "./components/CustomFieldsTable";
@ -18,17 +19,18 @@ const initialPagedData: Paginated<CustomField> = {
data: [],
};
const initialSortColumn: Column<CustomField> = {
key: "name",
label: "Name",
order: "asc",
};
const CustomFields: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] =
useState<Paginated<CustomField>>(initialPagedData);
const initialSortColumn: Column<CustomField> = {
key: "name",
label: t("Name"),
order: "asc",
};
const [sortColumn, setSortColumn] =
useState<Column<CustomField>>(initialSortColumn);
const [filters, setFilters] = useState<Map<string, string>>(
@ -53,7 +55,7 @@ const CustomFields: React.FC = () => {
};
void loadInitial();
}, []);
}, [initialSortColumn.key, initialSortColumn.order]);
const changePage = async (page: number, pageSize: number) => {
const pagedDataResult = await customFieldsService.getFields(

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import Column from "../../../components/common/columns";
import { Paginated } from "../../../services/Paginated";
import DomainsTable from "./components/domainsTable";
@ -17,7 +18,7 @@ const initialPagedData: Paginated<GetDomain> = {
};
const Domains: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] =
useState<Paginated<GetDomain>>(initialPagedData);

View File

@ -1,5 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useSearchParams } from "react-router-dom";
import HorizontalTabs from "../../../components/common/HorizionalTabs";
import Tab from "../../../components/common/Tab";
@ -9,17 +10,17 @@ import MailTemplatesTab from "./components/MailTemplatesTab";
import SecurityRolesTab from "./components/SecurityRolesTab";
interface DomainsDetailsProps {
editMode: boolean;
isEditMode: boolean;
}
const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
const { t } = useTranslation();
const DomainsDetails: React.FC<DomainsDetailsProps> = ({ isEditMode }) => {
const { t } = useTranslation<typeof Namespaces.Common>();
const [searchParams] = useSearchParams();
const canViewMailTemplates = authentication.hasAccess("ViewDomain");
const canViewSecurityRoles = authentication.hasAccess("ViewRole");
const heading = editMode ? t("EditDomain") : t("AddDomain");
const heading = isEditMode ? t("EditDomain") : t("AddDomain");
const initialTab = searchParams.get("tab") || undefined;
const roleId = searchParams.get("roleId") || undefined;
const innerTab = searchParams.get("innerTab") || undefined;
@ -28,11 +29,11 @@ const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
tabs.push(
<Tab key={1} label={t("General")}>
<GeneralTab isEditMode={editMode} />
<GeneralTab isEditMode={isEditMode} />
</Tab>,
);
if (editMode) {
if (isEditMode) {
if (canViewMailTemplates) {
tabs.push(
<Tab key={2} label={t("MailTemplates")}>

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import { useForm } from "../../../../components/common/useForm";
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
import roleService from "../serrvices/rolesService";
@ -21,10 +23,11 @@ const AddUserToRole: React.FC<LocAddUserToRoleProps> = ({ isEditMode }) => {
domainId: string;
roleId: string;
}>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelUserId = "User";
const labelApply = "Save";
const labelSave = "Save and close";
const labelUserId = t("User");
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: true,
@ -48,7 +51,7 @@ const AddUserToRole: React.FC<LocAddUserToRoleProps> = ({ isEditMode }) => {
MakeGeneralIdRef(BigInt(roleId!)),
);
if (response) {
toast.info("User added to role");
toast.info(t("UserAddedToRole"));
if (buttonName === labelSave)
form.setState({

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import { useForm } from "../../../../components/common/useForm";
import { InputType } from "../../../../components/common/Input";
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
@ -22,10 +24,12 @@ const EmailTemplateEditor: React.FC<EmailTemplateEditorProps> = ({
domainId,
currentMailType,
}) => {
const labelName = "Subject";
const labelDefinition = "Definition";
const labelApply = "Save";
const labelSave = "Save and close";
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = t("Subject");
const labelDefinition = t("Definition");
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -101,7 +105,7 @@ const EmailTemplateEditor: React.FC<EmailTemplateEditorProps> = ({
definitionStr,
);
if (response) {
toast.info("Email Template saved");
toast.info(t("EmailTemplateSaved"));
if (buttonName === labelSave) form.setState({ redirect: "/domains" });
}
} catch (ex: any) {
@ -122,14 +126,10 @@ const EmailTemplateEditor: React.FC<EmailTemplateEditorProps> = ({
<>
<div style={{ position: "relative" }}>
{isOverriddenValue && (
<p>This template is custom for this domain only</p>
<p>{t("ThisTemplateIsCustomForThisDomainOnly")}</p>
)}
{!isOverriddenValue && (
<p>
The details below are loaded from the master template. Saving this
template will mean that any changes to the master template will not
automatically appear here.
</p>
<p>{t("TheDetailsBelowAreLoadedFromMasterTemplate")}</p>
)}
<form

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import { useForm } from "../../../../components/common/useForm";
import { InputType } from "../../../../components/common/Input";
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
@ -20,16 +22,17 @@ interface GeneralTabProps {
const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
const { domainId } = useParams<{ domainId: string }>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelSsoProvider = "Sso Provider";
const labelSunriseHostName = "e-flow hostname";
const labelSunriseAppId = "e-flow AppId";
const labelSunriseCategoryId = "e-flow CategoryId";
const labelSigmaId = "Sigma Id";
const labelName = t("Name");
const labelSsoProvider = t("SsoProvider");
const labelSunriseHostName = t("EFlowHostname");
const labelSunriseAppId = t("EFlowAppId");
const labelSunriseCategoryId = t("EFlowCategoryId");
const labelSigmaId = t("SigmaId");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -97,7 +100,7 @@ const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
sigmaIdValue,
);
if (response) {
toast.info("Domain edited");
toast.info(t("DomainEdited"));
}
} else {
const response = await domainsService.postDomain(
@ -109,7 +112,7 @@ const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
sigmaIdValue,
);
if (response) {
toast.info("New Domain added");
toast.info(t("NewDomainAdded"));
}
}

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import { toast } from "react-toastify";
import { Paginated } from "../../../../services/Paginated";
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
@ -31,7 +32,7 @@ interface RoleAccessEditorProps {
}
const RoleAccessEditor: React.FC<RoleAccessEditorProps> = ({ role }) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [accessList, setAccessList] =
useState<Paginated<GetSecurityAccess>>(initialAccessList);

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import { useForm } from "../../../../components/common/useForm";
import { InputType } from "../../../../components/common/Input";
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
@ -22,10 +24,11 @@ const RolesDetails: React.FC<RolesDetailsProps> = ({ isEditMode }) => {
domainId: string;
roleId: string;
}>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelApply = "Save";
const labelSave = "Save and close";
const labelName = t("Name");
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -51,7 +54,7 @@ const RolesDetails: React.FC<RolesDetailsProps> = ({ isEditMode }) => {
var generalIdRef = MakeGeneralIdRef(BigInt(roleId!));
const response = await roleService.putRole(generalIdRef, nameStr);
if (response) {
toast.info("Role edited");
toast.info(t("RoleEdited"));
}
} else {
const response = await roleService.postRole(
@ -59,7 +62,7 @@ const RolesDetails: React.FC<RolesDetailsProps> = ({ isEditMode }) => {
nameStr,
);
if (response) {
toast.info("New Role added");
toast.info(t("NewRoleAdded"));
}
}
@ -102,12 +105,14 @@ const RolesDetails: React.FC<RolesDetailsProps> = ({ isEditMode }) => {
const { loaded, redirect } = form.state;
if (redirect) return <Navigate to={redirect} />;
let mode = "Add";
if (isEditMode) mode = "Edit";
let mode = t("Add");
if (isEditMode) mode = t("Edit");
return (
<Loading loaded={loaded}>
<h1>{mode} Role</h1>
<h1>
{mode} {t("Role")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import { Paginated } from "../../../../services/Paginated";
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
@ -31,7 +32,7 @@ const RolesEditor: React.FC<RolesEditorProps> = ({
onUnselectRole,
initialRoleId,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] =
useState<Paginated<GetRoleResponse>>(initialPagedData);

View File

@ -1,5 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -8,7 +9,7 @@ import authentication from "../../../frame/services/authenticationService";
import { GetRoleResponse } from "../serrvices/rolesService";
const RolesTable: React.FC<PublishedTableProps<GetRoleResponse>> = (props) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<GetRoleResponse>[] = [
{ key: "name", label: t("Name"), order: "asc" },

View File

@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -21,7 +22,7 @@ const RollAccessTable: React.FC<RollAccessTableProps> = ({
onSort,
data,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [deltaAdditions, setDeltaAdditions] = useState<string[]>([]);
const [deltaDeletions, setDeltaDeletions] = useState<string[]>([]);

View File

@ -1,5 +1,6 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import HorizontalTabs from "../../../../components/common/HorizionalTabs";
import Tab from "../../../../components/common/Tab";
import RoleAccessEditor from "./RoleAccessEditor";
@ -17,7 +18,7 @@ const SecurityRolesTab: React.FC<SecurityRolesTabProps> = ({
initialRoleId,
initialInnerTab,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [selectedRole, setSelectedRole] = useState<GetRoleResponse | undefined>(
undefined,
);

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import { Paginated } from "../../../../services/Paginated";
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
@ -22,7 +23,7 @@ interface UserRoleEditorProps {
}
const UserRoleEditor: React.FC<UserRoleEditorProps> = ({ role }) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] =
useState<Paginated<RoleUser>>(initialPagedData);

View File

@ -1,5 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -8,7 +9,7 @@ import authentication from "../../../frame/services/authenticationService";
import { RoleUser } from "../serrvices/rolesService";
const UserRolesTable: React.FC<PublishedTableProps<RoleUser>> = (props) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<RoleUser>[] = [
{ key: "displayName", label: t("Name"), order: "asc" },

View File

@ -1,5 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -8,7 +9,7 @@ import authentication from "../../../frame/services/authenticationService";
import { GetDomain } from "../serrvices/domainsService";
const DomainsTable: React.FC<PublishedTableProps<GetDomain>> = (props) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<GetDomain>[] = [
{ key: "name", label: t("Name"), order: "asc" },

View File

@ -1,5 +1,6 @@
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import Button, { ButtonType } from "../../../components/common/Button";
import Column from "../../../components/common/columns";
import Permission from "../../../components/common/Permission";
@ -9,7 +10,7 @@ import formsService, { GetFormResponse } from "./services/formsService";
import Loading from "../../../components/common/Loading";
const Forms: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] = useState<Paginated<GetFormResponse>>({

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useForm } from "../../../components/common/useForm";
import { InputType } from "../../../components/common/Input";
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
@ -18,12 +20,13 @@ const FormsDetails: React.FC<{ editMode?: boolean }> = ({
editMode = false,
}) => {
const { formId } = useParams<{ formId: string }>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelDefinition = "Definition";
const labelName = t("Name");
const labelDefinition = t("Definition");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -80,12 +83,12 @@ const FormsDetails: React.FC<{ editMode?: boolean }> = ({
definitionStr,
);
if (response) {
toast.info("Form template edited");
toast.info(t("FormTemplateEdited"));
}
} else {
const response = await formsService.postForm(nameStr, definitionStr);
if (response) {
toast.info("New Form Template added");
toast.info(t("NewFormTemplateAdded"));
}
}
@ -102,12 +105,14 @@ const FormsDetails: React.FC<{ editMode?: boolean }> = ({
const { loaded, redirect } = form.state;
if (redirect) return <Navigate to={redirect} />;
let mode = "Add";
if (editMode) mode = "Edit";
let mode = t("Add");
if (editMode) mode = t("Edit");
return (
<Loading loaded={loaded}>
<h1>{mode} Form Template</h1>
<h1>
{mode} {t("FormTemplate")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,5 +1,6 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -15,7 +16,7 @@ const FormsTable: React.FC<PublishedTableProps<GetFormResponse>> = ({
onDelete,
onSort,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<GetFormResponse>[] = useMemo(
() => [

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useForm } from "../../../components/common/useForm";
import { InputType } from "../../../components/common/Input";
import { GeneralIdRef, MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
@ -28,12 +30,13 @@ const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
editMode = false,
}) => {
const { glossaryId } = useParams<{ glossaryId: string }>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelChildCustomFieldDefinition = "Custom field for child entries";
const labelName = t("Name");
const labelChildCustomFieldDefinition = t("CustomFieldForChildEntries");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -159,7 +162,7 @@ const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
customfieldValues,
);
if (response) {
toast.info("Glossary Item edited");
toast.info(t("GlossaryItemEdited"));
}
} else {
const generalIdRef = parentGlossary
@ -172,7 +175,7 @@ const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
customfieldValues,
);
if (response) {
toast.info("New Glossary Item added");
toast.info(t("NewGlossaryItemAdded"));
}
}
@ -191,8 +194,8 @@ const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
const { loaded, redirect, data } = form.state;
if (redirect) return <Navigate to={redirect} />;
let mode = "Add";
if (editMode) mode = "Edit";
let mode = t("Add");
if (editMode) mode = t("Edit");
const parentGlossary = data.parent as Glossary | undefined;
const handleCustomFieldChange = (
@ -223,7 +226,9 @@ const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
return (
<Loading loaded={loaded}>
<h1>{mode} Glossary Item</h1>
<h1>
{mode} {t("GlossaryItem")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
import GlossariesTable from "./components/GlossariesTable";
import glossariesService, {
@ -13,7 +14,7 @@ import Loading from "../../../components/common/Loading";
import Permission from "../../../components/common/Permission";
const Glossaries: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const { glossaryId } = useParams<{ glossaryId: string }>();
const [loaded, setLoaded] = useState(false);

View File

@ -1,5 +1,6 @@
import React, { useState, useEffect, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table from "../../../../components/common/Table";
import { Glossary } from "../services/glossaryService";
@ -22,7 +23,7 @@ const GlossariesTable: React.FC<GlossariesTableProps> = ({
data,
onDelete,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [columnsList, setColumnsList] = useState<CustomColumn[]>([]);

View File

@ -1,6 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import Button, { ButtonType } from "../../../components/common/Button";
import { useTranslation } from "react-i18next";import { Namespaces } from "../../../i18n/i18n";import Button, { ButtonType } from "../../../components/common/Button";
import Column from "../../../components/common/columns";
import Permission from "../../../components/common/Permission";
import { Paginated } from "../../../services/Paginated";
@ -11,7 +10,7 @@ import organisationsService, {
import Loading from "../../../components/common/Loading";
const Organisations: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] = useState<Paginated<ReadOrganisation>>({
page: 1,

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useForm } from "../../../components/common/useForm";
import { InputType } from "../../../components/common/Input";
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
@ -19,18 +21,19 @@ const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
editMode = false,
}) => {
const { organisationId } = useParams<{ organisationId: string }>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelAddress = "Address";
const labelStatus = "Status";
const labelName = t("Name");
const labelAddress = t("Address");
const labelStatus = t("Status");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const organisationStatusOptions: Option[] = [
{ _id: "Active", name: "Active" },
{ _id: "Pending", name: "Pending" },
{ _id: "Blocked", name: "Blocked" },
{ _id: "Active", name: t("Active") },
{ _id: "Pending", name: t("Pending") },
{ _id: "Blocked", name: t("Blocked") },
];
const form = useForm({
@ -95,7 +98,7 @@ const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
statusStr,
);
if (response) {
toast.info("Organisation edited");
toast.info(t("OrganisationEdited"));
}
} else {
const response = await organisationsService.postOrganisation(
@ -104,7 +107,7 @@ const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
statusStr,
);
if (response) {
toast.info("New Organisation added");
toast.info(t("NewOrganisationAdded"));
}
}
@ -121,12 +124,14 @@ const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
const { loaded, redirect } = form.state;
if (redirect) return <Navigate to={redirect} />;
let mode = "Add";
if (editMode) mode = "Edit";
let mode = t("Add");
if (editMode) mode = t("Edit");
return (
<Loading loaded={loaded}>
<h1>{mode} Organisation</h1>
<h1>
{mode} {t("Organisation")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,5 +1,6 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -15,7 +16,7 @@ const OrganisationsTable: React.FC<PublishedTableProps<ReadOrganisation>> = ({
onDelete,
onSort,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const canViewSite = authentication.hasAccess("ViewSite");
const columns: Column<ReadOrganisation>[] = useMemo(

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useForm } from "../../../components/common/useForm";
import { InputType } from "../../../components/common/Input";
import {
@ -24,15 +26,16 @@ const SequenceDetails: React.FC<SequenceDetailsProps> = ({
editMode = false,
}) => {
const { sequenceId } = useParams<{ sequenceId: string }>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelSeed = "Seed";
const labelIncrement = "Increment";
const labelPattern = "Pattern";
const labelRolloverType = "Rollover Type";
const labelName = t("Name");
const labelSeed = t("Seed");
const labelIncrement = t("Increment");
const labelPattern = t("Pattern");
const labelRolloverType = t("RolloverType");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -110,7 +113,7 @@ const SequenceDetails: React.FC<SequenceDetailsProps> = ({
rolloverTypeStr,
);
if (response) {
toast.info("Sequence edited");
toast.info(t("SequenceEdited"));
}
} else {
const response = await sequenceService.postSequence(
@ -121,7 +124,7 @@ const SequenceDetails: React.FC<SequenceDetailsProps> = ({
rolloverTypeStr,
);
if (response) {
toast.info("New sequence added");
toast.info(t("NewSequenceAdded"));
}
}
@ -141,17 +144,19 @@ const SequenceDetails: React.FC<SequenceDetailsProps> = ({
if (redirect) return <Navigate to={redirect} />;
const rolloverOptions: Option[] = [
{ _id: "Continuous", name: "Continuous" },
{ _id: "Day", name: "Day" },
{ _id: "Month", name: "Month" },
{ _id: "Year", name: "Year" },
{ _id: "Continuous", name: t("Continuous") },
{ _id: "Day", name: t("Day") },
{ _id: "Month", name: t("Month") },
{ _id: "Year", name: t("Year") },
];
const mode = editMode ? "Edit" : "Add";
const mode = editMode ? t("Edit") : t("Add");
return (
<Loading loaded={loaded}>
<h1>{mode} Sequence</h1>
<h1>
{mode} {t("Sequence")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,5 +1,6 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -15,7 +16,7 @@ const SequenceTable: React.FC<PublishedTableProps<ReadSequence>> = ({
onDelete,
onSort,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<ReadSequence>[] = useMemo(
() => [{ key: "name", label: t("Name"), order: "asc" }],

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import sequenceService, { ReadSequence } from "./services/sequenceService";
import SequenceTable from "./components/squenceTable";
import Column from "../../../components/common/columns";
@ -9,7 +10,7 @@ import Loading from "../../../components/common/Loading";
import Permission from "../../../components/common/Permission";
const Sequence: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] = useState<Paginated<ReadSequence>>({
page: 1,

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useForm } from "../../../components/common/useForm";
import { InputType } from "../../../components/common/Input";
import {
@ -24,13 +26,14 @@ const SiteDetails: React.FC<SiteDetailsProps> = ({ editMode = false }) => {
organisationId: string;
siteId?: string;
}>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelAddress = "Address";
const labelStatus = "Status";
const labelName = t("Name");
const labelAddress = t("Address");
const labelStatus = t("Status");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -98,7 +101,7 @@ const SiteDetails: React.FC<SiteDetailsProps> = ({ editMode = false }) => {
organisationGeneralIdRef,
);
if (response) {
toast.info("Site edited");
toast.info(t("SiteEdited"));
}
} else {
const response = await siteService.postSite(
@ -108,7 +111,7 @@ const SiteDetails: React.FC<SiteDetailsProps> = ({ editMode = false }) => {
organisationGeneralIdRef,
);
if (response) {
toast.info("New site added");
toast.info(t("NewSiteAdded"));
}
}
@ -128,16 +131,18 @@ const SiteDetails: React.FC<SiteDetailsProps> = ({ editMode = false }) => {
if (redirect) return <Navigate to={redirect} />;
const organisationStatusOptions: Option[] = [
{ _id: "Active", name: "Active" },
{ _id: "Pending", name: "Pending" },
{ _id: "Blocked", name: "Blocked" },
{ _id: "Active", name: t("Active") },
{ _id: "Pending", name: t("Pending") },
{ _id: "Blocked", name: t("Blocked") },
];
const mode = editMode ? "Edit" : "Add";
const mode = editMode ? t("Edit") : t("Add");
return (
<Loading loaded={loaded}>
<h1>{mode} Site</h1>
<h1>
{mode} {t("Site")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useParams } from "react-router-dom";
import Column from "../../../components/common/columns";
import { Paginated } from "../../../services/Paginated";
@ -18,7 +19,7 @@ const initialPagedData: Paginated<ReadSite> = {
};
const Sites: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const { organisationId } = useParams<{ organisationId: string }>();
const [loaded, setLoaded] = useState(false);

View File

@ -1,5 +1,6 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -16,7 +17,7 @@ const SitesTable: React.FC<PublishedTableProps<ReadSite>> = ({
onDelete,
onSort,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<ReadSite>[] = useMemo(
() => [

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useParams } from "react-router-dom";
import Column from "../../../components/common/columns";
import { Paginated } from "../../../services/Paginated";
@ -20,7 +21,7 @@ const initialPagedData: Paginated<ReadSpecification> = {
};
const Specifications: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const { siteId } = useParams<{ siteId: string }>();
const [loaded, setLoaded] = useState(false);

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect, useRef, useState, useCallback } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useForm } from "../../../components/common/useForm";
import { InputType } from "../../../components/common/Input";
import Loading from "../../../components/common/Loading";
@ -33,13 +35,14 @@ const SpecificationsDetails: React.FC<SpecificationsDetailsProps> = ({
siteId: string;
specificationId?: string;
}>();
const { t } = useTranslation<typeof Namespaces.Common>();
const TemplateFillerRef = useRef<TemplateFillerHandle>(null);
const labelName = "Name";
const labelPrintSpecification = "Print Specification";
const labelSigmaId = "SigmaId";
const labelApply = "Save";
const labelSave = "Save and close";
const labelName = t("Name");
const labelPrintSpecification = t("PrintSpecification");
const labelSigmaId = t("SigmaId");
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -173,12 +176,12 @@ const SpecificationsDetails: React.FC<SpecificationsDetailsProps> = ({
sigmaIdValue,
);
if (response) {
toast.info("Specifications edited");
toast.info(t("SpecificationsEdited"));
}
} else {
const newFormInstanceId = await templateFiller.Save();
if (!newFormInstanceId) {
toast.error("Failed to save form instance");
toast.error(t("FailedToSaveFormInstance"));
return;
}
@ -189,7 +192,7 @@ const SpecificationsDetails: React.FC<SpecificationsDetailsProps> = ({
sigmaIdValue,
);
if (response) {
toast.info("New Specifications added");
toast.info(t("NewSpecificationsAdded"));
}
}
@ -210,11 +213,13 @@ const SpecificationsDetails: React.FC<SpecificationsDetailsProps> = ({
const { loaded, redirect } = form.state;
if (redirect && redirect !== "") return <Navigate to={redirect} />;
const mode = isEditMode() ? "Edit" : "Add";
const mode = isEditMode() ? t("Edit") : t("Add");
return (
<Loading loaded={loaded}>
<h1>{mode} Specifications</h1>
<h1>
{mode} {t("Specifications")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,5 +1,6 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -15,7 +16,7 @@ const SpecificationsTable: React.FC<PublishedTableProps<ReadSpecification>> = ({
onDelete,
onSort,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<ReadSpecification>[] = useMemo(
() => [{ key: "name", label: t("Name"), order: "asc" }],

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams, useLocation } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { useForm } from "../../../components/common/useForm";
import { InputType } from "../../../components/common/Input";
import {
@ -22,17 +24,18 @@ const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
}) => {
const { ssoProviderId } = useParams<{ ssoProviderId: string }>();
const location = useLocation();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelName = "Name";
const labelClientId = "Client Id";
const labelClientSecret = "Client Secret";
const labelValidIssuer = "Valid Issuer";
const labelAuthorizationEndpoint = "Authorisation Endpoint";
const labelTokenEndpoint = "Token Endpoint";
const labelIsPublic = "Is Public";
const labelName = t("Name");
const labelClientId = t("ClientId");
const labelClientSecret = t("ClientSecret");
const labelValidIssuer = t("ValidIssuer");
const labelAuthorizationEndpoint = t("AuthorizationEndpoint");
const labelTokenEndpoint = t("TokenEndpoint");
const labelIsPublic = t("IsPublic");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -132,7 +135,7 @@ const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
isPublicValue,
);
if (response) {
toast.info("Sso Provider edited");
toast.info(t("SsoProviderEdited"));
}
} else {
const response = await ssoManagerService.postSsoProvider(
@ -145,7 +148,7 @@ const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
isPublicValue,
);
if (response) {
toast.info("New Sso Provider added");
toast.info(t("NewSsoProviderAdded"));
}
}
@ -164,7 +167,7 @@ const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
const { loaded, redirect } = form.state;
if (redirect) return <Navigate to={redirect} />;
const mode = editMode ? "Edit" : "Add";
const mode = editMode ? t("Edit") : t("Add");
const redirectUrl =
window.location.href.slice(
0,
@ -175,7 +178,9 @@ const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
return (
<Loading loaded={loaded}>
<h1>{mode} Sso Provider</h1>
<h1>
{mode} {t("SsoProvider")}
</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(

View File

@ -1,5 +1,6 @@
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -15,7 +16,7 @@ const SsoManagerTable: React.FC<PublishedTableProps<GetSsoProvider>> = ({
onDelete,
onSort,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const columns: Column<GetSsoProvider>[] = useMemo(
() => [{ key: "name", label: t("Name"), order: "asc" }],

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import Column from "../../../components/common/columns";
import { Paginated } from "../../../services/Paginated";
import SsoManagerTable from "./components/ssoManagerTable";
@ -11,7 +12,7 @@ import Loading from "../../../components/common/Loading";
import Permission from "../../../components/common/Permission";
const SsoManager: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] = useState<Paginated<GetSsoProvider>>({
page: 1,

View File

@ -1,5 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import HorizontalTabs from "../../../components/common/HorizionalTabs";
import Tab from "../../../components/common/Tab";
import GeneralTab from "./components/GeneralTab";
@ -9,7 +10,7 @@ interface UserDetailsProps {
}
const UserDetails: React.FC<UserDetailsProps> = ({ editMode }) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const heading = editMode ? t("EditUser") : t("AddUser");

View File

@ -2,6 +2,8 @@ import Joi from "joi";
import React, { useEffect } from "react";
import { Navigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import { useForm } from "../../../../components/common/useForm";
import { InputType } from "../../../../components/common/Input";
import { GeneralIdRef, MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
@ -22,15 +24,16 @@ interface GeneralTabProps {
const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
const { userId } = useParams<{ userId: string }>();
const { t } = useTranslation<typeof Namespaces.Common>();
const labelFirstName = "First name";
const labelMiddleNames = "Middle names";
const labelLastName = "Last name";
const labelEmail = "Mail";
const labelDomain = "Domain";
const labelFirstName = t("FirstName");
const labelMiddleNames = t("MiddleNames");
const labelLastName = t("LastName");
const labelEmail = t("Mail");
const labelDomain = t("Domain");
const labelApply = "Save";
const labelSave = "Save and close";
const labelApply = t("Save");
const labelSave = t("SaveAndClose");
const form = useForm({
loaded: false,
@ -110,7 +113,7 @@ const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
domainValue,
);
if (response) {
toast.info("User edited");
toast.info(t("UserEdited"));
}
} else {
const response = await userService.postUser(
@ -121,7 +124,7 @@ const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
domainValue,
);
if (response) {
toast.info("New User added");
toast.info(t("NewUserAdded"));
}
}

View File

@ -1,5 +1,6 @@
import React, { useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../../i18n/i18n";
import Column from "../../../../components/common/columns";
import Table, {
PublishedTableProps,
@ -23,7 +24,7 @@ const UsersTable: React.FC<UsersTableProps> = ({
onSort,
resendConfirmEmail,
}) => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const canResendConfirmMail = authentication.hasAccess("ResendConfirmMail");
const resendConfirmEmailHandler = useCallback(

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import Column from "../../../components/common/columns";
import { Paginated } from "../../../services/Paginated";
import UsersTable from "./components/usersTable";
@ -10,7 +11,7 @@ import Loading from "../../../components/common/Loading";
import Permission from "../../../components/common/Permission";
const Users: React.FC = () => {
const { t } = useTranslation();
const { t } = useTranslation<typeof Namespaces.Common>();
const [loaded, setLoaded] = useState(false);
const [pagedData, setPagedData] = useState<Paginated<GetUser>>({
page: 1,

View File

@ -1,6 +1,8 @@
import React, { useEffect, useState } from "react";
import Joi from "joi";
import { toast } from "react-toastify";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../i18n/i18n";
import { useForm } from "../../components/common/useForm";
import profileService from "./services/profileService";
import { InputType } from "../../components/common/Input";
@ -15,15 +17,17 @@ import {
} from "../../components/common/formHelpers";
const Profile: React.FC = () => {
const labelFirstName = "First Name";
const labelMiddleNames = "Middle Name(s)";
const labelLastName = "Last Name";
const labelEmail = "E-Mail";
const labelNewPassword = "New Password";
const labelConfirmPassword = "Confirm Password";
const labelUsingTwoFactorAuthentication = "2 Factor Authentication";
const labelTfaCode = "Authentication code";
const labelApply = "Save";
const { t } = useTranslation<typeof Namespaces.Common>();
const labelFirstName = t("FirstName");
const labelMiddleNames = t("MiddleNames");
const labelLastName = t("LastName");
const labelEmail = t("Email");
const labelNewPassword = t("NewPassword");
const labelConfirmPassword = t("ConfirmPassword");
const labelUsingTwoFactorAuthentication = t("TwoFactorAuthentication");
const labelTfaCode = t("AuthenticationCode");
const labelApply = t("Save");
const [twoFactorAuthenticationSettings, setTwoFactorAuthenticationSettings] =
useState<TwoFactorAuthenticationSettings>({
@ -157,7 +161,7 @@ const Profile: React.FC = () => {
);
if (response) {
await loadProfile();
toast.info("Your profile settings have been saved");
toast.info(t("YourProfileSettingsHaveBeenSaved"));
}
} catch (ex: any) {
form.handleGeneralError(ex);
@ -172,7 +176,9 @@ const Profile: React.FC = () => {
const { usingTwoFactorAuthentication, newPassword } = form.state.data;
const passwordMaxLength = 255;
const tfaEnabled = usingTwoFactorAuthentication ? "Enabled" : "Disabled";
const tfaEnabled = usingTwoFactorAuthentication
? t("Enabled")
: t("Disabled");
let tfaImageBlock = null;
if (twoFactorAuthenticationSettings)
@ -268,7 +274,7 @@ const Profile: React.FC = () => {
return (
<Loading loaded={loaded}>
<h1>Profile</h1>
<h1>{t("Profile")}</h1>
<form onSubmit={handleSubmit}>
{renderError("_general", form.state.errors)}
{renderInput(