mirror of
https://github.com/logto-io/logto.git
synced 2025-03-31 22:51:25 -05:00
feat(console): display unsaved alert on custom phrases changed (#1994)
This commit is contained in:
parent
48832e5054
commit
0679a6a67c
8 changed files with 70 additions and 5 deletions
|
@ -20,11 +20,12 @@ import { CustomPhraseResponse } from './types';
|
|||
|
||||
type LanguageEditorProps = {
|
||||
selectedLanguageKey: LanguageKey;
|
||||
onFormStateChange: (isDirty: boolean) => void;
|
||||
};
|
||||
|
||||
const emptyUiTranslation = createEmptyUiTranslation();
|
||||
|
||||
const LanguageEditor = ({ selectedLanguageKey }: LanguageEditorProps) => {
|
||||
const LanguageEditor = ({ selectedLanguageKey, onFormStateChange }: LanguageEditorProps) => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
const isBuiltInLanguage = Object.keys(resource).includes(selectedLanguageKey);
|
||||
|
@ -53,9 +54,13 @@ const LanguageEditor = ({ selectedLanguageKey }: LanguageEditorProps) => {
|
|||
const {
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting },
|
||||
formState: { isSubmitting, isDirty },
|
||||
} = formMethods;
|
||||
|
||||
useEffect(() => {
|
||||
onFormStateChange(isDirty);
|
||||
}, [isDirty, onFormStateChange]);
|
||||
|
||||
const onSubmit = handleSubmit(async (formData: UiTranslation) => {
|
||||
const updatedCustomPhrase = await api
|
||||
.put(`/api/custom-phrases/${selectedLanguageKey}`, {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { getDefaultLanguage, LanguageKey } from '@logto/core-kit';
|
||||
import { languageOptions as uiLanguageOptions } from '@logto/phrases-ui';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Modal from 'react-modal';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import ConfirmModal from '@/components/ConfirmModal';
|
||||
import ModalLayout from '@/components/ModalLayout';
|
||||
import { RequestError } from '@/hooks/use-api';
|
||||
import * as modalStyles from '@/scss/modal.module.scss';
|
||||
|
@ -19,6 +21,7 @@ type ManageLanguageModalProps = {
|
|||
};
|
||||
|
||||
const ManageLanguageModal = ({ isOpen, onClose }: ManageLanguageModalProps) => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { data: customPhraseResponses } = useSWR<CustomPhraseResponse[], RequestError>(
|
||||
'/api/custom-phrases'
|
||||
);
|
||||
|
@ -38,6 +41,11 @@ const ManageLanguageModal = ({ isOpen, onClose }: ManageLanguageModalProps) => {
|
|||
|
||||
const [selectedLanguageKey, setSelectedLanguageKey] = useState<LanguageKey>(defaultLanguageKey);
|
||||
|
||||
const [isLanguageEditorDirty, setIsLanguageEditorDirty] = useState(false);
|
||||
|
||||
const [isUnsavedAlertOpen, setIsUnsavedAlertOpen] = useState(false);
|
||||
const [preselectedLanguageKey, setPreselectedLanguageKey] = useState<LanguageKey>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setSelectedLanguageKey(defaultLanguageKey);
|
||||
|
@ -50,17 +58,57 @@ const ManageLanguageModal = ({ isOpen, onClose }: ManageLanguageModalProps) => {
|
|||
title="sign_in_exp.others.manage_language.title"
|
||||
subtitle="sign_in_exp.others.manage_language.subtitle"
|
||||
size="xlarge"
|
||||
onClose={onClose}
|
||||
onClose={() => {
|
||||
if (isLanguageEditorDirty) {
|
||||
setPreselectedLanguageKey(undefined);
|
||||
setIsUnsavedAlertOpen(true);
|
||||
|
||||
return;
|
||||
}
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<div className={style.container}>
|
||||
<LanguageNav
|
||||
languageKeys={allLanguageKeys}
|
||||
selectedLanguage={selectedLanguageKey}
|
||||
onSelect={setSelectedLanguageKey}
|
||||
onSelect={(languageKey) => {
|
||||
if (isLanguageEditorDirty) {
|
||||
setPreselectedLanguageKey(languageKey);
|
||||
setIsUnsavedAlertOpen(true);
|
||||
|
||||
return;
|
||||
}
|
||||
setSelectedLanguageKey(languageKey);
|
||||
}}
|
||||
/>
|
||||
<LanguageEditor
|
||||
selectedLanguageKey={selectedLanguageKey}
|
||||
onFormStateChange={setIsLanguageEditorDirty}
|
||||
/>
|
||||
<LanguageEditor selectedLanguageKey={selectedLanguageKey} />
|
||||
</div>
|
||||
</ModalLayout>
|
||||
<ConfirmModal
|
||||
isOpen={isUnsavedAlertOpen}
|
||||
cancelButtonText="general.stay_on_page"
|
||||
onCancel={() => {
|
||||
setIsUnsavedAlertOpen(false);
|
||||
}}
|
||||
onConfirm={() => {
|
||||
setIsUnsavedAlertOpen(false);
|
||||
|
||||
if (preselectedLanguageKey) {
|
||||
setSelectedLanguageKey(preselectedLanguageKey);
|
||||
setPreselectedLanguageKey(undefined);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('sign_in_exp.others.manage_language.unsaved_description')}
|
||||
</ConfirmModal>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -91,6 +91,7 @@ const sign_in_exp = {
|
|||
logto_source_language: 'Logto source language',
|
||||
custom_values: 'Custom values',
|
||||
clear_all: 'Clear all',
|
||||
unsaved_description: 'Changes won’t be saved if you leave this page without saving.',
|
||||
},
|
||||
authentication: {
|
||||
title: 'AUTHENTICATION',
|
||||
|
|
|
@ -93,6 +93,7 @@ const sign_in_exp = {
|
|||
logto_source_language: 'Logto source language', // UNTRANSLATED
|
||||
custom_values: 'Custom values', // UNTRANSLATED
|
||||
clear_all: 'Clear all', // UNTRANSLATED
|
||||
unsaved_description: 'Changes won’t be saved if you leave this page without saving.', // UNTRANSLATED
|
||||
},
|
||||
authentication: {
|
||||
title: 'AUTHENTICATION',
|
||||
|
|
|
@ -88,6 +88,7 @@ const sign_in_exp = {
|
|||
logto_source_language: 'Logto source language', // UNTRANSLATED
|
||||
custom_values: 'Custom values', // UNTRANSLATED
|
||||
clear_all: 'Clear all', // UNTRANSLATED
|
||||
unsaved_description: 'Changes won’t be saved if you leave this page without saving.', // UNTRANSLATED
|
||||
},
|
||||
authentication: {
|
||||
title: 'AUTHENTICATION',
|
||||
|
|
|
@ -91,6 +91,7 @@ const sign_in_exp = {
|
|||
logto_source_language: 'Logto source language', // UNTRANSLATED
|
||||
custom_values: 'Custom values', // UNTRANSLATED
|
||||
clear_all: 'Clear all', // UNTRANSLATED
|
||||
unsaved_description: 'Changes won’t be saved if you leave this page without saving.', // UNTRANSLATED
|
||||
},
|
||||
authentication: {
|
||||
title: 'AUTENTICAÇÃO',
|
||||
|
|
|
@ -92,6 +92,13 @@ const sign_in_exp = {
|
|||
logto_source_language: 'Logto source language', // UNTRANSLATED
|
||||
custom_values: 'Custom values', // UNTRANSLATED
|
||||
clear_all: 'Clear all', // UNTRANSLATED
|
||||
unsaved_description: 'Changes won’t be saved if you leave this page without saving.', // UNTRANSLATED
|
||||
deletion_title: 'Do you want to delete the added language?', // UNTRANSLATED
|
||||
deletion_description:
|
||||
'After deletion, your users won’t be able to browse in that language again.', // UNTRANSLATED
|
||||
default_language_deletion_title: 'Default language can’t be deleted.', // UNTRANSLATED
|
||||
default_language_deletion_description:
|
||||
'{{language}} is set as your default language and can’t be deleted. ', // UNTRANSLATED
|
||||
},
|
||||
authentication: {
|
||||
title: 'AUTHENTICATION',
|
||||
|
|
|
@ -88,6 +88,7 @@ const sign_in_exp = {
|
|||
logto_source_language: 'Logto source language', // UNTRANSLATED
|
||||
custom_values: 'Custom values', // UNTRANSLATED
|
||||
clear_all: 'Clear all', // UNTRANSLATED
|
||||
unsaved_description: 'Changes won’t be saved if you leave this page without saving.', // UNTRANSLATED
|
||||
},
|
||||
authentication: {
|
||||
title: '身份验证',
|
||||
|
|
Loading…
Add table
Reference in a new issue