create & update role with device approval

This commit is contained in:
Fred KISSIE
2026-01-08 03:33:03 +01:00
parent abfe476cb9
commit 39bebea5f7
12 changed files with 449 additions and 128 deletions

View File

@@ -1,5 +1,15 @@
"use client";
import {
Credenza,
CredenzaBody,
CredenzaClose,
CredenzaContent,
CredenzaDescription,
CredenzaFooter,
CredenzaHeader,
CredenzaTitle
} from "@app/components/Credenza";
import { Button } from "@app/components/ui/button";
import {
Form,
@@ -11,37 +21,26 @@ import {
FormMessage
} from "@app/components/ui/form";
import { Input } from "@app/components/ui/input";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useOrgContext } from "@app/hooks/useOrgContext";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { toast } from "@app/hooks/useToast";
import { createApiClient, formatAxiosError } from "@app/lib/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { build } from "@server/build";
import type { CreateRoleBody, CreateRoleResponse } from "@server/routers/role";
import { AxiosResponse } from "axios";
import { useState } from "react";
import { useTranslations } from "next-intl";
import { useTransition } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import {
Credenza,
CredenzaBody,
CredenzaClose,
CredenzaContent,
CredenzaDescription,
CredenzaFooter,
CredenzaHeader,
CredenzaTitle
} from "@app/components/Credenza";
import { useOrgContext } from "@app/hooks/useOrgContext";
import type { CreateRoleBody, CreateRoleResponse } from "@server/routers/role";
import { formatAxiosError } from "@app/lib/api";
import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useTranslations } from "next-intl";
import { CheckboxWithLabel } from "./ui/checkbox";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { build } from "@server/build";
import { PaidFeaturesAlert } from "./PaidFeaturesAlert";
import { CheckboxWithLabel } from "./ui/checkbox";
type CreateRoleFormProps = {
open: boolean;
setOpen: (open: boolean) => void;
afterCreate?: (res: CreateRoleResponse) => Promise<void>;
afterCreate?: (res: CreateRoleResponse) => void;
};
export default function CreateRoleForm({
@@ -54,13 +53,14 @@ export default function CreateRoleForm({
const { isPaidUser } = usePaidStatus();
const formSchema = z.object({
name: z.string({ message: t("nameRequired") }).max(32),
name: z
.string({ message: t("nameRequired") })
.min(1)
.max(32),
description: z.string().max(255).optional(),
requireDeviceApproval: z.boolean().optional()
});
const [loading, setLoading] = useState(false);
const api = createApiClient(useEnvContext());
const form = useForm<z.infer<typeof formSchema>>({
@@ -72,17 +72,13 @@ export default function CreateRoleForm({
}
});
async function onSubmit(values: z.infer<typeof formSchema>) {
setLoading(true);
const [loading, startTransition] = useTransition();
async function onSubmit(values: z.infer<typeof formSchema>) {
const res = await api
.put<AxiosResponse<CreateRoleResponse>>(
`/org/${org?.org.orgId}/role`,
{
name: values.name,
description: values.description
} as CreateRoleBody
)
.put<
AxiosResponse<CreateRoleResponse>
>(`/org/${org?.org.orgId}/role`, values satisfies CreateRoleBody)
.catch((e) => {
toast({
variant: "destructive",
@@ -105,12 +101,8 @@ export default function CreateRoleForm({
setOpen(false);
}
if (afterCreate) {
afterCreate(res.data.data);
}
afterCreate?.(res.data.data);
}
setLoading(false);
}
return (
@@ -119,7 +111,6 @@ export default function CreateRoleForm({
open={open}
onOpenChange={(val) => {
setOpen(val);
setLoading(false);
form.reset();
}}
>
@@ -133,7 +124,9 @@ export default function CreateRoleForm({
<CredenzaBody>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
onSubmit={form.handleSubmit((values) =>
startTransition(() => onSubmit(values))
)}
className="space-y-4"
id="create-role-form"
>
@@ -168,23 +161,37 @@ export default function CreateRoleForm({
)}
/>
{build !== "oss" && (
<>
<div className="pt-3">
<PaidFeaturesAlert />
<FormField
control={form.control}
name="requireDeviceApproval"
render={({ field }) => (
<FormItem className="pt-3">
<FormItem className="my-2">
<FormControl>
<CheckboxWithLabel
{...field}
disabled={
!isPaidUser
}
value={undefined}
defaultChecked={
field.value
}
value="on"
checked={form.watch(
"requireDeviceApproval"
)}
onCheckedChange={(
checked
) => {
if (
checked !==
"indeterminate"
) {
form.setValue(
"requireDeviceApproval",
checked
);
}
}}
label={t(
"requireDeviceApproval"
)}
@@ -201,7 +208,7 @@ export default function CreateRoleForm({
</FormItem>
)}
/>
</>
</div>
)}
</form>
</Form>