[IMPROVE] Administration -> Mailer Rewrite to React. (#17191)
parent
b57d5ed5d8
commit
03cddfd2da
@ -1,4 +1,2 @@ |
||||
import './mailer.html'; |
||||
import './mailer'; |
||||
import './mailerUnsubscribe.html'; |
||||
import './mailerUnsubscribe'; |
||||
|
||||
@ -1,62 +0,0 @@ |
||||
<template name="mailer"> |
||||
<section class="page-container page-list"> |
||||
{{> header sectionName="Mailer"}} |
||||
<div class="content"> |
||||
{{#unless hasPermission 'access-mailer'}} |
||||
<p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> |
||||
{{else}} |
||||
<form> |
||||
<div class="rocket-form"> |
||||
<fieldset> |
||||
<div class="input-line"> |
||||
<label>{{_ "Email_from"}}</label> |
||||
<div> |
||||
<input type="text" class="rc-input__element" name="from" value="" placeholder="{{fromEmail}}" /> |
||||
</div> |
||||
<div> |
||||
<small class="settings-description secondary-font-color">{{{_ "From_email_warning"}}}</small> |
||||
</div> |
||||
</div> |
||||
<div class="input-line"> |
||||
<label>{{_ "Dry_run"}}</label> |
||||
<div> |
||||
<input type="checkbox" name="dryrun" value="1" /> |
||||
</div> |
||||
<div> |
||||
<small class="settings-description secondary-font-color">{{{_ "Dry_run_description"}}}</small> |
||||
</div> |
||||
</div> |
||||
<div class="input-line"> |
||||
<label>{{_ "Query"}}</label> |
||||
<div> |
||||
<input type="text" class="rc-input__element" name="query" value="" /> |
||||
</div> |
||||
<div> |
||||
<small class="settings-description secondary-font-color">{{{_ "Query_description"}}}</small> |
||||
</div> |
||||
</div> |
||||
<div class="input-line"> |
||||
<label>{{_ "Email_subject"}}</label> |
||||
<div> |
||||
<input type="text" class="rc-input__element" name="subject" value="" /> |
||||
</div> |
||||
</div> |
||||
<div class="input-line"> |
||||
<label>{{_ "Email_body"}}</label> |
||||
<div> |
||||
<textarea class="rc-input__element" name="body" rows="10" style="height: auto"></textarea> |
||||
</div> |
||||
<div> |
||||
<small class="settings-description secondary-font-color">{{{_ "Mailer_body_tags"}}}</small> |
||||
</div> |
||||
</div> |
||||
</fieldset> |
||||
<div class="submit"> |
||||
<button class="button primary send"><i class="icon-send"></i><span>{{_ "Send_email"}}</span></button> |
||||
</div> |
||||
</div> |
||||
</form> |
||||
{{/unless}} |
||||
</div> |
||||
</section> |
||||
</template> |
||||
@ -1,47 +0,0 @@ |
||||
import { Meteor } from 'meteor/meteor'; |
||||
import { Template } from 'meteor/templating'; |
||||
import { Tracker } from 'meteor/tracker'; |
||||
import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; |
||||
import toastr from 'toastr'; |
||||
|
||||
import { settings } from '../../../settings'; |
||||
import { handleError } from '../../../utils'; |
||||
import { SideNav } from '../../../ui-utils/client'; |
||||
|
||||
Template.mailer.helpers({ |
||||
fromEmail() { |
||||
return settings.get('From_Email'); |
||||
}, |
||||
}); |
||||
|
||||
Template.mailer.events({ |
||||
'click .send'(e, t) { |
||||
e.preventDefault(); |
||||
const from = $(t.find('[name=from]')).val(); |
||||
const subject = $(t.find('[name=subject]')).val(); |
||||
const body = $(t.find('[name=body]')).val(); |
||||
const dryrun = $(t.find('[name=dryrun]:checked')).val(); |
||||
const query = $(t.find('[name=query]')).val(); |
||||
if (!from) { |
||||
toastr.error(TAPi18n.__('error-invalid-from-address')); |
||||
return; |
||||
} |
||||
if (body.indexOf('[unsubscribe]') === -1) { |
||||
toastr.error(TAPi18n.__('error-missing-unsubscribe-link')); |
||||
return; |
||||
} |
||||
return Meteor.call('Mailer.sendMail', from, subject, body, dryrun, query, function(err) { |
||||
if (err) { |
||||
return handleError(err); |
||||
} |
||||
return toastr.success(TAPi18n.__('The_emails_are_being_sent')); |
||||
}); |
||||
}, |
||||
}); |
||||
|
||||
Template.mailer.onRendered(() => { |
||||
Tracker.afterFlush(() => { |
||||
SideNav.setFlex('adminFlex'); |
||||
SideNav.openFlex(); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,99 @@ |
||||
import React, { useState } from 'react'; |
||||
import { TextInput, TextAreaInput, Field, FieldGroup, CheckBox, Button, Icon, ButtonGroup } from '@rocket.chat/fuselage'; |
||||
|
||||
import { useTranslation } from '../../../../../client/contexts/TranslationContext'; |
||||
import { Page } from '../../../../../client/components/basic/Page'; |
||||
import { isEmail } from '../../../../utils/lib/isEmail.js'; |
||||
import { isJSON } from '../../../../utils/lib/isJSON.js'; |
||||
|
||||
export function Mailer({ sendMail = () => {}, ...props }) { |
||||
const t = useTranslation(); |
||||
|
||||
const [fromEmail, setFromEmail] = useState({ value: '', error: false }); |
||||
const [dryRun, setDryRun] = useState(false); |
||||
const [query, setQuery] = useState({ value: '', error: false }); |
||||
const [subject, setSubject] = useState(''); |
||||
const [emailBody, setEmailBody] = useState(''); |
||||
|
||||
return <Page _id='mailer' {...props}> |
||||
<Page.Header title={t('Mailer')}></Page.Header> |
||||
<Page.ContentShadowScroll maxWidth='x600' alignSelf='center' display='flex' flexDirection='column'> |
||||
<FieldGroup is='form' method='post'> |
||||
<Field> |
||||
<Field.Label>{t('From')}</Field.Label> |
||||
<Field.Row> |
||||
<TextInput |
||||
id='fromEmail' |
||||
placeholder={t('Type_your_email')} |
||||
value={fromEmail.value} |
||||
error={fromEmail.error} |
||||
onChange={(e) => { |
||||
setFromEmail({ |
||||
value: e.currentTarget.value, |
||||
error: !isEmail(e.currentTarget.value), |
||||
}); |
||||
}} |
||||
/> |
||||
</Field.Row> |
||||
</Field> |
||||
<Field> |
||||
<Field.Row> |
||||
<CheckBox |
||||
id='dryRun' |
||||
checked={dryRun} |
||||
onChange={() => setDryRun(!dryRun)} |
||||
/> |
||||
<Field.Label htmlFor='dry-run'> |
||||
{t('Dry_run')} |
||||
</Field.Label> |
||||
</Field.Row> |
||||
<Field.Hint>{t('Dry_run_description')}</Field.Hint> |
||||
</Field> |
||||
<Field> |
||||
<Field.Label>{t('Query')}</Field.Label> |
||||
<Field.Row> |
||||
<TextInput id='query' |
||||
value={query.value} |
||||
error={query.error} |
||||
onChange={(e) => { |
||||
setQuery({ |
||||
value: e.currentTarget.value, |
||||
error: e.currentTarget.value && !isJSON(e.currentTarget.value), |
||||
}); |
||||
}} |
||||
/> |
||||
</Field.Row> |
||||
<Field.Hint>{t('Query_description')}</Field.Hint> |
||||
</Field> |
||||
<Field> |
||||
<Field.Label>{t('Subject')}</Field.Label> |
||||
<Field.Row> |
||||
<TextInput |
||||
id='subject' |
||||
value={subject.value} |
||||
error={subject.error} |
||||
onChange={(e) => { |
||||
setSubject(e.currentTarget.value); |
||||
}} |
||||
/> |
||||
</Field.Row> |
||||
</Field> |
||||
<Field> |
||||
<Field.Label>{t('Email_body')}</Field.Label> |
||||
<Field.Row> |
||||
<TextAreaInput |
||||
id='emailBody' |
||||
rows={10} |
||||
value={emailBody} |
||||
onChange={(e) => setEmailBody(e.currentTarget.value)} |
||||
/> |
||||
</Field.Row> |
||||
<Field.Hint dangerouslySetInnerHTML={{ __html: t('Mailer_body_tags') }}></Field.Hint> |
||||
</Field> |
||||
<ButtonGroup align='end'> |
||||
<Button primary onClick={() => { sendMail({ fromEmail, dryRun, query, subject, emailBody }); }}><Icon name='send' size='x20' mie='x8'/>{t('Send_email')}</Button> |
||||
</ButtonGroup> |
||||
</FieldGroup> |
||||
</Page.ContentShadowScroll> |
||||
</Page>; |
||||
} |
||||
@ -0,0 +1,11 @@ |
||||
import React from 'react'; |
||||
|
||||
import { Mailer } from './Mailer'; |
||||
|
||||
export default { |
||||
title: 'admin/pages/mailer', |
||||
component: Mailer, |
||||
}; |
||||
|
||||
export const _default = () => |
||||
<Mailer />; |
||||
@ -0,0 +1,37 @@ |
||||
import React from 'react'; |
||||
import toastr from 'toastr'; |
||||
|
||||
import { usePermission } from '../../../../../client/contexts/AuthorizationContext'; |
||||
import { useMethod } from '../../../../../client/contexts/ServerContext'; |
||||
import { useTranslation } from '../../../../../client/contexts/TranslationContext'; |
||||
import { Mailer } from './Mailer'; |
||||
import { NotAuthorizedPage } from '../settings/NotAuthorizedPage'; |
||||
|
||||
|
||||
const useSendMail = () => { |
||||
const meteorSendMail = useMethod('Mailer.sendMail'); |
||||
const t = useTranslation(); |
||||
return ({ fromEmail, subject, emailBody, dryRun, query }) => { |
||||
if (query.error) { |
||||
toastr.error(t('Query_is_not_valid_JSON')); |
||||
return; |
||||
} |
||||
if (fromEmail.error || fromEmail.length < 1) { |
||||
toastr.error(t('error-invalid-from-address')); |
||||
return; |
||||
} |
||||
if (emailBody.indexOf('[unsubscribe]') === -1) { |
||||
toastr.error(t('error-missing-unsubscribe-link')); |
||||
return; |
||||
} |
||||
meteorSendMail(fromEmail.value, subject, emailBody, dryRun, query.value); |
||||
toastr.success(t('The_emails_are_being_sent')); |
||||
}; |
||||
}; |
||||
|
||||
export default function MailerRoute(props) { |
||||
const canAccessMailer = usePermission('access-mailer'); |
||||
const sendMail = useSendMail(); |
||||
|
||||
return canAccessMailer ? <Mailer sendMail={sendMail} {...props} /> : <NotAuthorizedPage/>; |
||||
} |
||||
@ -0,0 +1,7 @@ |
||||
export const isJSON = (value) => { |
||||
try { |
||||
return !!JSON.parse(value); |
||||
} catch { |
||||
return false; |
||||
} |
||||
}; |
||||
Loading…
Reference in new issue