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:
Krzysztof Wolski 2023-03-24 17:12:45 +01:00 committed by GitHub
parent 14ac6144c0
commit 9d625fc405
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 232 additions and 13 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-app-emails-and-messages": patch
---
Improve instructions for the app configuration

View 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}`;
};

View file

@ -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>
); );
}; };

View file

@ -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>
);
};

View file

@ -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);

View file

@ -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}
/> />

View file

@ -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>
); );
}; };

View file

@ -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>
);
};

View file

@ -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);

View file

@ -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}
/> />

View file

@ -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>
); );
}; };

View file

@ -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>
);
};

View file

@ -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",