diff --git a/web/sdk/admin/views/organizations/details/layout/invite-users-dialog.tsx b/web/sdk/admin/views/organizations/details/layout/invite-users-dialog.tsx index 0f8b9b2b8..ddb59c778 100644 --- a/web/sdk/admin/views/organizations/details/layout/invite-users-dialog.tsx +++ b/web/sdk/admin/views/organizations/details/layout/invite-users-dialog.tsx @@ -1,10 +1,9 @@ import { Button, Dialog, + Field, Flex, - Label, Select, - Text, TextArea, toastManager } from '@raystack/apsara'; @@ -30,11 +29,21 @@ import { useTerminology } from '../../../../hooks/useTerminology'; import { handleConnectError } from '~/utils/error'; const inviteSchema = z.object({ - role: z.string(), + role: z.string().min(1, { message: 'Role is required' }), emails: z .string() - .transform(value => value.split(',').map(str => str.trim())) - .pipe(z.array(z.string().email())) + .min(1, { message: 'Email is required' }) + .transform(value => + value + .split(',') + .map(str => str.trim()) + .filter(str => str.length > 0) + ) + .pipe( + z + .array(z.string().email({ message: 'Enter valid email address(es)' })) + .min(1, { message: 'Email is required' }) + ) }); type InviteSchemaType = z.infer; @@ -109,6 +118,7 @@ export const InviteUsersDialog = ({ onOpenChange }: InviteUsersDialogProps) => { const isSubmitting = methods?.formState?.isSubmitting; const errors = methods?.formState?.errors; + return ( @@ -119,10 +129,14 @@ export const InviteUsersDialog = ({ onOpenChange }: InviteUsersDialogProps) => { - - + e?.message)?.message + : undefined) + }> { ); }} /> - {errors?.emails?.message || errors?.emails?.length ? ( - - {errors?.emails?.message || errors?.emails?.[0]?.message} - - ) : null} - + - - + { ); }} /> - - {errors?.role?.message && ( - - {errors?.role?.message} - - )} - + diff --git a/web/sdk/admin/views/users/list/invite-users.module.css b/web/sdk/admin/views/users/list/invite-users.module.css index c80cc9bec..17f8528a4 100644 --- a/web/sdk/admin/views/users/list/invite-users.module.css +++ b/web/sdk/admin/views/users/list/invite-users.module.css @@ -5,14 +5,6 @@ gap: var(--rs-space-7); } -.invite-users-dialog-label { - font-weight: var(--rs-font-weight-medium); -} - -.form-error-message { - color: var(--rs-color-foreground-danger-primary); -} - .invite-users-emails-textarea { resize: vertical; width: 100%; diff --git a/web/sdk/admin/views/users/list/invite-users.tsx b/web/sdk/admin/views/users/list/invite-users.tsx index a7e3defc3..5075a3e98 100644 --- a/web/sdk/admin/views/users/list/invite-users.tsx +++ b/web/sdk/admin/views/users/list/invite-users.tsx @@ -2,11 +2,11 @@ import { useMemo, useState, useEffect } from "react"; import { Button, Dialog, + Field, Flex, - Label, Select, - Text, TextArea, + Skeleton, toastManager, } from "@raystack/apsara"; import { PlusIcon } from "@radix-ui/react-icons"; @@ -15,7 +15,6 @@ import { Controller, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { SCOPES, DEFAULT_ROLES } from "../../../utils/constants"; import styles from "./invite-users.module.css"; -import Skeleton from "react-loading-skeleton"; import { useMutation, useQuery } from "@connectrpc/connect-query"; import { AdminServiceQueries, @@ -28,16 +27,29 @@ import { create } from "@bufbuild/protobuf"; import { handleConnectError } from "~/utils/error"; import { useTerminology } from "../../../hooks/useTerminology"; -const inviteSchema = z.object({ - role: z.string(), - organizationId: z.string(), - emails: z - .string() - .transform(value => value.split(",").map(str => str.trim())) - .pipe(z.array(z.string().email())), -}); +const createInviteSchema = (t: ReturnType) => + z.object({ + role: z.string().min(1, { message: "Role is required" }), + organizationId: z.string().min(1, { + message: `${t.organization({ case: "capital" })} is required`, + }), + emails: z + .string() + .min(1, { message: "Email is required" }) + .transform(value => + value + .split(",") + .map(str => str.trim()) + .filter(str => str.length > 0) + ) + .pipe( + z + .array(z.string().email({ message: "Enter valid email address(es)" })) + .min(1, { message: "Email is required" }) + ), + }); -type InviteSchemaType = z.infer; +type InviteSchemaType = z.infer>; export const InviteUser = () => { const t = useTerminology(); @@ -67,6 +79,8 @@ export const InviteUser = () => { } ); + const isLoading = isRolesLoading || isOrganizationsLoading; + useEffect(() => { if (organizationsError) { console.error("Failed to fetch organizations:", organizationsError); @@ -84,6 +98,8 @@ export const InviteUser = () => { [roles], ); + const inviteSchema = useMemo(() => createInviteSchema(t), [t]); + const { formState: { errors, isSubmitting }, handleSubmit, @@ -149,46 +165,46 @@ export const InviteUser = () => { - - - { - const { value, ...rest } = field; - return ( -