diff --git a/src/components/resource-policy/CreatePolicyAuthMethodsSectionForm.tsx b/src/components/resource-policy/CreatePolicyAuthMethodsSectionForm.tsx
index f881104cb..30a87ffc8 100644
--- a/src/components/resource-policy/CreatePolicyAuthMethodsSectionForm.tsx
+++ b/src/components/resource-policy/CreatePolicyAuthMethodsSectionForm.tsx
@@ -14,7 +14,7 @@ import { useTranslations } from "next-intl";
import z from "zod";
-import { type PolicyFormValues } from ".";
+import { createPolicySchema, type PolicyFormValues } from ".";
import { SwitchInput } from "@app/components/SwitchInput";
import { Button } from "@app/components/ui/button";
@@ -46,7 +46,7 @@ import {
import { cn } from "@app/lib/cn";
import { Binary, Bot, Key, Plus } from "lucide-react";
-import { useState } from "react";
+import { useEffect, useState } from "react";
import { type UseFormReturn, useForm, useWatch } from "react-hook-form";
// ─── CreatePolicyAuthMethodsSectionForm ───────────────────────────────────────
@@ -70,7 +70,7 @@ export type CreatePolicyAuthMethodsSectionFormProps = {
};
export function CreatePolicyAuthMethodsSectionForm({
- form
+ form: parentForm
}: CreatePolicyAuthMethodsSectionFormProps) {
const t = useTranslations();
const [isExpanded, setIsExpanded] = useState(false);
@@ -78,6 +78,30 @@ export function CreatePolicyAuthMethodsSectionForm({
const [isSetPincodeOpen, setIsSetPincodeOpen] = useState(false);
const [isSetHeaderAuthOpen, setIsSetHeaderAuthOpen] = useState(false);
+ const form = useForm({
+ resolver: zodResolver(
+ createPolicySchema.pick({
+ password: true,
+ pincode: true,
+ headerAuth: true
+ })
+ ),
+ defaultValues: {
+ password: null,
+ pincode: null,
+ headerAuth: null
+ }
+ });
+
+ useEffect(() => {
+ const subscription = form.watch((values) => {
+ parentForm.setValue("password", values.password as any);
+ parentForm.setValue("pincode", values.pincode as any);
+ parentForm.setValue("headerAuth", values.headerAuth as any);
+ });
+ return () => subscription.unsubscribe();
+ }, [form, parentForm]);
+
const password = useWatch({
control: form.control,
name: "password"
diff --git a/src/components/resource-policy/CreatePolicyForm.tsx b/src/components/resource-policy/CreatePolicyForm.tsx
index 9cc2d06b4..b3a5599a9 100644
--- a/src/components/resource-policy/CreatePolicyForm.tsx
+++ b/src/components/resource-policy/CreatePolicyForm.tsx
@@ -43,7 +43,7 @@ import {
} from "@app/components/ui/form";
import { Input } from "@app/components/ui/input";
-import { useMemo, useActionState } from "react";
+import { useMemo, useTransition } from "react";
import { useForm } from "react-hook-form";
import { CreatePolicyUsersRolesSectionForm } from "./CreatePolicyUserRolesSectionForm";
import { CreatePolicyAuthMethodsSectionForm } from "./CreatePolicyAuthMethodsSectionForm";
@@ -59,7 +59,7 @@ export function CreatePolicyForm({}: CreatePolicyFormProps) {
const t = useTranslations();
const { env } = useEnvContext();
const api = createApiClient({ env });
- const [, formAction, isSubmitting] = useActionState(onSubmit, null);
+ const [isSubmitting, startTransition] = useTransition();
const { isPaidUser } = usePaidStatus();
const router = useRouter();
@@ -202,8 +202,7 @@ export function CreatePolicyForm({}: CreatePolicyFormProps) {
return (
);
}
diff --git a/src/components/resource-policy/CreatePolicyOtpEmailSectionForm.tsx b/src/components/resource-policy/CreatePolicyOtpEmailSectionForm.tsx
index ce8ac54b9..fb324cced 100644
--- a/src/components/resource-policy/CreatePolicyOtpEmailSectionForm.tsx
+++ b/src/components/resource-policy/CreatePolicyOtpEmailSectionForm.tsx
@@ -9,30 +9,31 @@ import {
SettingsSectionTitle
} from "@app/components/Settings";
+import { zodResolver } from "@hookform/resolvers/zod";
import { useTranslations } from "next-intl";
import z from "zod";
-import { type PolicyFormValues } from ".";
+import { createPolicySchema, type PolicyFormValues } from ".";
import { SwitchInput } from "@app/components/SwitchInput";
import { Tag, TagInput } from "@app/components/tags/tag-input";
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
import { Button } from "@app/components/ui/button";
import {
+ Form,
FormControl,
FormDescription,
FormField,
FormItem,
- FormLabel,
- FormMessage
+ FormLabel
} from "@app/components/ui/form";
import { InfoPopup } from "@app/components/ui/info-popup";
import { InfoIcon, Plus } from "lucide-react";
-import { useState } from "react";
-import { type UseFormReturn } from "react-hook-form";
+import { useEffect, useState } from "react";
+import { type UseFormReturn, useForm, useWatch } from "react-hook-form";
// ─── CreatePolicyOtpEmailSectionForm ──────────────────────────────────────────
@@ -42,16 +43,44 @@ export type CreatePolicyOtpEmailSectionFormProps = {
};
export function CreatePolicyOtpEmailSectionForm({
- form,
+ form: parentForm,
emailEnabled
}: CreatePolicyOtpEmailSectionFormProps) {
const t = useTranslations();
const [isExpanded, setIsExpanded] = useState(false);
- const [whitelistEnabled, setWhitelistEnabled] = useState(false);
const [activeEmailTagIndex, setActiveEmailTagIndex] = useState<
number | null
>(null);
+ const form = useForm({
+ resolver: zodResolver(
+ createPolicySchema.pick({
+ emailWhitelistEnabled: true,
+ emails: true
+ })
+ ),
+ defaultValues: {
+ emailWhitelistEnabled: false,
+ emails: []
+ }
+ });
+
+ useEffect(() => {
+ const subscription = form.watch((values) => {
+ parentForm.setValue(
+ "emailWhitelistEnabled",
+ values.emailWhitelistEnabled as boolean
+ );
+ parentForm.setValue("emails", values.emails as [Tag, ...Tag[]]);
+ });
+ return () => subscription.unsubscribe();
+ }, [form, parentForm]);
+
+ const whitelistEnabled = useWatch({
+ control: form.control,
+ name: "emailWhitelistEnabled"
+ });
+
if (!isExpanded) {
return (
@@ -78,100 +107,107 @@ export function CreatePolicyOtpEmailSectionForm({
}
return (
-
-
-
- {t("otpEmailTitle")}
-
-
- {t("otpEmailTitleDescription")}
-
-
-
-
- {!emailEnabled && (
-
-
-
- {t("otpEmailSmtpRequired")}
-
-
- {t("otpEmailSmtpRequiredDescription")}
-
-
- )}
- {
- setWhitelistEnabled(val);
- form.setValue("emailWhitelistEnabled", val);
- }}
- disabled={!emailEnabled}
- />
-
- {whitelistEnabled && emailEnabled && (
- (
-
-
-
-
-
- {/* @ts-ignore */}
- {
- return z
- .email()
- .or(
- z
- .string()
- .regex(
- /^\*@[\w.-]+\.[a-zA-Z]{2,}$/,
- {
- message: t(
- "otpEmailErrorInvalid"
- )
- }
- )
- )
- .safeParse(tag).success;
- }}
- setActiveTagIndex={
- setActiveEmailTagIndex
- }
- placeholder={t("otpEmailEnter")}
- tags={form.getValues().emails}
- setTags={(newEmails) => {
- form.setValue(
- "emails",
- newEmails as [Tag, ...Tag[]]
- );
- }}
- allowDuplicates={false}
- sortTags={true}
- />
-
-
- {t("otpEmailEnterDescription")}
-
-
- )}
+
+
+
+
);
}
diff --git a/src/components/resource-policy/CreatePolicyRulesSectionForm.tsx b/src/components/resource-policy/CreatePolicyRulesSectionForm.tsx
index 87152fa09..c8635c5a3 100644
--- a/src/components/resource-policy/CreatePolicyRulesSectionForm.tsx
+++ b/src/components/resource-policy/CreatePolicyRulesSectionForm.tsx
@@ -13,7 +13,7 @@ import { useTranslations } from "next-intl";
import z from "zod";
-import { type PolicyFormValues } from ".";
+import { createPolicySchema, type PolicyFormValues } from ".";
import { toast } from "@app/hooks/useToast";
import { SwitchInput } from "@app/components/SwitchInput";
@@ -81,8 +81,8 @@ import {
Plus
} from "lucide-react";
-import { useCallback, useMemo, useState } from "react";
-import { type UseFormReturn, useForm } from "react-hook-form";
+import { useCallback, useEffect, useMemo, useState } from "react";
+import { type UseFormReturn, useForm, useWatch } from "react-hook-form";
// ─── CreatePolicyRulesSectionForm ─────────────────────────────────────────────
@@ -111,18 +111,43 @@ export type CreatePolicyRulesSectionFormProps = {
};
export function CreatePolicyRulesSectionForm({
- form,
+ form: parentForm,
isMaxmindAvailable,
isMaxmindAsnAvailable
}: CreatePolicyRulesSectionFormProps) {
const t = useTranslations();
const [isExpanded, setIsExpanded] = useState(false);
const [rules, setRules] = useState([]);
- const [rulesEnabled, setRulesEnabled] = useState(false);
const [openAddRuleCountrySelect, setOpenAddRuleCountrySelect] =
useState(false);
const [openAddRuleAsnSelect, setOpenAddRuleAsnSelect] = useState(false);
+ const form = useForm({
+ resolver: zodResolver(
+ createPolicySchema.pick({
+ applyRules: true,
+ rules: true
+ })
+ ),
+ defaultValues: {
+ applyRules: false,
+ rules: []
+ }
+ });
+
+ useEffect(() => {
+ const subscription = form.watch((values) => {
+ parentForm.setValue("applyRules", values.applyRules as boolean);
+ parentForm.setValue("rules", values.rules as any);
+ });
+ return () => subscription.unsubscribe();
+ }, [form, parentForm]);
+
+ const rulesEnabled = useWatch({
+ control: form.control,
+ name: "applyRules"
+ });
+
const addRuleForm = useForm({
resolver: zodResolver(addRuleSchema),
defaultValues: {
@@ -656,7 +681,6 @@ export function CreatePolicyRulesSectionForm({
label={t("rulesEnable")}
defaultChecked={false}
onCheckedChange={(val) => {
- setRulesEnabled(val);
form.setValue("applyRules", val);
}}
/>
diff --git a/src/components/resource-policy/CreatePolicyUserRolesSectionForm.tsx b/src/components/resource-policy/CreatePolicyUserRolesSectionForm.tsx
index 48d8b94f8..132363fc1 100644
--- a/src/components/resource-policy/CreatePolicyUserRolesSectionForm.tsx
+++ b/src/components/resource-policy/CreatePolicyUserRolesSectionForm.tsx
@@ -9,9 +9,11 @@ import {
SettingsSectionTitle
} from "@app/components/Settings";
+import { zodResolver } from "@hookform/resolvers/zod";
import { SwitchInput } from "@app/components/SwitchInput";
import { Tag, TagInput } from "@app/components/tags/tag-input";
import {
+ Form,
FormControl,
FormDescription,
FormField,
@@ -26,10 +28,10 @@ import {
SelectTrigger,
SelectValue
} from "@app/components/ui/select";
-import { type PolicyFormValues } from ".";
+import { createPolicySchema, type PolicyFormValues } from ".";
import { useTranslations } from "next-intl";
-import { useState } from "react";
-import { type UseFormReturn, useWatch } from "react-hook-form";
+import { useEffect, useState } from "react";
+import { type UseFormReturn, useForm, useWatch } from "react-hook-form";
// ─── CreatePolicyUsersRolesSectionForm ────────────────────────────────────────
@@ -41,12 +43,40 @@ export type CreatePolicyUsersRolesSectionFormProps = {
};
export function CreatePolicyUsersRolesSectionForm({
- form,
+ form: parentForm,
allRoles,
allUsers,
allIdps
}: CreatePolicyUsersRolesSectionFormProps) {
const t = useTranslations();
+
+ const form = useForm({
+ resolver: zodResolver(
+ createPolicySchema.pick({
+ sso: true,
+ skipToIdpId: true,
+ roles: true,
+ users: true
+ })
+ ),
+ defaultValues: {
+ sso: true,
+ skipToIdpId: null,
+ roles: [],
+ users: []
+ }
+ });
+
+ useEffect(() => {
+ const subscription = form.watch((values) => {
+ parentForm.setValue("sso", values.sso as boolean);
+ parentForm.setValue("skipToIdpId", values.skipToIdpId as number | null);
+ parentForm.setValue("roles", values.roles as [Tag, ...Tag[]]);
+ parentForm.setValue("users", values.users as [Tag, ...Tag[]]);
+ });
+ return () => subscription.unsubscribe();
+ }, [form, parentForm]);
+
const ssoEnabled = useWatch({ control: form.control, name: "sso" });
const selectedIdpId = useWatch({
control: form.control,
@@ -60,165 +90,168 @@ export function CreatePolicyUsersRolesSectionForm({
>(null);
return (
-
-
-
- {t("resourceUsersRoles")}
-
-
- {t("resourcePolicyUsersRolesDescription")}
-
-
-
-
- {
- console.log(`form.setValue("sso", ${val})`);
- form.setValue("sso", val);
- }}
- />
+
);
}