Improve configuration instructions (#322)
* Add helper texts * Add instruction components * Add changeset * Fix new tab opening * Update and move id generation to the single location * Remove unused code * Apply suggestions from code review Co-authored-by: Dawid <tarasiukdawid@gmail.com> --------- Co-authored-by: Dawid <tarasiukdawid@gmail.com>
This commit is contained in:
parent
14ac6144c0
commit
9d625fc405
13 changed files with 232 additions and 13 deletions
5
.changeset/cold-bugs-remember.md
Normal file
5
.changeset/cold-bugs-remember.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"saleor-app-emails-and-messages": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve instructions for the app configuration
|
10
apps/emails-and-messages/src/lib/generate-random-id.ts
Normal file
10
apps/emails-and-messages/src/lib/generate-random-id.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/**
|
||||||
|
* Generates a random id containing current time and random string.
|
||||||
|
*/
|
||||||
|
export const generateRandomId = () => {
|
||||||
|
const date = new Date();
|
||||||
|
const offsetInMinutes = date.getTimezoneOffset();
|
||||||
|
const randomDate = date.setMinutes(date.getMinutes() + offsetInMinutes).valueOf();
|
||||||
|
const randomString = (Math.random() + 1).toString(36).substring(7);
|
||||||
|
return `${randomDate}${randomString}`;
|
||||||
|
};
|
|
@ -6,6 +6,7 @@ import { AppColumnsLayout } from "../../ui/app-columns-layout";
|
||||||
import { trpcClient } from "../../trpc/trpc-client";
|
import { trpcClient } from "../../trpc/trpc-client";
|
||||||
import SideMenu from "./side-menu";
|
import SideMenu from "./side-menu";
|
||||||
import { LoadingIndicator } from "../../ui/loading-indicator";
|
import { LoadingIndicator } from "../../ui/loading-indicator";
|
||||||
|
import { Instructions } from "./instructions";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => {
|
const useStyles = makeStyles((theme) => {
|
||||||
return {
|
return {
|
||||||
|
@ -142,6 +143,7 @@ export const ChannelsConfigurationTab = () => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<Instructions />
|
||||||
</AppColumnsLayout>
|
</AppColumnsLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { Paper, Typography } from "@material-ui/core";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => {
|
||||||
|
return {
|
||||||
|
instructionsContainer: {
|
||||||
|
padding: 15,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Instructions = () => {
|
||||||
|
const styles = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper elevation={0} className={styles.instructionsContainer}>
|
||||||
|
<Typography paragraph variant="h4">
|
||||||
|
Welcome to Emails and Messages App!
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph>
|
||||||
|
The application will allow you to send emails and messages to your customers using different
|
||||||
|
services.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography paragraph variant="h4">
|
||||||
|
How to configure the app
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph>
|
||||||
|
Start by creating a new configuration for provider of your choice. You can create multiple
|
||||||
|
configurations and then assign them to channels. Navigate to the relevant tab to configure the provider.
|
||||||
|
</Typography>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,8 +1,7 @@
|
||||||
import { messageEventTypes } from "../../event-handlers/message-event-types";
|
import { messageEventTypes } from "../../event-handlers/message-event-types";
|
||||||
import { MjmlConfig as MjmlConfigurationRoot, MjmlConfiguration } from "./mjml-config";
|
import { MjmlConfig as MjmlConfigurationRoot, MjmlConfiguration } from "./mjml-config";
|
||||||
import { defaultMjmlTemplates, defaultMjmlSubjectTemplates } from "../default-templates";
|
import { defaultMjmlTemplates, defaultMjmlSubjectTemplates } from "../default-templates";
|
||||||
|
import { generateRandomId } from "../../../lib/generate-random-id";
|
||||||
export const generateMjmlConfigurationId = () => Date.now().toString();
|
|
||||||
|
|
||||||
export const getDefaultEventsConfiguration = (): MjmlConfiguration["events"] =>
|
export const getDefaultEventsConfiguration = (): MjmlConfiguration["events"] =>
|
||||||
messageEventTypes.map((eventType) => ({
|
messageEventTypes.map((eventType) => ({
|
||||||
|
@ -77,7 +76,7 @@ const createConfiguration =
|
||||||
// for creating a new configurations, the ID has to be generated
|
// for creating a new configurations, the ID has to be generated
|
||||||
const newConfiguration = {
|
const newConfiguration = {
|
||||||
...mjmlConfiguration,
|
...mjmlConfiguration,
|
||||||
id: generateMjmlConfigurationId(),
|
id: generateRandomId(),
|
||||||
events: getDefaultEventsConfiguration(),
|
events: getDefaultEventsConfiguration(),
|
||||||
};
|
};
|
||||||
mjmlConfigNormalized.configurations.push(newConfiguration);
|
mjmlConfigNormalized.configurations.push(newConfiguration);
|
||||||
|
|
|
@ -136,7 +136,9 @@ export const MjmlConfigurationForm = (props: Props) => {
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
error={!!error}
|
error={!!error}
|
||||||
helperText={error?.message}
|
helperText={
|
||||||
|
error?.message || "Name of the configuration, for example 'Production' or 'Test'"
|
||||||
|
}
|
||||||
{...CommonFieldProps}
|
{...CommonFieldProps}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -182,7 +184,7 @@ export const MjmlConfigurationForm = (props: Props) => {
|
||||||
<TextField
|
<TextField
|
||||||
label="Sender name"
|
label="Sender name"
|
||||||
error={!!error}
|
error={!!error}
|
||||||
helperText={error?.message}
|
helperText={error?.message || "Name which will be presented as author of the email"}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
{...CommonFieldProps}
|
{...CommonFieldProps}
|
||||||
|
@ -198,7 +200,7 @@ export const MjmlConfigurationForm = (props: Props) => {
|
||||||
<TextField
|
<TextField
|
||||||
label="Sender email"
|
label="Sender email"
|
||||||
value={value}
|
value={value}
|
||||||
helperText={error?.message}
|
helperText={error?.message || "Email which will be presented as author of the email"}
|
||||||
error={!!error}
|
error={!!error}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
{...CommonFieldProps}
|
{...CommonFieldProps}
|
||||||
|
@ -221,7 +223,10 @@ export const MjmlConfigurationForm = (props: Props) => {
|
||||||
label="SMTP server host"
|
label="SMTP server host"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
helperText={error?.message}
|
helperText={
|
||||||
|
error?.message ||
|
||||||
|
"Address of the SMTP server, without the protocol. For example 'smtp.example.com'"
|
||||||
|
}
|
||||||
error={!!error}
|
error={!!error}
|
||||||
{...CommonFieldProps}
|
{...CommonFieldProps}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { MjmlConfiguration } from "../mjml-config";
|
||||||
import { LoadingIndicator } from "../../../ui/loading-indicator";
|
import { LoadingIndicator } from "../../../ui/loading-indicator";
|
||||||
import { Add } from "@material-ui/icons";
|
import { Add } from "@material-ui/icons";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { MjmlInstructions } from "./mjml-instructions";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => {
|
const useStyles = makeStyles((theme) => {
|
||||||
return {
|
return {
|
||||||
|
@ -165,6 +166,7 @@ export const MjmlConfigurationTab = ({ configurationId }: MjmlConfigurationTabPr
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<MjmlInstructions />
|
||||||
</AppColumnsLayout>
|
</AppColumnsLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { Link, Paper, Typography } from "@material-ui/core";
|
||||||
|
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => {
|
||||||
|
return {
|
||||||
|
instructionsContainer: {
|
||||||
|
padding: 15,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const MjmlInstructions = () => {
|
||||||
|
const styles = useStyles();
|
||||||
|
|
||||||
|
const { appBridge } = useAppBridge();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper elevation={0} className={styles.instructionsContainer}>
|
||||||
|
<Typography paragraph variant="h4">
|
||||||
|
MJML Provider
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph>
|
||||||
|
You can use this provider to send emails using MJML as a template language. The emails are
|
||||||
|
then sent using the SMTP.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography paragraph>
|
||||||
|
<Link
|
||||||
|
href="https://mjml.io/"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
appBridge?.dispatch(
|
||||||
|
actions.Redirect({
|
||||||
|
to: "https://mjml.io/",
|
||||||
|
newContext: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Visit the MJML Homepage
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph variant="h4">
|
||||||
|
How to configure
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph>
|
||||||
|
Create a new configuration and fill in the required fields. After the configuration is
|
||||||
|
saved, you will be able to modify the email templates.
|
||||||
|
</Typography>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,11 +1,10 @@
|
||||||
|
import { generateRandomId } from "../../../lib/generate-random-id";
|
||||||
import { messageEventTypes } from "../../event-handlers/message-event-types";
|
import { messageEventTypes } from "../../event-handlers/message-event-types";
|
||||||
import {
|
import {
|
||||||
SendgridConfig as SendgridConfigurationRoot,
|
SendgridConfig as SendgridConfigurationRoot,
|
||||||
SendgridConfiguration,
|
SendgridConfiguration,
|
||||||
} from "./sendgrid-config";
|
} from "./sendgrid-config";
|
||||||
|
|
||||||
export const generateSendgridConfigurationId = () => Date.now().toString();
|
|
||||||
|
|
||||||
export const getDefaultEventsConfiguration = (): SendgridConfiguration["events"] =>
|
export const getDefaultEventsConfiguration = (): SendgridConfiguration["events"] =>
|
||||||
messageEventTypes.map((eventType) => ({
|
messageEventTypes.map((eventType) => ({
|
||||||
active: true,
|
active: true,
|
||||||
|
@ -75,7 +74,7 @@ const createConfiguration =
|
||||||
// for creating a new configurations, the ID has to be generated
|
// for creating a new configurations, the ID has to be generated
|
||||||
const newConfiguration = {
|
const newConfiguration = {
|
||||||
...sendgridConfiguration,
|
...sendgridConfiguration,
|
||||||
id: generateSendgridConfigurationId(),
|
id: generateRandomId(),
|
||||||
events: getDefaultEventsConfiguration(),
|
events: getDefaultEventsConfiguration(),
|
||||||
};
|
};
|
||||||
sendgridConfigNormalized.configurations.push(newConfiguration);
|
sendgridConfigNormalized.configurations.push(newConfiguration);
|
||||||
|
|
|
@ -177,7 +177,9 @@ export const SendgridConfigurationForm = (props: Props) => {
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
error={!!error}
|
error={!!error}
|
||||||
helperText={error?.message}
|
helperText={
|
||||||
|
error?.message || "Name of the configuration, for example 'Production' or 'Test'"
|
||||||
|
}
|
||||||
{...CommonFieldProps}
|
{...CommonFieldProps}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -224,7 +226,10 @@ export const SendgridConfigurationForm = (props: Props) => {
|
||||||
label="Sendgrid API key"
|
label="Sendgrid API key"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
helperText={error?.message}
|
helperText={
|
||||||
|
error?.message ||
|
||||||
|
"The API key can be generated at Sendgrid dashboard, in the Settings / API Keys section"
|
||||||
|
}
|
||||||
error={!!error}
|
error={!!error}
|
||||||
{...CommonFieldProps}
|
{...CommonFieldProps}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { Add } from "@material-ui/icons";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { sendgridUrls } from "../../urls";
|
import { sendgridUrls } from "../../urls";
|
||||||
import { SendgridTemplatesCard } from "./sendgrid-templates-card";
|
import { SendgridTemplatesCard } from "./sendgrid-templates-card";
|
||||||
|
import { SendgridInstructions } from "./sendgrid-instructions";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => {
|
const useStyles = makeStyles((theme) => {
|
||||||
return {
|
return {
|
||||||
|
@ -170,6 +171,7 @@ export const SendgridConfigurationTab = ({ configurationId }: SendgridConfigurat
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<SendgridInstructions />
|
||||||
</AppColumnsLayout>
|
</AppColumnsLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
import { Link, Paper, Typography } from "@material-ui/core";
|
||||||
|
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => {
|
||||||
|
return {
|
||||||
|
instructionsContainer: {
|
||||||
|
padding: 15,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const SendgridInstructions = () => {
|
||||||
|
const styles = useStyles();
|
||||||
|
|
||||||
|
const { appBridge } = useAppBridge();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper elevation={0} className={styles.instructionsContainer}>
|
||||||
|
<Typography paragraph variant="h4">
|
||||||
|
Sendgrid Provider
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph>
|
||||||
|
The integration uses dynamic email templates to send the messages to your customers.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography paragraph>
|
||||||
|
<Link
|
||||||
|
href="https://sendgrid.com/"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
appBridge?.dispatch(
|
||||||
|
actions.Redirect({
|
||||||
|
to: "https://sendgrid.com/",
|
||||||
|
newContext: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Visit the Sendgrid Homepage
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph variant="h4">
|
||||||
|
How to configure
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography paragraph>
|
||||||
|
Before configuring the app, make sure you have a Sendgrid account set up. To proceed you
|
||||||
|
will need:
|
||||||
|
<br />
|
||||||
|
<Link
|
||||||
|
href="https://app.sendgrid.com/settings/api_keys"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
appBridge?.dispatch(
|
||||||
|
actions.Redirect({
|
||||||
|
to: "https://app.sendgrid.com/settings/api_keys",
|
||||||
|
newContext: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
API key which can be generated in the Sendgrid dashboard
|
||||||
|
</Link>
|
||||||
|
<br />
|
||||||
|
<Link
|
||||||
|
href="https://app.sendgrid.com/settings/sender_auth"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
appBridge?.dispatch(
|
||||||
|
actions.Redirect({
|
||||||
|
to: "https://app.sendgrid.com/settings/sender_auth",
|
||||||
|
newContext: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Verified sender account
|
||||||
|
</Link>
|
||||||
|
<br />
|
||||||
|
<Link
|
||||||
|
href="https://mc.sendgrid.com/dynamic-templates"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
appBridge?.dispatch(
|
||||||
|
actions.Redirect({
|
||||||
|
to: "https://mc.sendgrid.com/dynamic-templates",
|
||||||
|
newContext: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Created dynamic email templates
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography paragraph>
|
||||||
|
Create a new configuration and fill in the required fields. After the configuration is
|
||||||
|
saved, you will be able to assign the email template to each of the events.
|
||||||
|
</Typography>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
|
@ -4,7 +4,7 @@ import { PropsWithChildren } from "react";
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "280px auto",
|
gridTemplateColumns: "280px auto 400px",
|
||||||
alignItems: "start",
|
alignItems: "start",
|
||||||
gap: theme.spacing(3),
|
gap: theme.spacing(3),
|
||||||
padding: "20px 0",
|
padding: "20px 0",
|
||||||
|
|
Loading…
Reference in a new issue