saleor-apps-redis_apl/apps/search/src/components/AlgoliaConfigurationCard.tsx

168 lines
5.2 KiB
TypeScript
Raw Normal View History

import { useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Button, makeStyles } from "@saleor/macaw-ui";
import { Card, CardActions, CardHeader, TextField } from "@material-ui/core";
import { Controller, useForm } from "react-hook-form";
import { useQuery, useQueryClient, useMutation } from "react-query";
import { AlgoliaConfigurationFields } from "../lib/algolia/types";
import { fetchConfiguration } from "../lib/configuration";
const useStyles = makeStyles((theme) => ({
form: {
margin: theme.spacing(2),
},
confirmButton: {
marginLeft: "auto",
},
fieldContainer: {
marginBottom: theme.spacing(2),
},
}));
export const AlgoliaConfigurationCard = () => {
const { appBridge, appBridgeState } = useAppBridge();
const { handleSubmit, setValue, control } = useForm<AlgoliaConfigurationFields>({
defaultValues: { appId: "", indexNamePrefix: "", searchKey: "", secretKey: "" },
});
const classes = useStyles();
const { token, saleorApiUrl } = appBridgeState || {};
const reactQueryClient = useQueryClient();
const { isLoading: isQueryLoading } = useQuery({
queryKey: ["configuration"],
onSuccess(data) {
setValue("secretKey", data?.secretKey || "");
setValue("searchKey", data?.searchKey || "");
setValue("appId", data?.appId || "");
setValue("indexNamePrefix", data?.indexNamePrefix || "");
},
queryFn: async () => fetchConfiguration(saleorApiUrl!, token!),
enabled: !!token && !!saleorApiUrl,
});
const { mutate, isLoading: isMutationLoading } = useMutation(
async (conf: AlgoliaConfigurationFields) => {
const resp = await fetch("/api/configuration", {
method: "POST",
headers: {
"saleor-api-url": saleorApiUrl!,
"authorization-bearer": token!,
},
body: JSON.stringify(conf),
});
if (resp.status >= 200 && resp.status < 300) {
const data = (await resp.json()) as { data?: AlgoliaConfigurationFields };
return data.data;
}
throw new Error(`Server responded with status code ${resp.status}`);
},
{
onSuccess: async () => {
reactQueryClient.refetchQueries({
queryKey: ["configuration"],
});
appBridge?.dispatch({
type: "notification",
payload: {
status: "success",
title: "Configuration saved!",
actionId: "message-from-app",
},
});
},
onError: async (data: Error) => {
appBridge?.dispatch({
type: "notification",
payload: {
status: "error",
title: "Could not save the configuration",
text: data.message,
actionId: "message-from-app",
},
});
},
}
);
const onFormSubmit = handleSubmit(async (conf) => mutate(conf));
const isFormDisabled = isMutationLoading || isQueryLoading || !token || !saleorApiUrl;
return (
<Card>
<form onSubmit={onFormSubmit}>
<CardHeader title="Configure Algolia settings"></CardHeader>
<div className={classes.form}>
<Controller
name="appId"
control={control}
render={({ field }) => (
<TextField
className={classes.fieldContainer}
disabled={isFormDisabled}
label="Application ID"
helperText="Usually 10 characters, e.g. XYZAAABB00"
{...field}
fullWidth
/>
)}
/>
<Controller
name="searchKey"
control={control}
render={({ field }) => (
<TextField
className={classes.fieldContainer}
disabled={isFormDisabled}
label="Search-Only API Key"
{...field}
fullWidth
/>
)}
/>
<div key="secret" className={classes.fieldContainer}>
<Controller
name="secretKey"
control={control}
render={({ field }) => (
<TextField
helperText="In Algolia dashboard it's a masked field"
disabled={isFormDisabled}
label="Admin API Key"
{...field}
fullWidth
/>
)}
/>
</div>
<Controller
name="indexNamePrefix"
control={control}
render={({ field }) => (
<TextField
className={classes.fieldContainer}
disabled={isFormDisabled}
label="Index name prefix"
helperText='Optional prefix, you can add "test" or "staging" to test the app'
{...field}
fullWidth
/>
)}
/>
<CardActions style={{ padding: "30px 0 0 0" }}>
<Button disabled={isFormDisabled} type="submit" variant="primary" fullWidth>
{isFormDisabled ? "Loading..." : "Save"}
</Button>
</CardActions>
</div>
</form>
</Card>
);
};
/**
* Export default for Next.dynamic
*/
export default AlgoliaConfigurationCard;