diff --git a/package.json b/package.json
index 7177002b46..2711cfcca6 100644
--- a/package.json
+++ b/package.json
@@ -67,7 +67,7 @@
"prettier:code": "prettier \"**/*.js\"",
"prettier:other": "prettier \"**/*.{md,css,scss,yaml,yml}\"",
"test:clean": "rimraf ./coverage",
- "test:front": "npm run test:clean && cross-env NODE_ENV=test IS_EE=true jest --config ./jest.config.front.js --coverage",
+ "test:front": "npm run test:clean && cross-env NODE_ENV=test IS_EE=true jest --config ./jest.config.front.js",
"test:front:watch": "cross-env NODE_ENV=test IS_EE=true jest --config ./jest.config.front.js --watchAll",
"test:front:update": "cross-env NODE_ENV=test IS_EE=true jest --config ./jest.config.front.js --u",
"test:front:ce": "npm run test:clean && cross-env NODE_ENV=test IS_EE=false jest --config ./jest.config.front.js --coverage",
diff --git a/packages/strapi-plugin-i18n/admin/src/components/LocaleRow/index.js b/packages/strapi-plugin-i18n/admin/src/components/LocaleRow/index.js
index f83fe6771e..2d11addc00 100644
--- a/packages/strapi-plugin-i18n/admin/src/components/LocaleRow/index.js
+++ b/packages/strapi-plugin-i18n/admin/src/components/LocaleRow/index.js
@@ -12,7 +12,7 @@ import { getTrad } from '../../utils';
const canUpdate = true;
const canDelete = true;
-const LocaleSettingsPage = ({ locale }) => {
+const LocaleSettingsPage = ({ locale, onDelete }) => {
const { formatMessage } = useIntl();
return (
@@ -34,12 +34,21 @@ const LocaleSettingsPage = ({ locale }) => {
: null,
+ icon: canUpdate ? (
+
+
+
+ ) : null,
onClick: () => console.log('edit'),
},
{
- icon: canDelete && !locale.isDefault ? : null,
- onClick: () => console.log('open delete modal'),
+ icon:
+ canDelete && !locale.isDefault ? (
+
+
+
+ ) : null,
+ onClick: onDelete,
},
]}
/>
@@ -54,6 +63,7 @@ LocaleSettingsPage.propTypes = {
displayName: PropTypes.string,
code: PropTypes.string.isRequired,
}).isRequired,
+ onDelete: PropTypes.func.isRequired,
};
export default LocaleSettingsPage;
diff --git a/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/index.js b/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/index.js
index 9ca033fd0c..effba33468 100644
--- a/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/index.js
+++ b/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/index.js
@@ -1,17 +1,25 @@
import React from 'react';
import { useIntl } from 'react-intl';
-import { BaselineAlignment } from 'strapi-helper-plugin';
+import { BaselineAlignment, ModalConfirm } from 'strapi-helper-plugin';
import { Header, List } from '@buffetjs/custom';
-import { Button } from '@buffetjs/core';
-
+import { Button, Text } from '@buffetjs/core';
import { LocaleRow } from '../../components';
import { useLocales } from '../../hooks';
import { getTrad } from '../../utils';
+import useDeleteLocale from '../../hooks/useDeleteLocale';
// Fake permissions
const canCreate = true;
const LocaleSettingsPage = () => {
+ const {
+ isDeleting,
+ isDeleteModalOpen,
+ deleteLocale,
+ showDeleteModal,
+ hideDeleteModal,
+ } = useDeleteLocale();
+
const { formatMessage } = useIntl();
const { locales, isLoading } = useLocales();
@@ -59,8 +67,29 @@ const LocaleSettingsPage = () => {
title={listTitle}
items={locales}
isLoading={isLoading}
- customRowComponent={locale => }
+ customRowComponent={locale => (
+ showDeleteModal(locale)} />
+ )}
/>
+
+
+
+ {formatMessage({ id: getTrad('Settings.locales.modal.delete.secondMessage') })}
+
+
>
);
};
diff --git a/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js b/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js
new file mode 100644
index 0000000000..808d9f2318
--- /dev/null
+++ b/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js
@@ -0,0 +1,85 @@
+import React from 'react';
+import { fireEvent, render, screen, within, waitFor } from '@testing-library/react';
+import { ThemeProvider } from 'styled-components';
+import LocaleSettingsPage from '..';
+import themes from '../../../../../../strapi-admin/admin/src/themes';
+
+// TODO: we should not be forced to mock this module
+// but it bugs somehow when run with jest
+jest.mock('strapi-helper-plugin', () => ({
+ BaselineAlignment: () => ,
+ // eslint-disable-next-line react/prop-types
+ ModalConfirm: ({ onConfirm, isOpen }) =>
+ isOpen ? (
+
+
+
+ ) : null,
+}));
+
+jest.mock('../../../utils', () => ({
+ getTrad: x => x,
+}));
+
+jest.mock('react-intl', () => ({
+ useIntl: () => ({
+ formatMessage: ({ id }) => id,
+ }),
+}));
+
+describe('i18n settings page', () => {
+ describe('initial state', () => {
+ it('shows default EN locale with edit button but no delete button', async () => {
+ render(
+
+
+
+ );
+
+ const row = await waitFor(() => screen.getByText('English').closest('tr'));
+ const rowUtils = within(row);
+
+ expect(rowUtils.queryByLabelText('Delete locale')).toBeFalsy();
+ expect(rowUtils.getByLabelText('Edit locale')).toBeVisible();
+ expect(rowUtils.getByText('Settings.locales.row.default-locale')).toBeVisible();
+ expect(rowUtils.getByText('en-US')).toBeVisible();
+ });
+
+ it('shows FR locale with edit button and delete button', async () => {
+ render(
+
+
+
+ );
+
+ const row = await waitFor(() => screen.getByText('French').closest('tr'));
+ const rowUtils = within(row);
+
+ expect(rowUtils.getByLabelText('Delete locale')).toBeVisible();
+ expect(rowUtils.getByLabelText('Edit locale')).toBeVisible();
+ expect(rowUtils.getByText('fr-FR')).toBeVisible();
+ });
+ });
+
+ describe('delete', () => {
+ it('removes the locale when clicking the confirmation button', async () => {
+ render(
+
+
+
+ );
+
+ const row = await waitFor(() => screen.getByText('French').closest('tr'));
+ const rowUtils = within(row);
+
+ fireEvent.click(rowUtils.getByLabelText('Delete locale'));
+
+ const dialog = screen.getByRole('dialog');
+ expect(dialog).toBeVisible();
+
+ fireEvent.click(screen.getByText('Confirm'));
+ });
+ });
+});
diff --git a/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/constants.js b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/constants.js
new file mode 100644
index 0000000000..80998d9d21
--- /dev/null
+++ b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/constants.js
@@ -0,0 +1,4 @@
+export const SHOW_MODAL = 'SHOW_MODAL';
+export const HIDE_MODAL = 'HIDE_MODAL';
+export const DELETE_LOCALE = 'DELETE_LOCALE';
+export const RESOLVE_LOCALE = 'RESOLVE_LOCALE';
diff --git a/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/index.js b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/index.js
new file mode 100644
index 0000000000..6973bbc1e8
--- /dev/null
+++ b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/index.js
@@ -0,0 +1,25 @@
+import { useReducer } from 'react';
+import reducer, { initialState } from './reducer';
+import { SHOW_MODAL, HIDE_MODAL, RESOLVE_LOCALE, DELETE_LOCALE } from './constants';
+
+const useDeleteLocale = () => {
+ const [{ isDeleteModalOpen, isDeleting }, dispatch] = useReducer(reducer, initialState);
+
+ const deleteLocale = () => {
+ dispatch({ type: DELETE_LOCALE });
+
+ return new Promise(resolve =>
+ setTimeout(() => {
+ dispatch({ type: RESOLVE_LOCALE });
+ resolve();
+ }, 1000)
+ );
+ };
+
+ const showDeleteModal = localeToDelete => dispatch({ type: SHOW_MODAL, localeToDelete });
+ const hideDeleteModal = () => dispatch({ type: HIDE_MODAL });
+
+ return { isDeleting, isDeleteModalOpen, deleteLocale, showDeleteModal, hideDeleteModal };
+};
+
+export default useDeleteLocale;
diff --git a/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/reducer.js b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/reducer.js
new file mode 100644
index 0000000000..6125e08878
--- /dev/null
+++ b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/reducer.js
@@ -0,0 +1,41 @@
+/* eslint-disable consistent-return */
+import produce from 'immer';
+import { SHOW_MODAL, HIDE_MODAL, RESOLVE_LOCALE, DELETE_LOCALE } from './constants';
+
+export const initialState = {
+ localeToDelete: null,
+ isDeleteModalOpen: false,
+ isDeleting: false,
+};
+
+const reducer = (state, action) =>
+ produce(state, draftState => {
+ switch (action.type) {
+ case SHOW_MODAL: {
+ draftState.isDeleteModalOpen = true;
+ draftState.localeToDelete = action.localeToDelete;
+ break;
+ }
+ case HIDE_MODAL: {
+ draftState.isDeleteModalOpen = false;
+ draftState.localeToDelete = null;
+ break;
+ }
+ case DELETE_LOCALE: {
+ draftState.isDeleting = true;
+ break;
+ }
+
+ case RESOLVE_LOCALE: {
+ draftState.isDeleting = false;
+ draftState.isDeleteModalOpen = false;
+ draftState.localeToDelete = null;
+ break;
+ }
+
+ default:
+ return draftState;
+ }
+ });
+
+export default reducer;
diff --git a/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/tests/reducer.test.js b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/tests/reducer.test.js
new file mode 100644
index 0000000000..257349753c
--- /dev/null
+++ b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/tests/reducer.test.js
@@ -0,0 +1,105 @@
+import reducer from '../reducer';
+import { SHOW_MODAL, HIDE_MODAL, RESOLVE_LOCALE, DELETE_LOCALE } from '../constants';
+
+describe(`I18N Settings page reducer`, () => {
+ describe(`Initial state`, () => {
+ it('returns the initialState', () => {
+ const state = {
+ localeToDelete: null,
+ isDeleteModalOpen: false,
+ isDeleting: false,
+ };
+
+ expect(reducer(state, {})).toEqual(state);
+ });
+ });
+
+ describe(SHOW_MODAL, () => {
+ it('set the isDeleteModalOpen key to true', () => {
+ const state = {
+ localeToDelete: null,
+ isDeleteModalOpen: false,
+ isDeleting: false,
+ };
+
+ const action = {
+ type: SHOW_MODAL,
+ localeToDelete: 'en-EN',
+ };
+
+ const expected = {
+ localeToDelete: 'en-EN',
+ isDeleteModalOpen: true,
+ isDeleting: false,
+ };
+
+ expect(reducer(state, action)).toEqual(expected);
+ });
+ });
+
+ describe(HIDE_MODAL, () => {
+ it('sets the isDeleteModalOpen value to false when it was true', () => {
+ const state = {
+ localeToDelete: 'en-EN',
+ isDeleteModalOpen: true,
+ isDeleting: false,
+ };
+
+ const action = {
+ type: HIDE_MODAL,
+ };
+
+ const expected = {
+ localeToDelete: null,
+ isDeleteModalOpen: false,
+ isDeleting: false,
+ };
+
+ expect(reducer(state, action)).toEqual(expected);
+ });
+ });
+
+ describe(DELETE_LOCALE, () => {
+ it('sets the isDeleting value to true', () => {
+ const state = {
+ localeToDelete: 'en-EN',
+ isDeleteModalOpen: true,
+ isDeleting: false,
+ };
+
+ const action = {
+ type: DELETE_LOCALE,
+ };
+
+ const expected = {
+ localeToDelete: 'en-EN',
+ isDeleteModalOpen: true,
+ isDeleting: true,
+ };
+
+ expect(reducer(state, action)).toEqual(expected);
+ });
+ });
+
+ describe(RESOLVE_LOCALE, () => {
+ it('resets the state to its initial values when they were true', () => {
+ const state = {
+ localeToDelete: 'en-EN',
+ isDeleteModalOpen: true,
+ isDeleting: true,
+ };
+
+ const action = {
+ type: RESOLVE_LOCALE,
+ };
+
+ const expected = {
+ localeToDelete: null,
+ isDeleteModalOpen: false,
+ isDeleting: false,
+ };
+
+ expect(reducer(state, action)).toEqual(expected);
+ });
+ });
+});
diff --git a/packages/strapi-plugin-i18n/admin/src/translations/en.json b/packages/strapi-plugin-i18n/admin/src/translations/en.json
index 92679eab18..6c2efff9a3 100644
--- a/packages/strapi-plugin-i18n/admin/src/translations/en.json
+++ b/packages/strapi-plugin-i18n/admin/src/translations/en.json
@@ -5,5 +5,8 @@
"Settings.list.description": "Configure the settings for the internationalization plugin",
"Settings.locales.list.title.singular": "{number} Locale",
"Settings.locales.list.title.plural": "{number} Locales",
- "Settings.locales.row.default-locale": "Default locale"
+ "Settings.locales.row.default-locale": "Default locale",
+ "Settings.locales.modal.delete.confirm": "Yes, delete",
+ "Settings.locales.modal.delete.message": "Deleting this locale will delete all associated content. If you want to keep some content, make sure to reallocate it to another locale first.",
+ "Settings.locales.modal.delete.secondMessage": "Do you want to delete this locale?"
}
diff --git a/test/config/front/strapi.js b/test/config/front/strapi.js
index 182c0a6e71..1ea0728f8d 100644
--- a/test/config/front/strapi.js
+++ b/test/config/front/strapi.js
@@ -7,6 +7,8 @@
// Setup the strapi functioon global variable
+import '@testing-library/jest-dom/extend-expect';
+
const React = require('react');
const hoistNonReactStatics = require('hoist-non-react-statics');