2023-02-09 10:58:20 +00:00
|
|
|
import { useAppBridge, withAuthorization } from "@saleor/app-sdk/app-bridge";
|
|
|
|
import { SALEOR_API_URL_HEADER, SALEOR_AUTHORIZATION_BEARER_HEADER } from "@saleor/app-sdk/const";
|
|
|
|
import { ChangeEvent, ReactElement, SyntheticEvent, useEffect, useState } from "react";
|
|
|
|
|
|
|
|
import { ConfigurationError } from "../components/ConfigurationError/ConfigurationError";
|
2023-04-05 18:27:23 +00:00
|
|
|
import { useAppApi } from "../hooks/useAppApi";
|
2023-02-09 10:58:20 +00:00
|
|
|
import { AppColumnsLayout } from "../components/AppColumnsLayout/AppColumnsLayout";
|
2023-04-14 15:40:49 +00:00
|
|
|
import { useDashboardNotification } from "@saleor/apps-shared";
|
2023-02-09 10:58:20 +00:00
|
|
|
|
2023-06-22 08:32:25 +00:00
|
|
|
import { Input, Text, Box, Button } from "@saleor/macaw-ui/next";
|
2023-06-27 09:45:37 +00:00
|
|
|
|
|
|
|
import { TextLink } from "@saleor/apps-ui";
|
2023-06-22 08:32:25 +00:00
|
|
|
import { AccessWarning } from "../components/AccessWarning/AccessWarning";
|
|
|
|
|
2023-02-09 10:58:20 +00:00
|
|
|
interface ConfigurationField {
|
|
|
|
key: string;
|
|
|
|
value: string;
|
|
|
|
}
|
|
|
|
|
2023-02-09 14:56:52 +00:00
|
|
|
function Configuration() {
|
2023-02-09 10:58:20 +00:00
|
|
|
const { appBridgeState } = useAppBridge();
|
2023-04-14 15:40:49 +00:00
|
|
|
const { notifyError, notifySuccess } = useDashboardNotification();
|
2023-02-09 10:58:20 +00:00
|
|
|
const [configuration, setConfiguration] = useState<ConfigurationField[]>();
|
|
|
|
|
|
|
|
const { data: configurationData, error } = useAppApi<{ data: ConfigurationField[] }>({
|
|
|
|
url: "/api/configuration",
|
|
|
|
});
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (configurationData && !configuration) {
|
|
|
|
setConfiguration(configurationData.data);
|
|
|
|
}
|
|
|
|
}, [configurationData, configuration]);
|
|
|
|
|
|
|
|
const handleSubmit = (event: SyntheticEvent) => {
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
fetch("/api/configuration", {
|
|
|
|
method: "POST",
|
|
|
|
headers: [
|
|
|
|
["content-type", "application/json"],
|
|
|
|
[SALEOR_API_URL_HEADER, appBridgeState?.saleorApiUrl!],
|
|
|
|
[SALEOR_AUTHORIZATION_BEARER_HEADER, appBridgeState?.token!],
|
|
|
|
],
|
|
|
|
body: JSON.stringify({ data: configuration }),
|
|
|
|
})
|
|
|
|
.then(async (response) => {
|
2023-04-14 15:40:49 +00:00
|
|
|
notifySuccess("Success", "Configuration updated successfully");
|
2023-02-09 10:58:20 +00:00
|
|
|
})
|
|
|
|
.catch(async () => {
|
2023-04-14 15:40:49 +00:00
|
|
|
await notifyError("Configuration update failed");
|
2023-02-09 10:58:20 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const onChange = (event: ChangeEvent) => {
|
|
|
|
const { name, value } = event.target as HTMLInputElement;
|
2023-04-18 13:10:00 +00:00
|
|
|
|
2023-02-09 10:58:20 +00:00
|
|
|
setConfiguration((prev) =>
|
|
|
|
prev!.map((prevField) => (prevField.key === name ? { ...prevField, value } : prevField))
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
console.error("Can't establish connection with the App API: ", error);
|
2023-02-09 14:56:52 +00:00
|
|
|
return <ConfigurationError />;
|
2023-02-09 10:58:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (configuration === undefined) {
|
2023-06-22 08:32:25 +00:00
|
|
|
return <Text>Loading</Text>;
|
2023-02-09 10:58:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
|
|
{configuration!.map(({ key, value }) => (
|
2023-06-22 08:32:25 +00:00
|
|
|
<div key={key}>
|
2023-06-22 08:47:39 +00:00
|
|
|
<Input
|
|
|
|
label={key}
|
|
|
|
name={key}
|
|
|
|
onChange={onChange}
|
|
|
|
value={value}
|
|
|
|
helperText={
|
|
|
|
"This webhook will be called when new order is created and `order_created` event is triggered."
|
|
|
|
}
|
|
|
|
/>
|
2023-02-09 10:58:20 +00:00
|
|
|
</div>
|
|
|
|
))}
|
2023-06-22 08:47:39 +00:00
|
|
|
<Box marginTop={4}>
|
2023-06-22 08:32:25 +00:00
|
|
|
<Button type="submit" variant="primary">
|
|
|
|
Save
|
|
|
|
</Button>
|
2023-06-22 08:47:39 +00:00
|
|
|
</Box>
|
2023-02-09 10:58:20 +00:00
|
|
|
</form>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function Instructions() {
|
|
|
|
const { appBridge } = useAppBridge();
|
|
|
|
|
|
|
|
const { data } = useAppApi({
|
|
|
|
url: "/api/slack-app-manifest",
|
|
|
|
});
|
|
|
|
|
|
|
|
const slackUrl = new URL("https://api.slack.com/apps");
|
2023-04-18 13:10:00 +00:00
|
|
|
|
2023-02-09 10:58:20 +00:00
|
|
|
slackUrl.searchParams.append("new_app", "1");
|
|
|
|
slackUrl.searchParams.append("manifest_json", JSON.stringify(data));
|
|
|
|
|
|
|
|
const openExternalUrl = (to: string) => {
|
|
|
|
appBridge?.dispatch({
|
|
|
|
type: "redirect",
|
|
|
|
payload: {
|
|
|
|
newContext: true,
|
|
|
|
actionId: "redirect_from_slack_app",
|
|
|
|
to,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
2023-06-27 09:45:37 +00:00
|
|
|
<Text variant={"heading"}>How to configure</Text>
|
|
|
|
<Box display={"flex"} gap={2} as={"ul"} flexDirection={"column"}>
|
2023-06-22 08:32:25 +00:00
|
|
|
<li>
|
2023-06-27 09:45:37 +00:00
|
|
|
<TextLink href={slackUrl.href}>1. Install Slack application</TextLink>
|
2023-06-22 08:32:25 +00:00
|
|
|
</li>
|
|
|
|
<li>
|
2023-06-22 08:47:39 +00:00
|
|
|
<Text>
|
2023-06-27 09:45:37 +00:00
|
|
|
2. Copy incoming Webhook URL from Slack app configuration and paste it below into{" "}
|
|
|
|
<Text variant={"bodyStrong"}>WEBHOOK_URL</Text> field
|
2023-06-22 08:47:39 +00:00
|
|
|
</Text>
|
2023-06-22 08:32:25 +00:00
|
|
|
</li>
|
2023-06-27 09:45:37 +00:00
|
|
|
<li>
|
|
|
|
<Text>3. Save configuration</Text>
|
|
|
|
</li>
|
|
|
|
</Box>
|
|
|
|
<Text variant={"heading"}>Useful links</Text>
|
2023-06-22 08:32:25 +00:00
|
|
|
<ul>
|
|
|
|
<li>
|
2023-06-27 09:45:37 +00:00
|
|
|
<TextLink newTab href={"https://api.slack.com/messaging/webhooks"}>
|
|
|
|
Read about Slack apps that use incoming webhooks
|
|
|
|
</TextLink>
|
2023-06-22 08:32:25 +00:00
|
|
|
</li>
|
|
|
|
</ul>
|
2023-02-09 10:58:20 +00:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const ConfigurationWithAuth = withAuthorization({
|
|
|
|
notIframe: <AccessWarning cause="not_in_iframe" />,
|
|
|
|
unmounted: null,
|
|
|
|
noDashboardToken: <AccessWarning cause="missing_access_token" />,
|
|
|
|
dashboardTokenInvalid: <AccessWarning cause="invalid_access_token" />,
|
|
|
|
})(Configuration);
|
|
|
|
|
|
|
|
ConfigurationWithAuth.getLayout = (page: ReactElement) => (
|
2023-02-28 19:18:34 +00:00
|
|
|
<AppColumnsLayout>
|
2023-06-27 09:45:37 +00:00
|
|
|
<Box marginBottom={4}>
|
|
|
|
<Instructions />
|
|
|
|
</Box>
|
|
|
|
<Box
|
|
|
|
borderColor={"neutralHighlight"}
|
|
|
|
borderStyle={"solid"}
|
|
|
|
borderWidth={1}
|
|
|
|
padding={4}
|
|
|
|
borderRadius={4}
|
|
|
|
>
|
2023-06-22 08:47:39 +00:00
|
|
|
<Text as={"h2"} marginBottom={4} variant={"heading"}>
|
|
|
|
Configuration
|
|
|
|
</Text>
|
2023-06-22 08:32:25 +00:00
|
|
|
<Box>{page}</Box>
|
|
|
|
</Box>
|
2023-02-28 19:18:34 +00:00
|
|
|
</AppColumnsLayout>
|
2023-02-09 10:58:20 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
export default ConfigurationWithAuth;
|