lemail2
Version:
Strapi Email designer plugin.
362 lines (328 loc) • 11.4 kB
JavaScript
/*
*
* HomePage
*
* Reference: https://strapi.io/documentation/developer-docs/latest/plugin-development/frontend-development.html#environment-setup
*/
import React, { memo, useRef, useState, useEffect, useCallback } from 'react';
import {
PopUpWarning,
LoadingIndicator,
request,
useGlobalContext,
dateFormats,
dateToUtcTime,
} from 'strapi-helper-plugin';
import { faLink, faFileExport, faFileImport, faPencilAlt, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Link, useHistory } from 'react-router-dom';
import { Table, Button } from '@buffetjs/core';
import { Duplicate } from '@buffetjs/icons';
import { Tooltip } from '@buffetjs/styles';
import { Header } from '@buffetjs/custom';
import { isEmpty, isNil, pick, uniqBy } from 'lodash';
import styled from 'styled-components';
import getTrad from '../../utils/getTrad';
import pluginId from '../../pluginId';
const getUrl = (to) => (to ? `/plugins/${pluginId}/${to}` : `/plugins/${pluginId}`);
const Wrapper = styled.div`
margin-bottom: 30px;
`;
const CustomTable = styled(Table)`
p {
margin-bottom: 0;
}
tr,
td {
height: 54px !important;
}
`;
const FooterWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`;
const FooterButtonsWrapper = styled.div`
button {
margin-right: 0.5rem;
&:last-of-type {
margin-right: 0;
}
}
`;
const HomePage = () => {
const { push } = useHistory();
const { formatMessage, plugins } = useGlobalContext();
const [templates, setTemplates] = useState([]);
const [deleteConfirmationModal, setDeleteConfirmationModal] = useState(false);
const [duplicateConfirmationModal, setDuplicateConfirmationModal] = useState(false);
const [importConfirmationModal, setImportConfirmationModal] = useState(false);
const emailTemplatesFileSelect = useRef();
useEffect(() => {
(async () => {
let templatesData = await request(`/${pluginId}/templates`, {
method: 'GET',
});
templatesData.forEach((data) => {
data.enabled = data.enabled.toString();
data.created_at = dateToUtcTime(data.created_at).format(dateFormats.date);
});
setTemplates(templatesData.map((row) => pick(row, ['id', 'name', 'enabled', 'created_at'])));
})();
}, []);
const duplicateTemplateHandler = useCallback(async () => {
try {
const response = await request(`/${pluginId}/templates/duplicate/${duplicateConfirmationModal}`, {
method: 'POST',
});
push(getUrl(`design/${response.id}`));
} catch (error) {
strapi.notification.toggle({
type: 'warning',
message: { id: getTrad('notification.impossibleToDuplicate') },
});
}
}, [duplicateConfirmationModal, push]);
const deleteTemplateHandler = useCallback(async () => {
try {
const { removed } = await request(`/${pluginId}/templates/${deleteConfirmationModal}`, {
method: 'DELETE',
});
if (removed) {
setTemplates((state) => state.filter((el) => el.id !== deleteConfirmationModal));
setDeleteConfirmationModal(false);
strapi.notification.toggle({
type: 'success',
message: { id: getTrad('notification.templateDeleted') },
});
}
} catch (error) {
console.log(error);
strapi.notification.toggle({
type: 'warning',
message: { id: getTrad('notification.impossibileToDeleteTemplate') },
});
}
}, [deleteConfirmationModal]);
const exportTemplatesHandler = async () => {
const templates = await request(`/${pluginId}/templates`, {
method: 'GET',
});
const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(templates))}`;
let a = document.createElement('a');
a.href = dataStr;
a.download = `${pluginId}-templates_${dateToUtcTime().unix()}.json`;
a.click();
};
const fileChangeHandler = (event) => {
const file = event.target.files[0];
if (file) {
const fr = new FileReader();
fr.onload = async () => {
const content = JSON.parse(fr.result.toString());
setImportConfirmationModal(content);
};
fr.readAsText(file);
}
};
let importLoading = false;
const handleTemplatesFromImport = async () => {
const tpls = importConfirmationModal;
importLoading = true;
let importedTemplates = [];
tpls.forEach(async (template) => {
const response = await request(`/${pluginId}/templates/${template.id}`, {
// later templateId
method: 'POST',
body: {
...template,
created_at: dateToUtcTime().unix(),
updated_at: dateToUtcTime().unix(),
import: true,
},
});
importedTemplates.push(response);
});
let newTemplates = [...templates, ...importedTemplates].map((data) => {
data.enabled = data.enabled.toString();
data.created_at = dateToUtcTime(
data.created_at,
dateToUtcTime(data.created_at).isValid() ? undefined : dateFormats.date
).format('dddd, MMMM Do YYYY');
return data;
});
newTemplates = uniqBy(newTemplates, function (e) {
return e.id;
});
setTemplates(newTemplates);
emailTemplatesFileSelect.current.value = '';
setImportConfirmationModal(undefined);
importLoading = false;
};
const headers = [
{ name: formatMessage({ id: getTrad('table.name') }), value: 'name' },
{ name: formatMessage({ id: getTrad('table.templateId') }), value: 'id' },
{ name: formatMessage({ id: getTrad('table.enabled') }), value: 'enabled' },
{ name: formatMessage({ id: getTrad('table.createdAt') }), value: 'created_at' },
];
return (
<div className="container-fluid" style={{ padding: '18px 30px 66px 30px' }}>
<PopUpWarning
isConfirmButtonLoading={importLoading}
isOpen={importConfirmationModal && importConfirmationModal.length > 0}
content={{
title: getTrad('pleaseConfirm'),
message: getTrad('notification.importTemplate'),
}}
popUpWarningType="danger"
toggleModal={() => {
emailTemplatesFileSelect.current.value = '';
setImportConfirmationModal(undefined);
}}
onConfirm={async () => {
await handleTemplatesFromImport();
}}
/>
<PopUpWarning
isOpen={!isNil(duplicateConfirmationModal) && duplicateConfirmationModal !== false}
content={{
title: getTrad('pleaseConfirm'),
message: getTrad('questions.sureToDuplicate'),
}}
popUpWarningType="danger"
toggleModal={() => setDuplicateConfirmationModal(false)}
onConfirm={async () => {
await duplicateTemplateHandler();
}}
/>
<PopUpWarning
isOpen={!isNil(deleteConfirmationModal) && deleteConfirmationModal !== false}
content={{
title: getTrad('pleaseConfirm'),
message: getTrad('questions.sureToDelete'),
}}
popUpWarningType="danger"
toggleModal={() => setDeleteConfirmationModal(false)}
onConfirm={async () => {
await deleteTemplateHandler();
}}
/>
<Header
isLoading={!plugins[pluginId].isReady}
actions={[
{
label: formatMessage({ id: getTrad('newTemplate') }),
onClick: () => push(getUrl(`design/new`)),
color: 'primary',
type: 'button',
icon: true,
},
]}
title={{
label: formatMessage({ id: getTrad('plugin.name') }),
}}
content={formatMessage({ id: getTrad('header.description') })}
/>
{!plugins[pluginId].isReady && <LoadingIndicator />}
<Wrapper>
<CustomTable
className="remove-margin"
headers={headers}
rows={templates}
// customRow={this.CustomRow}
onClickRow={(e, data) => {
push(getUrl(`design/${data.id}`));
}}
rowLinks={[
{
icon: (
<>
<div data-for="duplicate" data-tip={formatMessage({ id: getTrad('tooltip.duplicate') })}>
<Duplicate fill="#000000" />
</div>
<Tooltip id="duplicate" />
</>
),
onClick: (data) => setDuplicateConfirmationModal(data.id),
},
{
icon: (
<>
<div data-for="edit" data-tip={formatMessage({ id: getTrad('tooltip.edit') })}>
<FontAwesomeIcon icon={faPencilAlt} />
</div>
<Tooltip id="edit" />
</>
),
onClick: (data) => {
push(getUrl(`design/${data.id}`));
},
},
{
icon: (
<>
<div data-for="copy_template_id" data-tip={formatMessage({ id: getTrad('tooltip.copyTemplateId') })}>
<FontAwesomeIcon icon={faLink} />
</div>
<Tooltip id="copy_template_id" />
</>
),
onClick: (data) => {
navigator.clipboard.writeText(`${data.id}`).then(
function () {
strapi.notification.toggle({
type: 'success',
message: {
id: getTrad('notification.templateIdCopied'),
},
});
console.log('Template ID copied to clipboard successfully!');
},
function (err) {
console.error('Could not copy text: ', err);
}
);
},
},
{
icon: (
<>
<div data-for="delete_template" data-tip={formatMessage({ id: getTrad('tooltip.delete') })}>
<FontAwesomeIcon icon={faTrashAlt} />
</div>
<Tooltip id="delete_template" />
</>
),
onClick: (data) => setDeleteConfirmationModal(data.id),
},
]}
/>
</Wrapper>
<FooterWrapper>
<Link to={`/plugins/${pluginId}/how-to`}>{formatMessage({ id: getTrad('howToUse.link') })}</Link>
<FooterButtonsWrapper>
<Button
onClick={() => exportTemplatesHandler()}
color="success"
icon={<FontAwesomeIcon icon={faFileExport} />}
>
{formatMessage({ id: getTrad('templates.exportTemplates') })}
</Button>
<Button
onClick={() => {
emailTemplatesFileSelect.current.click();
}}
color="delete"
icon={<FontAwesomeIcon icon={faFileImport} />}
>
{formatMessage({ id: getTrad('templates.importTemplates') })}
</Button>
<span style={{ display: 'none' }}>
<input type="file" ref={emailTemplatesFileSelect} onChange={fileChangeHandler} />
</span>
</FooterButtonsWrapper>
</FooterWrapper>
</div>
);
};
export default memo(HomePage);