Martin Dimitrov 9c6231f045
All checks were successful
Build and push image for doorman-homeassistant / docker (push) Successful in 30s
Build and push Doorman UI / API / docker (push) Successful in 1m24s
Build and push image for doorman-homeassistant / deploy-gitainer (push) Successful in 5s
add approval id in discord notification and add flashbar after clicking edit
2025-06-01 21:42:07 -07:00

186 lines
6.9 KiB
TypeScript

import { AppLayout, BreadcrumbGroup, Button, Container, Flashbar, FlashbarProps, Form, FormField, Header, Link, SpaceBetween } from "@cloudscape-design/components";
import { useLoaderData, useSearchParams } from "react-router-dom";
import { DoorResponse } from "../types/DoorResponse";
import { useForm } from "react-hook-form";
import { InputTokenGroup } from "../components/InputTokenGroup";
import { ReactNode, useState } from "react";
export type DoorEditForm = DoorResponse & { pin: string, fallbackNumber: string, discordUser: string };
export const EditPage = () => {
const doorResponse = useLoaderData() as DoorResponse;
const door = doorResponse.id;
const { register, setValue, setError, getValues, watch, formState, clearErrors } = useForm<DoorEditForm>({
defaultValues: doorResponse,
mode: "all",
});
const [ alerts, setAlerts ] = useState<FlashbarProps.MessageDefinition[]>([]);
const dismissAlert = (id: string) => {
setAlerts(alerts => alerts.filter(alert => alert.id !== id));
}
const createAlert = (type: FlashbarProps.Type, content: ReactNode): FlashbarProps.MessageDefinition => {
const id = `${Math.random()}`;
return {
id,
type,
content,
dismissible: type !== 'in-progress',
onDismiss: () => dismissAlert(id),
}
}
const addAlert = (type: FlashbarProps.Type, content: ReactNode): string => {
const newAlert = createAlert(type, content);
setAlerts(alerts => [
newAlert,
...alerts,
]);
return newAlert.id as string;
}
const fallbackNumbers = watch("fallbackNumbers");
const discordUsers = watch("discordUsers");
const fallbackNumbersError = formState.errors.fallbackNumbers?.message;
const discordUsersError = formState.errors.discordUsers?.message;
return (
<AppLayout
contentType="form"
navigationHide
toolsHide
breadcrumbs={
<BreadcrumbGroup
items={[
{ text: 'Door', href: '#' },
{ text: door, href: `?edit&door=${door}` },
]}
/>
}
notifications={
<Flashbar
stackItems={true}
items={alerts}
/>
}
content={
<Form
actions={
<SpaceBetween direction="horizontal" size="xs">
<Button formAction="none" variant="link" href={`?door=${door}`}>
Cancel
</Button>
<Button
variant="primary"
onClick={() => {
fetch(`/api/door/edit?door=${door}&newConfig=${encodeURIComponent(JSON.stringify(getValues()))}`)
.then(res => res.json())
.then(res => {
addAlert("success", `Created approval, check Discord notifcation from Doorman to confirm and approve the changes`);
})
}}
>
Submit
</Button>
</SpaceBetween>
}
header={<Header variant="h1">Edit Door</Header>}
>
<Container
header={
<Header variant="h2">
Door - {door}
</Header>
}
>
<SpaceBetween direction="vertical" size="l">
<FormField label="Buzzer Number (read-only)" constraintText="The phone number of your buzzer system">
<input readOnly {...register("buzzer")} />
</FormField>
<FormField label="PIN" constraintText={"The code to unlock the buzzer"}>
<input type="password" {...register("pin")}/>
</FormField>
<FormField label="Buzzer Code" constraintText={"The number that you dial on your buzzer"}>
<input {...register("buzzerCode")} />
</FormField>
<FormField label="Timeout" constraintText="Time in seconds for the door to remain unlocked">
<input type="number" {...register("timeout", {
valueAsNumber: true,
})} />
</FormField>
<FormField label="Unlock key" constraintText="Key to press to buzz up on Intercom">
<input {...register("pressKey")} />
</FormField>
<FormField
errorText={fallbackNumbersError}
label="Fallback numbers"
constraintText="Phone numbers to dial through in case door is not unlocked"
>
<InputTokenGroup
registerInput={register("fallbackNumber")}
tokenGroupProps={{ items: fallbackNumbers.map(n => ({ label: n }))}}
onAdd={() => {
clearErrors("fallbackNumbers");
setValue("fallbackNumbers", [...fallbackNumbers, getValues().fallbackNumber])
setValue("fallbackNumber", "")
}}
onDismiss={(i) => {
clearErrors("fallbackNumbers");
if (fallbackNumbers.length === 1) {
setError("fallbackNumbers", { message: "Can't remove last entry", type: "value" })
return;
}
fallbackNumbers.splice(i, 1);
setValue("fallbackNumbers", [...fallbackNumbers]);
}}
/>
</FormField>
<FormField
label="Discord Users"
errorText={discordUsersError}
constraintText={
<>
<Link fontSize={"body-s"} href="https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID#h_01HRSTXPS5H5D7JBY2QKKPVKNA">Discord users</Link> to receive notifications
</>
}
>
<InputTokenGroup
type="string"
registerInput={register("discordUser")}
tokenGroupProps={{ items: discordUsers.map(n => ({ label: n }))}}
onAdd={() => {
clearErrors("discordUsers");
setValue("discordUsers", [...discordUsers, getValues().discordUser])
setValue("discordUser", "")
}}
onDismiss={(i) => {
clearErrors("discordUsers");
if (discordUsers.length === 1) {
setError("discordUsers", { message: "Can't remove last entry" })
return;
}
discordUsers.splice(i, 1);
setValue("discordUsers", [...discordUsers]);
}}
/>
</FormField>
<FormField label="Welcome Message" constraintText="Message to display after a successful unlock">
<textarea {...register("greeting")}/>
</FormField>
</SpaceBetween>
</Container>
</Form>
}
/>
);
};