diff --git a/src/assets/images/icons/Duplicate.svg b/src/assets/images/icons/Duplicate.svg
new file mode 100644
index 000000000..9337e4c2e
--- /dev/null
+++ b/src/assets/images/icons/Duplicate.svg
@@ -0,0 +1,25 @@
+
+
\ No newline at end of file
diff --git a/src/assets/images/icons/Flow/Duplicate.svg b/src/assets/images/icons/Flow/Duplicate.svg
deleted file mode 100644
index 6d55607bf..000000000
--- a/src/assets/images/icons/Flow/Duplicate.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
\ No newline at end of file
diff --git a/src/containers/Flow/FlowList/FlowList.tsx b/src/containers/Flow/FlowList/FlowList.tsx
index cf01c3983..8531a227a 100644
--- a/src/containers/Flow/FlowList/FlowList.tsx
+++ b/src/containers/Flow/FlowList/FlowList.tsx
@@ -6,7 +6,7 @@ import { useLazyQuery, useMutation, useQuery } from '@apollo/client';
import { FormControl, MenuItem, Select } from '@mui/material';
import FlowIcon from 'assets/images/icons/Flow/Dark.svg?react';
-import DuplicateIcon from 'assets/images/icons/Flow/Duplicate.svg?react';
+import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react';
import ExportIcon from 'assets/images/icons/Flow/Export.svg?react';
import ConfigureIcon from 'assets/images/icons/Configure/UnselectedDark.svg?react';
import PinIcon from 'assets/images/icons/Pin/Active.svg?react';
diff --git a/src/containers/InteractiveMessage/InteractiveMessageList/InteractiveMessageList.tsx b/src/containers/InteractiveMessage/InteractiveMessageList/InteractiveMessageList.tsx
index a0e3472cd..9283f8742 100644
--- a/src/containers/InteractiveMessage/InteractiveMessageList/InteractiveMessageList.tsx
+++ b/src/containers/InteractiveMessage/InteractiveMessageList/InteractiveMessageList.tsx
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import InteractiveMessageIcon from 'assets/images/icons/InteractiveMessage/Dark.svg?react';
import DownArrow from 'assets/images/icons/DownArrow.svg?react';
-import DuplicateIcon from 'assets/images/icons/Flow/Duplicate.svg?react';
+import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react';
import { List } from 'containers/List/List';
import {
FILTER_INTERACTIVE_MESSAGES,
diff --git a/src/containers/Template/Form/HSM/HSM.test.tsx b/src/containers/Template/Form/HSM/HSM.test.tsx
index 8bb04964d..083ea5a70 100644
--- a/src/containers/Template/Form/HSM/HSM.test.tsx
+++ b/src/containers/Template/Form/HSM/HSM.test.tsx
@@ -48,21 +48,26 @@ describe('Add mode', () => {
const { queryByText } = within(container.querySelector('form') as HTMLElement);
const button: any = queryByText('Submit for Approval');
await user.click(button);
+
+ // we should have 2 errors
await waitFor(() => {
expect(queryByText('Title is required.')).toBeInTheDocument();
expect(queryByText('Message is required.')).toBeInTheDocument();
});
- // we should have 2 errors
-
fireEvent.change(container.querySelector('input[name="label"]') as HTMLInputElement, {
target: {
value:
'We are not allowing a really long title, and we should trigger validation for this.',
},
});
+
+ await user.click(button);
+
// we should still have 2 errors
- expect(queryByText('Title is required.')).toBeInTheDocument();
- expect(queryByText('Message is required.')).toBeInTheDocument();
+ await waitFor(() => {
+ expect(queryByText('Title length is too long.')).toBeInTheDocument();
+ expect(queryByText('Message is required.')).toBeInTheDocument();
+ });
});
});
diff --git a/src/containers/Template/Form/HSM/HSM.tsx b/src/containers/Template/Form/HSM/HSM.tsx
index b756355ef..67a2f5825 100644
--- a/src/containers/Template/Form/HSM/HSM.tsx
+++ b/src/containers/Template/Form/HSM/HSM.tsx
@@ -2,7 +2,7 @@ import { useState } from 'react';
import { useQuery } from '@apollo/client';
import { EditorState } from 'draft-js';
import { useTranslation } from 'react-i18next';
-import { useParams } from 'react-router-dom';
+import { useParams, useLocation } from 'react-router-dom';
import Loading from 'components/UI/Layout/Loading/Loading';
import TemplateIcon from 'assets/images/icons/Template/UnselectedDark.svg?react';
import { GET_HSM_CATEGORIES } from 'graphql/queries/Template';
@@ -32,6 +32,7 @@ export const HSM = () => {
const [category, setCategory] = useState({ label: '', id: '' });
const { t } = useTranslation();
const params = useParams();
+ const location: any = useLocation();
const { data: categoryList, loading } = useQuery(GET_HSM_CATEGORIES);
@@ -109,8 +110,9 @@ export const HSM = () => {
setSampleMessages(message);
};
+ const isCopyState = location.state === 'copy';
let disabled = false;
- if (params.id) {
+ if (params.id && !isCopyState) {
disabled = true;
}
diff --git a/src/containers/Template/Form/Template.tsx b/src/containers/Template/Form/Template.tsx
index 8d1057006..695be6525 100644
--- a/src/containers/Template/Form/Template.tsx
+++ b/src/containers/Template/Form/Template.tsx
@@ -13,7 +13,7 @@ import { EmojiInput } from 'components/UI/Form/EmojiInput/EmojiInput';
import { AutoComplete } from 'components/UI/Form/AutoComplete/AutoComplete';
import { Checkbox } from 'components/UI/Form/Checkbox/Checkbox';
import { LanguageBar } from 'components/UI/LanguageBar/LanguageBar';
-import { GET_TEMPLATE, FILTER_TEMPLATES } from 'graphql/queries/Template';
+import { GET_TEMPLATE } from 'graphql/queries/Template';
import { CREATE_MEDIA_MESSAGE } from 'graphql/mutations/Chat';
import { USER_LANGUAGES } from 'graphql/queries/Organization';
import { GET_TAGS } from 'graphql/queries/Tags';
@@ -182,12 +182,11 @@ const Template = ({
const [label, setLabel] = useState('');
const [body, setBody] = useState(EditorState.createEmpty());
const [example, setExample] = useState(EditorState.createEmpty());
- const [filterLabel, setFilterLabel] = useState('');
const [shortcode, setShortcode] = useState('');
const [language, setLanguageId] = useState({});
const [type, setType] = useState(null);
const [translations, setTranslations] = useState();
- const [attachmentURL, setAttachmentURL] = useState();
+ const [attachmentURL, setAttachmentURL] = useState('');
const [languageOptions, setLanguageOptions] = useState([]);
const [isActive, setIsActive] = useState(true);
const [validatingURL, setValidatingURL] = useState(false);
@@ -203,13 +202,37 @@ const Template = ({
const navigate = useNavigate();
const location: any = useLocation();
const params = useParams();
- const isEditForm = !!params.id;
- const { data: tag } = useQuery(GET_TAGS, {
+ let isEditing = false;
+ let mode;
+
+ const isCopyState = location.state === 'copy';
+ if (isCopyState) {
+ queries.updateItemQuery = CREATE_TEMPLATE;
+ mode = 'copy';
+ } else {
+ queries.updateItemQuery = UPDATE_TEMPLATE;
+ }
+
+ if (params.id && !isCopyState) {
+ isEditing = true;
+ }
+
+ const { data: tag, loading: tagLoading } = useQuery(GET_TAGS, {
variables: {},
fetchPolicy: 'network-only',
});
+ const { data: languages, loading: languageLoading } = useQuery(USER_LANGUAGES, {
+ variables: { opts: { order: 'ASC' } },
+ });
+
+ const [getSessionTemplate, { data: template, loading: templateLoading }] =
+ useLazyQuery(GET_TEMPLATE);
+
+ // create media for attachment
+ const [createMediaMessage] = useMutation(CREATE_MEDIA_MESSAGE);
+
const states = {
language,
label,
@@ -242,7 +265,7 @@ const Template = ({
hasButtons,
}: any) => {
if (languageOptions.length > 0 && languageIdValue) {
- if (location.state) {
+ if (location.state && location.state !== 'copy') {
const selectedLangauge = languageOptions.find(
(lang: any) => lang.label === location.state.language
);
@@ -353,26 +376,78 @@ const Template = ({
}
};
- const { data: languages } = useQuery(USER_LANGUAGES, {
- variables: { opts: { order: 'ASC' } },
- });
+ const displayWarning = () => {
+ if (type && type.id === 'STICKER') {
+ setWarning(
+
+
+ - {t('Animated stickers are not supported.')}
+ - {t('Captions along with stickers are not supported.')}
+
+
+ );
+ } else if (type && type.id === 'AUDIO') {
+ setWarning(
+
+
+ - {t('Captions along with audio are not supported.')}
+
+
+ );
+ } else {
+ setWarning(null);
+ }
+ };
- const [getSessionTemplates, { data: sessionTemplates }] = useLazyQuery(FILTER_TEMPLATES, {
- variables: {
- filter: { languageId: language ? parseInt(language.id, 10) : null },
- opts: {
- order: 'ASC',
- limit: null,
- offset: 0,
- },
- },
- });
+ const validateURL = (value: string) => {
+ if (value && type) {
+ setValidatingURL(true);
+ validateMedia(value, type.id, false).then((response: any) => {
+ if (!response.data.is_valid) {
+ setIsUrlValid(response.data.message);
+ } else {
+ setIsUrlValid('');
+ }
+ setValidatingURL(false);
+ });
+ }
+ };
- const [getSessionTemplate, { data: template, loading: templateLoading }] =
- useLazyQuery(GET_TEMPLATE);
+ const addTemplateButtons = (addFromTemplate: boolean = true) => {
+ let buttons: any = [];
+ const buttonType: any = {
+ QUICK_REPLY: { value: '' },
+ CALL_TO_ACTION: { type: '', title: '', value: '' },
+ };
- // create media for attachment
- const [createMediaMessage] = useMutation(CREATE_MEDIA_MESSAGE);
+ if (templateType) {
+ buttons = addFromTemplate
+ ? [...templateButtons, buttonType[templateType]]
+ : [buttonType[templateType]];
+ }
+
+ setTemplateButtons(buttons);
+ };
+
+ const removeTemplateButtons = (index: number) => {
+ const result = templateButtons.filter((val, idx) => idx !== index);
+ setTemplateButtons(result);
+ };
+
+ const getTemplateAndButton = (text: string) => {
+ const exp = /(\|\s\[)|(\|\[)/;
+ const areButtonsPresent = text.search(exp);
+
+ let message: any = text;
+ let buttons: any = null;
+
+ if (areButtonsPresent !== -1) {
+ buttons = text.substr(areButtonsPresent);
+ message = text.substr(0, areButtonsPresent);
+ }
+
+ return { message, buttons };
+ };
useEffect(() => {
if (params.id) {
@@ -387,16 +462,10 @@ const Template = ({
lang.sort((first: any, second: any) => (first.label > second.label ? 1 : -1));
setLanguageOptions(lang);
- if (!isEditForm) setLanguageId(lang[0]);
+ if (!isEditing) setLanguageId(lang[0]);
}
}, [languages]);
- useEffect(() => {
- if (filterLabel && language && language.id) {
- getSessionTemplates();
- }
- }, [filterLabel, language, getSessionTemplates]);
-
useEffect(() => {
setShortcode(getShortcode);
}, [getShortcode]);
@@ -407,27 +476,53 @@ const Template = ({
}
}, [getExample]);
- const validateTitle = (value: any) => {
- let error;
- if (value) {
- setFilterLabel(value);
- let found = [];
- if (sessionTemplates) {
- if (getSessionTemplatesCallBack) {
- getSessionTemplatesCallBack(sessionTemplates);
- }
- // need to check exact title
- found = sessionTemplates.sessionTemplates.filter((search: any) => search.label === value);
- if (params.id && found.length > 0) {
- found = found.filter((search: any) => search.id !== params.id);
- }
+ useEffect(() => {
+ if ((type === '' || type) && attachmentURL) {
+ validateURL(attachmentURL);
+ if (getUrlAttachmentAndType) {
+ getUrlAttachmentAndType(type.id || 'TEXT', { url: attachmentURL });
}
- if (found.length > 0) {
- error = t('Title already exists.');
+ }
+ }, [type, attachmentURL]);
+
+ useEffect(() => {
+ displayWarning();
+ }, [type]);
+
+ useEffect(() => {
+ if (templateType) {
+ addTemplateButtons(false);
+ }
+ }, [templateType]);
+
+ // Removing buttons when checkbox is checked or unchecked
+ useEffect(() => {
+ if (getExample) {
+ const { message }: any = getTemplateAndButton(getPlainTextFromEditor(getExample));
+ onExampleChange(message || '');
+ }
+ }, [isAddButtonChecked]);
+
+ // Converting buttons to template and vice-versa to show realtime update on simulator
+ useEffect(() => {
+ if (templateButtons.length > 0) {
+ const parse = convertButtonsToTemplate(templateButtons, templateType);
+
+ const parsedText = parse.length ? `| ${parse.join(' | ')}` : null;
+
+ const { message }: any = getTemplateAndButton(getPlainTextFromEditor(example));
+
+ const sampleText: any = parsedText && message + parsedText;
+
+ if (sampleText) {
+ onExampleChange(sampleText);
}
}
- return error;
- };
+ }, [templateButtons]);
+
+ if (languageLoading || templateLoading || tagLoading) {
+ return ;
+ }
const updateTranslation = (value: any) => {
const translationId = value.id;
@@ -469,7 +564,7 @@ const Template = ({
const selected = languageOptions.find(
({ label: languageLabel }: any) => languageLabel === value
);
- if (selected && isEditForm) {
+ if (selected && isEditing) {
updateTranslation(selected);
} else if (selected) {
setLanguageId(selected);
@@ -484,62 +579,12 @@ const Template = ({
}
// create translations only while updating
- if (result && isEditForm) {
+ if (result && isEditing) {
updateTranslation(result);
}
if (result) setLanguageId(result);
};
- const validateURL = (value: string) => {
- if (value && type) {
- setValidatingURL(true);
- validateMedia(value, type.id, false).then((response: any) => {
- if (!response.data.is_valid) {
- setIsUrlValid(response.data.message);
- } else {
- setIsUrlValid('');
- }
- setValidatingURL(false);
- });
- }
- };
-
- useEffect(() => {
- if ((type === '' || type) && attachmentURL) {
- validateURL(attachmentURL);
- if (getUrlAttachmentAndType) {
- getUrlAttachmentAndType(type.id || 'TEXT', { url: attachmentURL });
- }
- }
- }, [type, attachmentURL]);
-
- const displayWarning = () => {
- if (type && type.id === 'STICKER') {
- setWarning(
-
-
- - {t('Animated stickers are not supported.')}
- - {t('Captions along with stickers are not supported.')}
-
-
- );
- } else if (type && type.id === 'AUDIO') {
- setWarning(
-
-
- - {t('Captions along with audio are not supported.')}
-
-
- );
- } else {
- setWarning(null);
- }
- };
-
- useEffect(() => {
- displayWarning();
- }, [type]);
-
let timer: any = null;
const attachmentField = [
{
@@ -552,7 +597,7 @@ const Template = ({
variant: 'outlined',
label: t('Attachment Type'),
},
- disabled: !!(defaultAttribute.isHsm && params.id),
+ disabled: isEditing,
helperText: warning,
onChange: (event: any) => {
const val = event || '';
@@ -568,7 +613,7 @@ const Template = ({
type: 'text',
placeholder: t('Attachment URL'),
validate: () => isUrlValid,
- disabled: !!(defaultAttribute.isHsm && params.id),
+ disabled: isEditing,
helperText: t(
'Please provide a sample attachment for approval purpose. You may send a similar but different attachment when sending the HSM to users.'
),
@@ -607,7 +652,7 @@ const Template = ({
variant: 'outlined',
label: `${t('Language')}*`,
},
- disabled: !!(defaultAttribute.isHsm && params.id),
+ disabled: isEditing,
onChange: getLanguageId,
}
: {
@@ -623,8 +668,7 @@ const Template = ({
component: Input,
name: 'label',
placeholder: `${t('Title')}*`,
- validate: validateTitle,
- disabled: !!(defaultAttribute.isHsm && params.id),
+ disabled: isEditing,
helperText: defaultAttribute.isHsm
? t('Define what use case does this template serve eg. OTP, optin, activity preference')
: null,
@@ -639,7 +683,7 @@ const Template = ({
rows: 5,
convertToWhatsApp: true,
textArea: true,
- disabled: !!(defaultAttribute.isHsm && params.id),
+ disabled: isEditing,
helperText: defaultAttribute.isHsm
? 'You can also use variable and interactive actions. Variable format: {{1}}, Button format: [Button text,Value] Value can be a URL or a phone number.'
: null,
@@ -649,73 +693,6 @@ const Template = ({
},
];
- const addTemplateButtons = (addFromTemplate: boolean = true) => {
- let buttons: any = [];
- const buttonType: any = {
- QUICK_REPLY: { value: '' },
- CALL_TO_ACTION: { type: '', title: '', value: '' },
- };
-
- if (templateType) {
- buttons = addFromTemplate
- ? [...templateButtons, buttonType[templateType]]
- : [buttonType[templateType]];
- }
-
- setTemplateButtons(buttons);
- };
-
- const removeTemplateButtons = (index: number) => {
- const result = templateButtons.filter((val, idx) => idx !== index);
- setTemplateButtons(result);
- };
-
- useEffect(() => {
- if (templateType) {
- addTemplateButtons(false);
- }
- }, [templateType]);
-
- const getTemplateAndButton = (text: string) => {
- const exp = /(\|\s\[)|(\|\[)/;
- const areButtonsPresent = text.search(exp);
-
- let message: any = text;
- let buttons: any = null;
-
- if (areButtonsPresent !== -1) {
- buttons = text.substr(areButtonsPresent);
- message = text.substr(0, areButtonsPresent);
- }
-
- return { message, buttons };
- };
-
- // Removing buttons when checkbox is checked or unchecked
- useEffect(() => {
- if (getExample) {
- const { message }: any = getTemplateAndButton(getPlainTextFromEditor(getExample));
- onExampleChange(message || '');
- }
- }, [isAddButtonChecked]);
-
- // Converting buttons to template and vice-versa to show realtime update on simulator
- useEffect(() => {
- if (templateButtons.length > 0) {
- const parse = convertButtonsToTemplate(templateButtons, templateType);
-
- const parsedText = parse.length ? `| ${parse.join(' | ')}` : null;
-
- const { message }: any = getTemplateAndButton(getPlainTextFromEditor(example));
-
- const sampleText: any = parsedText && message + parsedText;
-
- if (sampleText) {
- onExampleChange(sampleText);
- }
- }
- }, [templateButtons]);
-
const handeInputChange = (event: any, row: any, index: any, eventType: any) => {
const { value } = event.target;
const obj = { ...row };
@@ -734,7 +711,7 @@ const Template = ({
component: Checkbox,
title: Add buttons,
name: 'isAddButtonChecked',
- disabled: !!(defaultAttribute.isHsm && params.id),
+ disabled: !!(defaultAttribute.isHsm && params.id && !isCopyState),
handleChange: (value: boolean) => setIsAddButtonChecked(value),
},
{
@@ -742,7 +719,7 @@ const Template = ({
isAddButtonChecked,
templateType,
inputFields: templateButtons,
- disabled: !!params.id,
+ disabled: isEditing,
onAddClick: addTemplateButtons,
onRemoveClick: removeTemplateButtons,
onInputChange: handeInputChange,
@@ -755,7 +732,7 @@ const Template = ({
name: 'tagId',
options: tag ? tag.tags : [],
optionLabel: 'label',
- disabled: false,
+ disabled: isEditing,
hasCreateOption: true,
multiple: false,
onChange: (value: any) => {
@@ -1001,8 +978,9 @@ const Template = ({
}
};
- if (languageOptions.length < 1 || templateLoading) {
- return ;
+ let copyMessage = t('Copy of the speed send has been created!');
+ if (defaultAttribute.isHsm) {
+ copyMessage = t('Copy of the template has been created!');
}
return (
@@ -1011,7 +989,7 @@ const Template = ({
states={states}
setStates={setStates}
setPayload={setPayload}
- validationSchema={isEditForm ? Yup.object() : FormSchema}
+ validationSchema={isEditing ? Yup.object() : FormSchema}
listItemName={listItemName}
dialogMessage={dialogMessage}
formFields={fields}
@@ -1029,6 +1007,8 @@ const Template = ({
customStyles={customStyle}
saveOnPageChange={false}
afterSave={!defaultAttribute.isHsm ? afterSave : undefined}
+ type={mode}
+ copyNotification={copyMessage}
/>
);
};
diff --git a/src/containers/Template/List/Template.tsx b/src/containers/Template/List/Template.tsx
index 81aa73601..cf3df953c 100644
--- a/src/containers/Template/List/Template.tsx
+++ b/src/containers/Template/List/Template.tsx
@@ -1,10 +1,11 @@
import { useContext, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import moment from 'moment';
import { useTranslation } from 'react-i18next';
import { Checkbox, FormControlLabel } from '@mui/material';
+import { useMutation, useQuery } from '@apollo/client';
import { List } from 'containers/List/List';
-import { useMutation, useQuery } from '@apollo/client';
import { WhatsAppToJsx } from 'common/RichEditor';
import { DATE_TIME_FORMAT, GUPSHUP_ENTERPRISE_SHORTCODE } from 'common/constants';
import {
@@ -22,6 +23,7 @@ import DownArrow from 'assets/images/icons/DownArrow.svg?react';
import ApprovedIcon from 'assets/images/icons/Template/Approved.svg?react';
import RejectedIcon from 'assets/images/icons/Template/Rejected.svg?react';
import PendingIcon from 'assets/images/icons/Template/Pending.svg?react';
+import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react';
import { ProviderContext } from 'context/session';
import { copyToClipboardMethod, exportCsvFile, getFileExtension } from 'common/utils';
import Loading from 'components/UI/Layout/Loading/Loading';
@@ -80,6 +82,7 @@ export const Template = ({
const [open, setOpen] = useState(false);
const [Id, setId] = useState('');
const { t } = useTranslation();
+ const navigate = useNavigate();
const { provider } = useContext(ProviderContext);
const [selectedTag, setSelectedTag] = useState(null);
@@ -223,6 +226,14 @@ export const Template = ({
}
};
+ const setCopyDialog = (id: any) => {
+ let redirectPath = 'speed-send';
+ if (isHSM) {
+ redirectPath = 'template';
+ }
+ navigate(`/${redirectPath}/${id}/edit`, { state: 'copy' });
+ };
+
const setDialog = (id: string) => {
if (Id !== id) {
setId(id);
@@ -232,6 +243,13 @@ export const Template = ({
}
};
+ const copyAction = {
+ label: t('Make a copy'),
+ icon: ,
+ parameter: 'id',
+ dialog: setCopyDialog,
+ };
+
let additionalAction: any = () => [
{
label: t('Show all languages'),
@@ -239,6 +257,7 @@ export const Template = ({
parameter: 'id',
dialog: setDialog,
},
+ copyAction,
];
let defaultSortBy;
@@ -292,6 +311,7 @@ export const Template = ({
parameter: 'id',
dialog: copyUuid,
},
+ copyAction,
];
defaultSortBy = 'STATUS';
appliedFilters = { ...templateFilters, status: filterValue };
diff --git a/src/containers/Trigger/TriggerList/TriggerList.tsx b/src/containers/Trigger/TriggerList/TriggerList.tsx
index a72055949..67d77b739 100644
--- a/src/containers/Trigger/TriggerList/TriggerList.tsx
+++ b/src/containers/Trigger/TriggerList/TriggerList.tsx
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
import TriggerIcon from 'assets/images/icons/Trigger/Union.svg?react';
import ClockIcon from 'assets/images/icons/Trigger/Clock.svg?react';
import ClockInactiveIcon from 'assets/images/icons/Trigger/Inactive.svg?react';
-import DuplicateIcon from 'assets/images/icons/Flow/Duplicate.svg?react';
+import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react';
import { TRIGGER_LIST_QUERY, TRIGGER_QUERY_COUNT } from 'graphql/queries/Trigger';
import { DELETE_TRIGGER } from 'graphql/mutations/Trigger';
import { FULL_DATE_FORMAT, dayList } from 'common/constants';
diff --git a/src/i18n/en/en.json b/src/i18n/en/en.json
index 359f15221..610e51e6d 100644
--- a/src/i18n/en/en.json
+++ b/src/i18n/en/en.json
@@ -373,6 +373,8 @@
"Message is required.": "Message is required.",
"Please enter valid phone number.": "Please enter valid phone number.",
"Please enter valid url.": "Please enter valid url.",
+ "Copy of the speed send has been created!": "",
+ "Copy of the template has been created!": "",
"Submit for Approval": "Submit for Approval",
"Create": "Create",
"Create Speed Send": "Create Speed Send",
@@ -393,6 +395,7 @@
"Change assignee": "Change assignee",
"Remarks": "Remarks",
"Update ticket": "Update ticket",
+ "ID": "ID",
"Created at": "Created at",
"Issue": "Issue",
"Opened by": "Opened by",
@@ -433,6 +436,5 @@
"Request header": "Request header",
"Request JSON": "Request JSON",
"Response JSON": "Response JSON",
- "Webhook Logs": "Webhook Logs",
- "ID": "ID"
+ "Webhook Logs": "Webhook Logs"
}