change edit form to be cloudscape friendly

This commit is contained in:
Martin Dimitrov 2025-06-03 18:00:29 -07:00
parent 16f1e96f83
commit 4e730c4648
4 changed files with 44 additions and 24 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -15,6 +15,7 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.53.2", "react-hook-form": "^7.53.2",
"react-hook-form-cloudscape": "^1.7.7",
"react-qr-code": "^2.0.12", "react-qr-code": "^2.0.12",
"react-router-dom": "^6.15.0", "react-router-dom": "^6.15.0",
"typescript": "^4.4.2", "typescript": "^4.4.2",

View File

@ -1,8 +1,10 @@
import { Button, ColumnLayout, Input, SpaceBetween, TokenGroup, TokenGroupProps } from "@cloudscape-design/components"; import { Button, ColumnLayout, Input, InputProps, SpaceBetween, TokenGroup, TokenGroupProps } from "@cloudscape-design/components";
import CInput from "react-hook-form-cloudscape/components/input";
export type InputTokenGroupProps = { export type InputTokenGroupProps = {
type?: React.HTMLInputTypeAttribute; type?: InputProps.Type;
registerInput: any, control: any;
name: string;
tokenGroupProps: TokenGroupProps, tokenGroupProps: TokenGroupProps,
onAdd: () => void, onAdd: () => void,
onDismiss: (i: number) => void, onDismiss: (i: number) => void,
@ -12,9 +14,13 @@ export const InputTokenGroup = (props: InputTokenGroupProps) => {
return ( return (
<SpaceBetween size="xs"> <SpaceBetween size="xs">
<ColumnLayout columns={2}> <ColumnLayout columns={2}>
<input <CInput
type={props.type} type={props.type}
{...props.registerInput} name={props.name}
rules={{
minLength: 1
}}
control={props.control}
/> />
<Button onClick={() => props.onAdd()}>Add</Button> <Button onClick={() => props.onAdd()}>Add</Button>
</ColumnLayout> </ColumnLayout>

View File

@ -1,16 +1,18 @@
import { AppLayout, BreadcrumbGroup, Button, Container, Flashbar, FlashbarProps, Form, FormField, Header, Link, SpaceBetween } from "@cloudscape-design/components"; import { AppLayout, BreadcrumbGroup, Button, Container, Flashbar, FlashbarProps, Form, FormField, Header, Input, Link, SpaceBetween } from "@cloudscape-design/components";
import { useLoaderData, useSearchParams } from "react-router-dom"; import { useLoaderData, useSearchParams } from "react-router-dom";
import { DoorResponse } from "../types/DoorResponse"; import { DoorResponse } from "../types/DoorResponse";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { InputTokenGroup } from "../components/InputTokenGroup"; import { InputTokenGroup } from "../components/InputTokenGroup";
import { ReactNode, useState } from "react"; import { ReactNode, useState } from "react";
import CInput from "react-hook-form-cloudscape/components/input";
import CTextArea from "react-hook-form-cloudscape/components/textarea";
export type DoorEditForm = DoorResponse & { pin: string, fallbackNumber: string, discordUser: string }; export type DoorEditForm = DoorResponse & { pin: string, fallbackNumber: string, discordUser: string };
export const EditPage = () => { export const EditPage = () => {
const doorResponse = useLoaderData() as DoorResponse; const doorResponse = useLoaderData() as DoorResponse;
const door = doorResponse.id; const door = doorResponse.id;
const { register, setValue, setError, getValues, watch, formState, clearErrors } = useForm<DoorEditForm>({ const { register, setValue, setError, getValues, watch, formState, clearErrors, control } = useForm<DoorEditForm>({
defaultValues: doorResponse, defaultValues: doorResponse,
mode: "all", mode: "all",
}); });
@ -22,7 +24,6 @@ export const EditPage = () => {
setAlerts(alerts => alerts.filter(alert => alert.id !== id)); setAlerts(alerts => alerts.filter(alert => alert.id !== id));
} }
const createAlert = (type: FlashbarProps.Type, content: ReactNode): FlashbarProps.MessageDefinition => { const createAlert = (type: FlashbarProps.Type, content: ReactNode): FlashbarProps.MessageDefinition => {
const id = `${Math.random()}`; const id = `${Math.random()}`;
return { return {
@ -80,7 +81,12 @@ export const EditPage = () => {
<Button <Button
variant="primary" variant="primary"
onClick={() => { onClick={() => {
fetch(`/api/door/edit?door=${door}&newConfig=${encodeURIComponent(JSON.stringify(getValues()))}`) const form = {
...getValues(),
timeout: parseInt("" + getValues("timeout"))
};
fetch(`/api/door/edit?door=${door}&newConfig=${encodeURIComponent(JSON.stringify(form))}`)
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(res => {
addAlert("success", `Created approval, check Discord notifcation from Doorman to confirm and approve the changes`); addAlert("success", `Created approval, check Discord notifcation from Doorman to confirm and approve the changes`);
@ -102,21 +108,19 @@ export const EditPage = () => {
> >
<SpaceBetween direction="vertical" size="l"> <SpaceBetween direction="vertical" size="l">
<FormField label="Buzzer Number (read-only)" constraintText="The phone number of your buzzer system"> <FormField label="Buzzer Number (read-only)" constraintText="The phone number of your buzzer system">
<input readOnly {...register("buzzer")} /> <CInput readOnly disabled name="buzzer" control={control} />
</FormField> </FormField>
<FormField label="PIN" constraintText={"The code to unlock the buzzer"}> <FormField label="PIN" constraintText={"The code to unlock the buzzer"}>
<input type="password" {...register("pin")}/> <CInput type="password" name="pin" control={control} />
</FormField> </FormField>
<FormField label="Buzzer Code" constraintText={"The number that you dial on your buzzer"}> <FormField label="Buzzer Code" constraintText={"The number that you dial on your buzzer"}>
<input {...register("buzzerCode")} /> <CInput name="buzzerCode" control={control} />
</FormField> </FormField>
<FormField label="Timeout" constraintText="Time in seconds for the door to remain unlocked"> <FormField label="Timeout" constraintText="Time in seconds for the door to remain unlocked">
<input type="number" {...register("timeout", { <CInput type="number" name="timeout" control={control} />
valueAsNumber: true,
})} />
</FormField> </FormField>
<FormField label="Unlock key" constraintText="Key to press to buzz up on Intercom"> <FormField label="Unlock key" constraintText="Key to press to buzz up on Intercom">
<input {...register("pressKey")} /> <CInput name="pressKey" control={control} />
</FormField> </FormField>
<FormField <FormField
errorText={fallbackNumbersError} errorText={fallbackNumbersError}
@ -124,12 +128,17 @@ export const EditPage = () => {
constraintText="Phone numbers to dial through in case door is not unlocked" constraintText="Phone numbers to dial through in case door is not unlocked"
> >
<InputTokenGroup <InputTokenGroup
registerInput={register("fallbackNumber")} name={"fallbackNumber"}
control={control}
tokenGroupProps={{ items: fallbackNumbers.map(n => ({ label: n }))}} tokenGroupProps={{ items: fallbackNumbers.map(n => ({ label: n }))}}
onAdd={() => { onAdd={() => {
const newValue = getValues().fallbackNumber;
if (newValue.length === 0) {
return;
}
clearErrors("fallbackNumbers"); clearErrors("fallbackNumbers");
setValue("fallbackNumbers", [...fallbackNumbers, getValues().fallbackNumber]) setValue("fallbackNumbers", [...fallbackNumbers, newValue]);
setValue("fallbackNumber", "") setValue("fallbackNumber", "");
}} }}
onDismiss={(i) => { onDismiss={(i) => {
clearErrors("fallbackNumbers"); clearErrors("fallbackNumbers");
@ -153,13 +162,17 @@ export const EditPage = () => {
} }
> >
<InputTokenGroup <InputTokenGroup
type="string" name={"discordUser"}
registerInput={register("discordUser")} control={control}
tokenGroupProps={{ items: discordUsers.map(n => ({ label: n }))}} tokenGroupProps={{ items: discordUsers.map(n => ({ label: n }))}}
onAdd={() => { onAdd={() => {
const newValue = getValues().discordUser;
if (newValue.length === 0) {
return;
}
clearErrors("discordUsers"); clearErrors("discordUsers");
setValue("discordUsers", [...discordUsers, getValues().discordUser]) setValue("discordUsers", [...discordUsers, newValue]);
setValue("discordUser", "") setValue("discordUser", "");
}} }}
onDismiss={(i) => { onDismiss={(i) => {
clearErrors("discordUsers"); clearErrors("discordUsers");
@ -174,7 +187,7 @@ export const EditPage = () => {
/> />
</FormField> </FormField>
<FormField label="Welcome Message" constraintText="Message to display after a successful unlock"> <FormField label="Welcome Message" constraintText="Message to display after a successful unlock">
<textarea {...register("greeting")}/> <CTextArea name="greeting" control={control} />
</FormField> </FormField>
</SpaceBetween> </SpaceBetween>
</Container> </Container>