|
|
|
@ -3,8 +3,9 @@ import { App, Popover, Flex, Button, List, Input } from 'antd';
|
|
|
|
|
import { MessageOutlined, SendOutlined } from '@ant-design/icons';
|
|
|
|
|
import useAuthStore from '@/stores/AuthStore';
|
|
|
|
|
import useConversationStore from '@/stores/ConversationStore';
|
|
|
|
|
import { cloneDeep, getNestedValue, objectMapper } from '@/utils/utils';
|
|
|
|
|
import { cloneDeep, getNestedValue, objectMapper, sortArrayByOrder } from '@/utils/utils';
|
|
|
|
|
import { replaceTemplateString } from '@/lib/msgUtils';
|
|
|
|
|
import { isEmpty } from '@/utils/commons';
|
|
|
|
|
|
|
|
|
|
const splitTemplate = (template) => {
|
|
|
|
|
const placeholders = template.match(/{{(.*?)}}/g) || [];
|
|
|
|
@ -40,7 +41,7 @@ const InputTemplate = ({ mobile, disabled = false, invokeSendMessage }) => {
|
|
|
|
|
const handleSearchTemplates = (val) => {
|
|
|
|
|
if (val.toLowerCase().trim() !== '') {
|
|
|
|
|
const res = templates.filter(
|
|
|
|
|
(item) => item.name.includes(val.toLowerCase().trim()) || item.components_origin.some((itemc) => itemc.text.toLowerCase().includes(val.toLowerCase().trim()))
|
|
|
|
|
(item) => item.name.includes(val.toLowerCase().trim()) || item.components_origin.some((itemc) => (itemc?.text || '').toLowerCase().includes(val.toLowerCase().trim()))
|
|
|
|
|
);
|
|
|
|
|
setDataSource(res);
|
|
|
|
|
return false;
|
|
|
|
@ -57,18 +58,18 @@ const InputTemplate = ({ mobile, disabled = false, invokeSendMessage }) => {
|
|
|
|
|
template: {
|
|
|
|
|
name: fromTemplate.name,
|
|
|
|
|
language: { code: fromTemplate.language },
|
|
|
|
|
components: fromTemplate.components_origin.map((citem) => {
|
|
|
|
|
components: sortArrayByOrder(fromTemplate.components_origin.map((citem) => {
|
|
|
|
|
const keys = ((citem?.text || '').match(/{{(.*?)}}/g) || []).map((key) => key.replace(/{{|}}/g, ''));
|
|
|
|
|
const params = keys.map((v) => ({ type: 'text', text: getNestedValue(mergeInput, [v]) }));
|
|
|
|
|
const paramText = params.map((p) => p.text);
|
|
|
|
|
const fillTemplate = paramText.length ? replaceTemplateString(citem?.text || '', paramText) : citem?.text || '';
|
|
|
|
|
valid = keys.length !== paramText.filter((s) => s).length ? false : valid;
|
|
|
|
|
return {
|
|
|
|
|
return citem.type.toLowerCase() === 'body' ? {
|
|
|
|
|
type: citem.type.toLowerCase(),
|
|
|
|
|
parameters: params,
|
|
|
|
|
text: fillTemplate,
|
|
|
|
|
};
|
|
|
|
|
}),
|
|
|
|
|
} : {...citem, type: citem.type.toLowerCase(),};
|
|
|
|
|
}), 'type', ['header', 'body', 'footer', 'buttons'] ),
|
|
|
|
|
},
|
|
|
|
|
template_origin: fromTemplate,
|
|
|
|
|
};
|
|
|
|
@ -78,6 +79,7 @@ const InputTemplate = ({ mobile, disabled = false, invokeSendMessage }) => {
|
|
|
|
|
description: '信息未填写完整, 请补充填写',
|
|
|
|
|
placement: 'top',
|
|
|
|
|
duration: 3,
|
|
|
|
|
closeIcon: false,
|
|
|
|
|
});
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -92,6 +94,49 @@ const InputTemplate = ({ mobile, disabled = false, invokeSendMessage }) => {
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const renderHeader = ({ tempItem }) => {
|
|
|
|
|
if (isEmpty(tempItem.components.header)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
const headerObj = tempItem.components.header[0];
|
|
|
|
|
return (
|
|
|
|
|
<div className='pb-1'>
|
|
|
|
|
{'text' === headerObj.format.toLowerCase() && <div>{headerObj.text}</div>}
|
|
|
|
|
{'image' === headerObj.format.toLowerCase() && <img src={headerObj.example.header_url} height={100}></img>}
|
|
|
|
|
{['document', 'video'].includes(headerObj.format.toLowerCase()) && (
|
|
|
|
|
<a href={headerObj.example.header_url} target='_blank' key={headerObj.format} rel='noreferrer' className='text-sm'>
|
|
|
|
|
[ {headerObj.format} ]({headerObj.example.header_url})
|
|
|
|
|
</a>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const renderButtons = ({ tempItem }) => {
|
|
|
|
|
if (isEmpty(tempItem.components.buttons)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
const buttons = tempItem.components.buttons.reduce((r, c) => r.concat(c.buttons), []);
|
|
|
|
|
return (
|
|
|
|
|
<div className='flex gap-1 pt-1'>
|
|
|
|
|
{buttons.map((btn, index) =>
|
|
|
|
|
btn.type.toLowerCase() === 'url' ? (
|
|
|
|
|
<Button className='text-blue-500' size={'small'} href={btn.url} target={'_blank'} key={btn.url} rel='noreferrer'>
|
|
|
|
|
{btn.text}
|
|
|
|
|
</Button>
|
|
|
|
|
) : btn.type.toLowerCase() === 'phone_number' ? (
|
|
|
|
|
<Button className='text-blue-500' size={'small'} key={btn.phone_number} rel='noreferrer'>
|
|
|
|
|
{btn.text} ({btn.phone_number})
|
|
|
|
|
</Button>
|
|
|
|
|
) : (
|
|
|
|
|
<Button className='text-blue-500' size={'small'} key={btn.type} rel='noreferrer'>
|
|
|
|
|
{btn.text}
|
|
|
|
|
</Button>
|
|
|
|
|
)
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const renderForm = ({ tempItem }) => {
|
|
|
|
|
const templateText = tempItem.components.body?.[0]?.text || '';
|
|
|
|
|
const tempArr = splitTemplate(templateText);
|
|
|
|
@ -167,8 +212,10 @@ const InputTemplate = ({ mobile, disabled = false, invokeSendMessage }) => {
|
|
|
|
|
description={
|
|
|
|
|
<>
|
|
|
|
|
<div className=' max-h-32 overflow-y-auto divide-dashed divide-x-0 divide-y divide-gray-300'>
|
|
|
|
|
<div className='text-slate-500'>{renderForm({ tempItem: item })}</div>
|
|
|
|
|
{renderHeader({ tempItem: item })}
|
|
|
|
|
<div className='text-slate-500 py-1'>{renderForm({ tempItem: item })}</div>
|
|
|
|
|
{item.components?.footer?.[0] ? <div className=''>{item.components.footer[0].text || ''}</div> : null}
|
|
|
|
|
{renderButtons({ tempItem: item })}
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
}
|
|
|
|
|