Skip to content

Commit

Permalink
new mail editor
Browse files Browse the repository at this point in the history
  • Loading branch information
Zwiterrion committed Sep 26, 2024
1 parent e2d846e commit c32aac0
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 43 deletions.
5 changes: 2 additions & 3 deletions daikoku/app/utils/ApiService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2617,7 +2617,6 @@ class ApiService(
} yield Ok(Json.obj("creation" -> "refused"))
}

<<<<<<< HEAD
def getApis[T](ctx: ApiActionContext[T], notDeleted: Boolean = false) = {
val repo = env.dataStore.apiRepo.forTenant(ctx.tenant)

Expand All @@ -2644,7 +2643,8 @@ class ApiService(
}
})
}
=======


case class ExtractTransferLink(
subscription: ApiSubscription,
childSubscriptions: Seq[ApiSubscription],
Expand Down Expand Up @@ -2829,5 +2829,4 @@ class ApiService(
)
)
} yield result
>>>>>>> master
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import { CodeInput, Form, format, SelectInput, type } from '@maif/react-forms';
import { useContext, useEffect, useRef, useState } from "react";
import { I18nContext } from "../../../contexts";

import showdown from 'showdown';
import classNames from 'classnames';

import '@fortawesome/fontawesome-free/css/all.css';
import 'highlight.js/styles/monokai.css';
import { getCmsPage, getMailTranslations } from '../../../services';
import { PillButton } from '../../inputs/PillButton';
import { CmsViewer } from '../../frontend/CmsViewer'
import Select from 'react-select';

function extractRequiredVariables(str?: string) {
const dels: Array<number> = [];
const words: Array<string> = [];

if (!str)
return []

for (let i = 0; i < str.length; i++) {
if (str[i] === '[') {
dels.push(i);
} else if (str[i] === ']' && dels.length > 0) {
let pos = dels[dels.length - 1];
dels.pop();

const len = i - 1 - pos;
words.push(str.substring(pos + 1, (pos < len ? len : len + pos) + 1));
}
}
return words;
}

function overwriteParameters(parameters, content) {
let out = content;
for (const parameter in parameters) {
out = out?.replace(`[${parameters[parameter]}]`, "COUCOU")
}
return out;
}

const converter = new showdown.Converter({
omitExtraWLInCodeBlocks: true,
ghCompatibleHeaderId: true,
parseImgDimensions: true,
simplifiedAutoLink: true,
tables: true,
tasklists: true,
requireSpaceBeforeHeadingText: true,
ghMentions: true,
emoji: true,
ghMentionsLink: '/{u}'
});

interface Range {
from: any;
to: any;
}


const commands = [
{
name: 'Add header',
icon: 'heading',
inject: (range: Range) => [{ from: range.from, insert: "# " }]
},
{
name: 'Add bold text',
icon: 'bold',
inject: (range: Range) => [{ from: range.from, insert: "**" }, { from: range.to, insert: '**' }]
},
{
name: 'Add italic text',
icon: 'italic',
inject: (range: Range) => [{ from: range.from, insert: '*' }, { from: range.to, insert: '*' }]
},
{
name: 'Add strikethrough text',
icon: 'strikethrough',
inject: (range: Range) => [{ from: range.from, insert: '~~' }, { from: range.to, insert: '~~' }]
},
{
name: 'Add link',
icon: 'link',
inject: (range: Range) => [{ from: range.from, insert: '[' }, { from: range.to, insert: '](url)' }]
},
{
name: 'Add code',
icon: 'code',
inject: (range: Range) => [{ from: range.from, insert: '```\n' }, { from: range.to, insert: '\n```\n' }]
},
{
name: 'Add quotes',
icon: 'quote-right',
inject: (range: Range) => [{ from: range.from, insert: '> ' }]
},
{
name: 'Add image',
icon: 'image',
inject: (range: Range) => [{ from: range.from, insert: '![' }, { from: range.to, insert: '](image-url)' }]
},
{
name: 'Add unordered list',
icon: 'list-ul',
inject: (range: Range) => [{ from: range.from, insert: '* ' }]
},
{
name: 'Add ordered list',
icon: 'list-ol',
inject: (range: Range) => [{ from: range.from, insert: '1. ' }]
},
{
name: 'Add check list',
icon: 'tasks',
inject: (range: Range) => [{ from: range.from, insert: '* [ ] ' }]
}
];

export function MailInput({ onSubmit, _id, translations, rawContent, defaultRawContent }) {

// const { translate } = useContext(I18nContext);

const [email, setEmail] = useState()
const [useCmsPage, toggleCmsPage] = useState(false)
const [language, toggleLanguage] = useState("fr")

const [cmsPage, setCmsPage] = useState()

const [emails, setEmails] = useState([])

let parameters = extractRequiredVariables(translations.find(t => t.language === language)?.value)

if (parameters?.includes('email')) {
parameters = [
...parameters,
...extractRequiredVariables(email)
]
}

useEffect(() => {
getCmsPage(`${_id}${language}`, {
email,
})
.then(content => setCmsPage(content))
}, [_id, language])

useEffect(() => {
getMailTranslations()
// @ts-ignore
.then(r => r.translations
.sort((a, b) => a._id.split(".")[1] < b._id.split(".")[1] ? -1 : 1)
.map(r => ({ label: r._id, value: r.content })))
.then(setEmails)

}, [])

const ref = useRef()

const cmsPageWithParameters = overwriteParameters(parameters, cmsPage)

return <div className='d-flex gap-3'>
<div style={{
flex: 1
}}>
<div className='h5 mb-2'>Format du mail</div>
<PillButton
className='mb-3'
leftText="En ligne"
rightText="Page de CMS"
onLeftClick={() => toggleCmsPage(false)}
onRightClick={() => toggleCmsPage(true)}
rightEnabled={!useCmsPage}
onChange={console.log}
/>
<div className='h5 mb-2'>Contenu</div>
{!useCmsPage && <CodeInput
value={rawContent || defaultRawContent}
onChange={onSubmit}
mode={'markdown'}
setRef={e => ref.current = e} />}

{useCmsPage && <p>La page utilisé est {_id}</p>}
</div>
<div style={{
flex: 1
}} className='section p-3'>
<div>Prévisualisation des mails</div>
<div className=''>
<label className='mb-1 mt-3'>Langue</label>
<PillButton
className='pill-button--small'
leftText="Francais"
rightText="Anglais"
onLeftClick={() => toggleLanguage('fr')}
onRightClick={() => toggleLanguage('en')}
rightEnabled={language === 'fr'}
onChange={toggleLanguage}
/>
</div>
<div className=''>
<label className='mb-1 mt-3'>Paramètres du mail</label>
{parameters?.includes('email') && <Select
// label='[email]'
// placeholder: 'Select a mail to visualize content'
options={emails}
value={email}
onChange={setEmail}
/>}
{parameters.filter(f => f !== 'email').map((acc, c) => {
return <div key={c}>
<label>{c}</label>
<input type="text" value="" />
</div>
})}
</div>
<div className='section mt-3'>
{useCmsPage ?
<div dangerouslySetInnerHTML={{ __html: cmsPageWithParameters, }} /> :
<div
className="mrf-preview "
dangerouslySetInnerHTML={{ __html: converter.makeHtml(rawContent.replace('{{email}}', rawContent) || "") }} />}
</div>

</div>
</div >

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ import { Table, TableRef } from '../../inputs';
import { Can, Option, Spinner, tenant as TENANT, manage } from '../../utils';
import { BeautifulTitle } from '../../utils/BeautifulTitle';
import { EditFrontOfficeTranslations } from './EditFrontOfficeTranslations';
import { MailInput } from './MailInput';

const MAIL_CATEGORIES = [
'subscription', 'new', 'create', 'apikey', 'team', 'api',
'contact', 'user', 'checkout', 'rejection', 'acceptation'
]

const EditMailtemplate = ({
tenantId
}: { tenantId: string }) => {
tenantId,
mails
}: { tenantId: string, mails: any }) => {
const [tenant, setTenant] = useState<ITenantFull>();
const [mailTemplateTranslations, setMailTemplateTranslations] = useState<Array<any>>([]);

Expand Down Expand Up @@ -137,44 +139,37 @@ const EditMailtemplate = ({
}

return (<div className="col-12 pb-3">
<div className="my-3">
<span className="h5">{translate('Default mail template')}</span>
<div className="mt-3">
<div className='d-flex'>
<div className='flex-grow'>
<Form
value={{ value: tenant?.mailerSettings?.template }}
schema={translationSchema}
onSubmit={t => {
saveTenant({
...tenant,
mailerSettings: {
...tenant.mailerSettings,
template: t.value,
},
})
}} />
</div>
<div className='flex-grow d-flex flex-column'>
<span className='h5'>Render</span>
{tenant?.mailerSettings?.template &&
<MarkdownInput className='' preview readOnly />}
<div className='d-flex align-items-center flex-grow'>
<p>Nothing to render</p>
</div>
</div>
</div>
</div>
</div>
{mailTemplateTranslations
<MailInput
defaultRawContent="{{email}}"
rawContent={tenant?.mailerSettings?.template}
translations={mailTemplateTranslations}
_id="-mails-root-tenant-mail-template-"
onSubmit={template => {
setTenant({
...tenant,
mailerSettings: {
...tenant.mailerSettings,
template
}
})
// saveTenant({
// ...tenant,
// mailerSettings: {
// ...tenant.mailerSettings,
// template
// },
// })
}}
title="Default mail template" />
{/* {mailTemplateTranslations
.map((translation) => {
return (<div className="my-3" key={`${translation.key}-${translation.language}`}>
<span className="h5">{translate('Translation')} : {translation.language}</span>
<div className="mt-3">
<Form value={translation} schema={translationSchema} onSubmit={saveTranslation} />
</div>
</div>);
})}
})} */}
</div>);
};

Expand Down Expand Up @@ -378,7 +373,6 @@ export const MailingInternalization = () => {
}, [domain])

useEffect(() => {
console.log('reload table', mails, category)
if (table.current)
table.current.update()
}, [mails, category])
Expand Down
2 changes: 1 addition & 1 deletion daikoku/javascript/src/components/frontend/CmsViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function CmsViewer({ pageId, fields }: CmsViewerProps) {
.then(page => {
setCmsPage(page)
})
}, [pageId])
}, [pageId, fields])

if (cmsPage)
return <div dangerouslySetInnerHTML={{ __html: cmsPage, }} />
Expand Down
6 changes: 3 additions & 3 deletions daikoku/javascript/src/components/inputs/PillButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ export function PillButton({
pillButtonStyle = {},
}) {
return (
<div className={`d-flex justify-content-center ${className}`}>
<div className={`d-flex ${className}`}>
<div
className="p-1"
style={{
borderRadius: '24px',
backgroundColor: 'var(--bg-color_level2)',
color: 'var(--color_level2)',
backgroundColor: "var(--level2_bg-color, #e5e7ea)",
color: "var(--level2_text-color, #4c4c4d)",
position: 'relative',
width: 'fit-content',
...style,
Expand Down
Loading

0 comments on commit c32aac0

Please sign in to comment.