first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
import {useFormContext} from 'react-hook-form';
import {AdminSettings} from '../../admin-settings';
import {useSocialLogin} from '../../../../auth/requests/use-social-login';
import {toast} from '../../../../ui/toast/toast';
import {message} from '../../../../i18n/message';
import {Button} from '../../../../ui/buttons/button';
import {GmailIcon} from './gmail-icon';
import {Trans} from '../../../../i18n/trans';
import {Fragment} from 'react';
export function ConnectGmailPanel() {
const {watch, setValue} = useFormContext<AdminSettings>();
const {connectSocial} = useSocialLogin();
const connectedEmail = watch('server.connectedGmailAccount');
const handleGmailConnect = async () => {
const e = await connectSocial('secure/settings/mail/gmail/connect');
if (e?.status === 'SUCCESS') {
const email = (e.callbackData as any).profile.email;
setValue('server.connectedGmailAccount', email);
toast(message('Connected gmail account: :email', {values: {email}}));
}
};
const connectButton = (
<Button
variant="outline"
color="primary"
startIcon={<GmailIcon />}
onClick={() => {
handleGmailConnect();
}}
>
<Trans message="Connect gmail account" />
</Button>
);
const reconnectPanel = (
<div className="flex items-center gap-14 rounded border bg-alt px-14 py-6 text-sm">
<GmailIcon size="lg" />
{connectedEmail}
<Button
variant="text"
color="primary"
className="ml-auto"
onClick={() => {
handleGmailConnect();
}}
>
<Trans message="Reconnect" />
</Button>
</div>
);
return (
<Fragment>
<div className="mb-6 text-sm">
<Trans message="Gmail account" />
</div>
{connectedEmail ? reconnectPanel : connectButton}
</Fragment>
);
}

View File

@@ -0,0 +1,33 @@
import {createSvgIcon} from '../../../../icons/create-svg-icon';
export const GmailIcon = createSvgIcon(
[
<path
key="0"
fill="#4caf50"
d="M45,16.2l-5,2.75l-5,4.75L35,40h7c1.657,0,3-1.343,3-3V16.2z"
/>,
<path
key="1"
fill="#1e88e5"
d="M3,16.2l3.614,1.71L13,23.7V40H6c-1.657,0-3-1.343-3-3V16.2z"
/>,
<polygon
key="2"
fill="#e53935"
points="35,11.2 24,19.45 13,11.2 12,17 13,23.7 24,31.95 35,23.7 36,17"
/>,
<path
key="3"
fill="#c62828"
d="M3,12.298V16.2l10,7.5V11.2L9.876,8.859C9.132,8.301,8.228,8,7.298,8h0C4.924,8,3,9.924,3,12.298z"
/>,
<path
key="4"
fill="#fbc02d"
d="M45,12.298V16.2l-10,7.5V11.2l3.124-2.341C38.868,8.301,39.772,8,40.702,8h0 C43.076,8,45,9.924,45,12.298z"
/>,
],
'Gmail',
'0 0 48 48'
);

View File

@@ -0,0 +1,40 @@
import {Fragment} from 'react';
import {FormTextField} from '../../../../ui/forms/input-field/text-field/text-field';
import {Trans} from '../../../../i18n/trans';
export interface MailgunCredentialsProps {
isInvalid: boolean;
}
export function MailgunCredentials({isInvalid}: MailgunCredentialsProps) {
return (
<Fragment>
<FormTextField
invalid={isInvalid}
className="mb-30"
name="server.mailgun_domain"
label={<Trans message="Mailgun domain" />}
description={
<Trans message="Usually the domain of your site (site.com)" />
}
required
/>
<FormTextField
invalid={isInvalid}
className="mb-30"
name="server.mailgun_secret"
label={<Trans message="Mailgun API key" />}
description={<Trans message="Should start with `key-`" />}
required
/>
<FormTextField
invalid={isInvalid}
name="server.mailgun_endpoint"
label={<Trans message="Mailgun endpoint" />}
description={
<Trans message="Can be left empty, if your mailgun account is in the US region." />
}
placeholder="api.eu.mailgun.net"
/>
</Fragment>
);
}

View File

@@ -0,0 +1,73 @@
import {SettingsPanel} from '../../settings-panel';
import {FormTextField} from '../../../../ui/forms/input-field/text-field/text-field';
import {ExternalLink} from '../../../../ui/buttons/external-link';
import {SectionHelper} from '../../../../ui/section-helper';
import {SettingsSeparator} from '../../settings-separator';
import {Trans} from '../../../../i18n/trans';
import {OutgoingMailGroup} from './outgoing-mail-group';
import {useSettings} from '../../../../core/settings/use-settings';
export function OutgoingEmailSettings() {
return (
<SettingsPanel
title={<Trans message="Outgoing email settings" />}
description={
<Trans message="Change outgoing email handlers, email credentials and other related settings." />
}
>
<FormTextField
id="outgoing-emails"
className="mb-30"
type="email"
name="server.mail_from_address"
label={<Trans message="From address" />}
description={
<Trans message="All outgoing application emails will be sent from this email address." />
}
required
/>
<ContactAddressSection />
<FormTextField
className="mb-30"
name="server.mail_from_name"
label={<Trans message="From name" />}
description={
<Trans message="All outgoing application emails will be sent using this name." />
}
required
/>
<SectionHelper
color="warning"
description={
<Trans message="Your selected mail method must be authorized to send emails using this address and name." />
}
/>
<SettingsSeparator />
<OutgoingMailGroup />
</SettingsPanel>
);
}
function ContactAddressSection() {
const {base_url} = useSettings();
const contactPageUrl = `${base_url}/contact`;
const link = (
<ExternalLink href={contactPageUrl}>{contactPageUrl}</ExternalLink>
);
return (
<FormTextField
className="mb-30"
type="email"
name="client.mail.contact_page_address"
label={<Trans message="Contact page address" />}
description={
<Trans
values={{
contactPageUrl: link,
}}
message="Where emails from :contactPageUrl page should be sent to."
/>
}
/>
);
}

View File

@@ -0,0 +1,81 @@
import {useFormContext} from 'react-hook-form';
import {AdminSettings} from '../../admin-settings';
import {ComponentType, Fragment} from 'react';
import {MailgunCredentials} from './mailgun-credentials';
import {SmtpCredentials} from './smtp-credentials';
import {SesCredentials} from './ses-credentials';
import {PostmarkCredentials} from './postmark-credentials';
import {ConnectGmailPanel} from './connect-gmail-panel';
import {SettingsErrorGroup} from '../../settings-error-group';
import {FormSelect, Option} from '../../../../ui/forms/select/select';
import {Trans} from '../../../../i18n/trans';
import {LearnMoreLink} from '../../learn-more-link';
export function OutgoingMailGroup() {
const {watch, clearErrors} = useFormContext<AdminSettings>();
const selectedDriver = watch('server.mail_driver');
const credentialForms: ComponentType<{isInvalid: boolean}>[] = [];
if (selectedDriver === 'mailgun') {
credentialForms.push(MailgunCredentials);
}
if (selectedDriver === 'smtp') {
credentialForms.push(SmtpCredentials);
}
if (selectedDriver === 'ses') {
credentialForms.push(SesCredentials);
}
if (selectedDriver === 'postmark') {
credentialForms.push(PostmarkCredentials);
}
if (selectedDriver === 'gmailApi') {
credentialForms.push(ConnectGmailPanel);
}
return (
<SettingsErrorGroup
separatorTop={false}
separatorBottom={false}
name="mail_group"
>
{isInvalid => (
<Fragment>
<FormSelect
onSelectionChange={() => {
clearErrors();
}}
invalid={isInvalid}
selectionMode="single"
name="server.mail_driver"
label={<Trans message="Outgoing mail method" />}
description={
<div>
<Trans message="Which method should be used for sending outgoing application emails (like registration confirmation)" />
<LearnMoreLink
className="mt-8"
link="https://support.vebto.com/hc/articles/42/44/155/incoming-emails"
/>
</div>
}
>
<Option value="mailgun">Mailgun</Option>
<Option value="gmailApi">Gmail Api</Option>
<Option value="smtp">SMTP</Option>
<Option value="postmark">Postmark</Option>
<Option value="ses">Ses (Amazon Simple Email Service)</Option>
<Option value="sendmail">SendMail</Option>
<Option value="log">Log (Email will be saved to error log)</Option>
</FormSelect>
{credentialForms.length ? (
<div className="mt-30">
{credentialForms.map((CredentialsForm, index) => (
<CredentialsForm key={index} isInvalid={isInvalid} />
))}
</div>
) : null}
</Fragment>
)}
</SettingsErrorGroup>
);
}

View File

@@ -0,0 +1,16 @@
import {FormTextField} from '../../../../ui/forms/input-field/text-field/text-field';
import {Trans} from '../../../../i18n/trans';
export interface PostmarkCredentialsProps {
isInvalid: boolean;
}
export function PostmarkCredentials({isInvalid}: PostmarkCredentialsProps) {
return (
<FormTextField
invalid={isInvalid}
name="server.postmark_token"
label={<Trans message="Postmark token" />}
required
/>
);
}

View File

@@ -0,0 +1,34 @@
import {FormTextField} from '../../../../ui/forms/input-field/text-field/text-field';
import {Trans} from '../../../../i18n/trans';
import {Fragment} from 'react';
export interface SesCredentialsProps {
isInvalid: boolean;
}
export function SesCredentials({isInvalid}: SesCredentialsProps) {
return (
<Fragment>
<FormTextField
invalid={isInvalid}
className="mb-30"
name="server.ses_key"
label={<Trans message="SES key" />}
required
/>
<FormTextField
invalid={isInvalid}
className="mb-30"
name="server.ses_secret"
label={<Trans message="SES secret" />}
required
/>
<FormTextField
invalid={isInvalid}
name="server.ses_region"
label={<Trans message="SES region" />}
placeholder="us-east-1"
required
/>
</Fragment>
);
}

View File

@@ -0,0 +1,57 @@
import {FormTextField} from '../../../../ui/forms/input-field/text-field/text-field';
import {Trans} from '../../../../i18n/trans';
import {FormSelect} from '@common/ui/forms/select/select';
import {Item} from '@common/ui/forms/listbox/item';
export interface SmtpCredentialsProps {
isInvalid: boolean;
}
export function SmtpCredentials({isInvalid}: SmtpCredentialsProps) {
return (
<>
<FormTextField
invalid={isInvalid}
className="mb-30"
name="server.mail_host"
label={<Trans message="SMTP host" />}
required
/>
<FormTextField
invalid={isInvalid}
className="mb-30"
name="server.mail_username"
label={<Trans message="SMTP username" />}
required
/>
<FormTextField
invalid={isInvalid}
className="mb-30"
type="password"
name="server.mail_password"
label={<Trans message="SMTP password" />}
required
/>
<FormTextField
invalid={isInvalid}
className="mb-30"
type="number"
name="server.mail_port"
label={<Trans message="SMTP port" />}
/>
<FormSelect
selectionMode="single"
invalid={isInvalid}
className="mb-30"
name="server.mail_encryption"
label={<Trans message="SMTP encryption" />}
>
<Item value="">
<Trans message="None" />
</Item>
<Item value="tls">
<Trans message="TLS" />
</Item>
</FormSelect>
</>
);
}