refactor: enhance user validation schemas, improve code formatting, and debug storage statistics retrieval.
This commit is contained in:
parent
793fa23c1b
commit
53c4048ad5
@ -23,19 +23,29 @@ import type { User } from "@/types/user";
|
|||||||
|
|
||||||
const assignmentSchema = z.object({
|
const assignmentSchema = z.object({
|
||||||
role_id: z.string().min(1, "Role is required"),
|
role_id: z.string().min(1, "Role is required"),
|
||||||
module_ids: z.array(z.string().min(1)).min(1, "At least one module is required"),
|
module_ids: z
|
||||||
|
.array(z.string().min(1))
|
||||||
|
.min(1, "At least one module is required"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Validation schema
|
// Validation schema
|
||||||
const editUserSchema = z.object({
|
const editUserSchema = z.object({
|
||||||
email: z.email({ message: "Please enter a valid email address" }),
|
email: z.email({ message: "Please enter a valid email address" }),
|
||||||
first_name: z.string().min(1, "First name is required"),
|
first_name: z
|
||||||
last_name: z.string().min(1, "Last name is required"),
|
.string()
|
||||||
|
.min(1, "First name is required")
|
||||||
|
.max(255, "Maximum 255 characters allowed"),
|
||||||
|
last_name: z
|
||||||
|
.string()
|
||||||
|
.min(1, "Last name is required")
|
||||||
|
.max(255, "Maximum 255 characters allowed"),
|
||||||
status: z.enum(["active", "suspended", "deleted"], {
|
status: z.enum(["active", "suspended", "deleted"], {
|
||||||
message: "Status is required",
|
message: "Status is required",
|
||||||
}),
|
}),
|
||||||
tenant_id: z.string().min(1, "Tenant is required"),
|
tenant_id: z.string().min(1, "Tenant is required"),
|
||||||
role_module_assignments: z.array(assignmentSchema).min(1, "At least one role assignment is required")
|
role_module_assignments: z
|
||||||
|
.array(assignmentSchema)
|
||||||
|
.min(1, "At least one role assignment is required")
|
||||||
.superRefine((assignments, ctx) => {
|
.superRefine((assignments, ctx) => {
|
||||||
const seenModules = new Set<string>();
|
const seenModules = new Set<string>();
|
||||||
assignments.forEach((assignment, rowIndex) => {
|
assignments.forEach((assignment, rowIndex) => {
|
||||||
@ -243,16 +253,32 @@ export const EditUserModal = ({
|
|||||||
const roleOptions: { value: string; label: string }[] = [];
|
const roleOptions: { value: string; label: string }[] = [];
|
||||||
const moduleOptions: { value: string; label: string }[] = [];
|
const moduleOptions: { value: string; label: string }[] = [];
|
||||||
|
|
||||||
let initialAssignments = [{ role_id: "", module_ids: [] as string[] }];
|
let initialAssignments = [
|
||||||
|
{ role_id: "", module_ids: [] as string[] },
|
||||||
|
];
|
||||||
|
|
||||||
if (user.role_module_combinations && user.role_module_combinations.length > 0) {
|
if (
|
||||||
|
user.role_module_combinations &&
|
||||||
|
user.role_module_combinations.length > 0
|
||||||
|
) {
|
||||||
const grouped = new Map<string, string[]>();
|
const grouped = new Map<string, string[]>();
|
||||||
user.role_module_combinations.forEach((c) => {
|
user.role_module_combinations.forEach((c) => {
|
||||||
if (c.role_id && c.role_name && !roleOptions.some(o => o.value === c.role_id)) {
|
if (
|
||||||
|
c.role_id &&
|
||||||
|
c.role_name &&
|
||||||
|
!roleOptions.some((o) => o.value === c.role_id)
|
||||||
|
) {
|
||||||
roleOptions.push({ value: c.role_id, label: c.role_name });
|
roleOptions.push({ value: c.role_id, label: c.role_name });
|
||||||
}
|
}
|
||||||
if (c.module_id && c.module_name && !moduleOptions.some(o => o.value === c.module_id)) {
|
if (
|
||||||
moduleOptions.push({ value: c.module_id, label: c.module_name });
|
c.module_id &&
|
||||||
|
c.module_name &&
|
||||||
|
!moduleOptions.some((o) => o.value === c.module_id)
|
||||||
|
) {
|
||||||
|
moduleOptions.push({
|
||||||
|
value: c.module_id,
|
||||||
|
label: c.module_name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (c.module_id) {
|
if (c.module_id) {
|
||||||
const existing = grouped.get(c.role_id) || [];
|
const existing = grouped.get(c.role_id) || [];
|
||||||
@ -260,23 +286,37 @@ export const EditUserModal = ({
|
|||||||
grouped.set(c.role_id, existing);
|
grouped.set(c.role_id, existing);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
initialAssignments = Array.from(grouped.entries()).map(([role_id, module_ids]) => ({
|
initialAssignments = Array.from(grouped.entries()).map(
|
||||||
|
([role_id, module_ids]) => ({
|
||||||
role_id,
|
role_id,
|
||||||
module_ids,
|
module_ids,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// Fallback for older format
|
// Fallback for older format
|
||||||
const r_ids = user.roles?.map(r => r.id) || (user.role_id ? [user.role_id] : []);
|
const r_ids =
|
||||||
|
user.roles?.map((r) => r.id) ||
|
||||||
|
(user.role_id ? [user.role_id] : []);
|
||||||
if (r_ids.length > 0) {
|
if (r_ids.length > 0) {
|
||||||
initialAssignments = r_ids.map(id => ({ role_id: id, module_ids: [] }));
|
initialAssignments = r_ids.map((id) => ({
|
||||||
|
role_id: id,
|
||||||
|
module_ids: [],
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
if (user.roles?.length) {
|
if (user.roles?.length) {
|
||||||
user.roles.forEach(r => roleOptions.push({ value: r.id, label: r.name }));
|
user.roles.forEach((r) =>
|
||||||
|
roleOptions.push({ value: r.id, label: r.name }),
|
||||||
|
);
|
||||||
} else if (user.role?.id) {
|
} else if (user.role?.id) {
|
||||||
roleOptions.push({ value: user.role.id, label: user.role.name });
|
roleOptions.push({
|
||||||
|
value: user.role.id,
|
||||||
|
label: user.role.name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (user.modules?.length) {
|
if (user.modules?.length) {
|
||||||
user.modules.forEach(m => moduleOptions.push({ value: m.id, label: m.name }));
|
user.modules.forEach((m) =>
|
||||||
|
moduleOptions.push({ value: m.id, label: m.name }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,7 +449,10 @@ export const EditUserModal = ({
|
|||||||
|
|
||||||
const { role_module_assignments, ...submitData } = data;
|
const { role_module_assignments, ...submitData } = data;
|
||||||
const role_module_combinations = role_module_assignments.flatMap((row) =>
|
const role_module_combinations = role_module_assignments.flatMap((row) =>
|
||||||
row.module_ids.map((module_id) => ({ role_id: row.role_id, module_id })),
|
row.module_ids.map((module_id) => ({
|
||||||
|
role_id: row.role_id,
|
||||||
|
module_id,
|
||||||
|
})),
|
||||||
);
|
);
|
||||||
await onSubmit(userId, { ...submitData, role_module_combinations });
|
await onSubmit(userId, { ...submitData, role_module_combinations });
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@ -556,7 +599,9 @@ export const EditUserModal = ({
|
|||||||
required
|
required
|
||||||
placeholder="Select Department"
|
placeholder="Select Department"
|
||||||
value={departmentIdValue || ""}
|
value={departmentIdValue || ""}
|
||||||
onValueChange={(value) => setValue("department_id", value, { shouldValidate: true })}
|
onValueChange={(value) =>
|
||||||
|
setValue("department_id", value, { shouldValidate: true })
|
||||||
|
}
|
||||||
onLoadOptions={loadDepartments}
|
onLoadOptions={loadDepartments}
|
||||||
initialOption={initialDepartmentOption || undefined}
|
initialOption={initialDepartmentOption || undefined}
|
||||||
error={errors.department_id?.message}
|
error={errors.department_id?.message}
|
||||||
@ -566,7 +611,9 @@ export const EditUserModal = ({
|
|||||||
required
|
required
|
||||||
placeholder="Select Designation"
|
placeholder="Select Designation"
|
||||||
value={designationIdValue || ""}
|
value={designationIdValue || ""}
|
||||||
onValueChange={(value) => setValue("designation_id", value, { shouldValidate: true })}
|
onValueChange={(value) =>
|
||||||
|
setValue("designation_id", value, { shouldValidate: true })
|
||||||
|
}
|
||||||
onLoadOptions={loadDesignations}
|
onLoadOptions={loadDesignations}
|
||||||
initialOption={initialDesignationOption || undefined}
|
initialOption={initialDesignationOption || undefined}
|
||||||
error={errors.designation_id?.message}
|
error={errors.designation_id?.message}
|
||||||
@ -627,7 +674,9 @@ export const EditUserModal = ({
|
|||||||
|
|
||||||
<div className="mt-2 mb-4">
|
<div className="mt-2 mb-4">
|
||||||
<div className="flex justify-between items-center mb-2">
|
<div className="flex justify-between items-center mb-2">
|
||||||
<label className="text-sm font-medium text-gray-700">Role & Module Assignments</label>
|
<label className="text-sm font-medium text-gray-700">
|
||||||
|
Role & Module Assignments
|
||||||
|
</label>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => append({ role_id: "", module_ids: [] })}
|
onClick={() => append({ role_id: "", module_ids: [] })}
|
||||||
@ -645,41 +694,76 @@ export const EditUserModal = ({
|
|||||||
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{fields.map((field, index) => {
|
{fields.map((field, index) => {
|
||||||
const roleIdValue = watch(`role_module_assignments.${index}.role_id`);
|
const roleIdValue = watch(
|
||||||
const moduleIdsValue = watch(`role_module_assignments.${index}.module_ids`) || [];
|
`role_module_assignments.${index}.role_id`,
|
||||||
|
);
|
||||||
|
const moduleIdsValue =
|
||||||
|
watch(`role_module_assignments.${index}.module_ids`) || [];
|
||||||
|
|
||||||
// Extract specific label if available from initial options
|
// Extract specific label if available from initial options
|
||||||
const getRoleLabel = (val: string) => {
|
const getRoleLabel = (val: string) => {
|
||||||
const opt = initialRoleOptions.find(o => o.value === val);
|
const opt = initialRoleOptions.find((o) => o.value === val);
|
||||||
return opt ? opt.label : undefined;
|
return opt ? opt.label : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialSelectedModules = moduleIdsValue
|
const initialSelectedModules = moduleIdsValue
|
||||||
.map((val) => {
|
.map((val) => {
|
||||||
const opt = initialModuleOptions.find((o) => o.value === val);
|
const opt = initialModuleOptions.find(
|
||||||
return opt ? { value: opt.value, label: opt.label } : null;
|
(o) => o.value === val,
|
||||||
|
);
|
||||||
|
return opt
|
||||||
|
? { value: opt.value, label: opt.label }
|
||||||
|
: null;
|
||||||
})
|
})
|
||||||
.filter((opt): opt is { value: string; label: string } => Boolean(opt));
|
.filter((opt): opt is { value: string; label: string } =>
|
||||||
|
Boolean(opt),
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={field.id} className="flex gap-2 items-start border p-3 rounded-md bg-gray-50 relative">
|
<div
|
||||||
|
key={field.id}
|
||||||
|
className="flex gap-2 items-start border p-3 rounded-md bg-gray-50 relative"
|
||||||
|
>
|
||||||
<div className="flex-1 grid grid-cols-2 gap-3">
|
<div className="flex-1 grid grid-cols-2 gap-3">
|
||||||
<PaginatedSelect
|
<PaginatedSelect
|
||||||
label="Select Role"
|
label="Select Role"
|
||||||
required
|
required
|
||||||
placeholder="Select Role"
|
placeholder="Select Role"
|
||||||
value={roleIdValue || ""}
|
value={roleIdValue || ""}
|
||||||
onValueChange={(value) => setValue(`role_module_assignments.${index}.role_id`, value, { shouldValidate: true })}
|
onValueChange={(value) =>
|
||||||
|
setValue(
|
||||||
|
`role_module_assignments.${index}.role_id`,
|
||||||
|
value,
|
||||||
|
{ shouldValidate: true },
|
||||||
|
)
|
||||||
|
}
|
||||||
onLoadOptions={loadRoles}
|
onLoadOptions={loadRoles}
|
||||||
initialOption={roleIdValue ? { value: roleIdValue, label: getRoleLabel(roleIdValue) || roleIdValue } : undefined}
|
initialOption={
|
||||||
error={errors.role_module_assignments?.[index]?.role_id?.message}
|
roleIdValue
|
||||||
|
? {
|
||||||
|
value: roleIdValue,
|
||||||
|
label:
|
||||||
|
getRoleLabel(roleIdValue) || roleIdValue,
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
error={
|
||||||
|
errors.role_module_assignments?.[index]?.role_id
|
||||||
|
?.message
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<MultiselectPaginatedSelect
|
<MultiselectPaginatedSelect
|
||||||
label="Select Modules"
|
label="Select Modules"
|
||||||
required
|
required
|
||||||
placeholder="Select Modules"
|
placeholder="Select Modules"
|
||||||
value={moduleIdsValue}
|
value={moduleIdsValue}
|
||||||
onValueChange={(value) => setValue(`role_module_assignments.${index}.module_ids`, value, { shouldValidate: true })}
|
onValueChange={(value) =>
|
||||||
|
setValue(
|
||||||
|
`role_module_assignments.${index}.module_ids`,
|
||||||
|
value,
|
||||||
|
{ shouldValidate: true },
|
||||||
|
)
|
||||||
|
}
|
||||||
onLoadOptions={loadModules}
|
onLoadOptions={loadModules}
|
||||||
initialOptions={initialSelectedModules}
|
initialOptions={initialSelectedModules}
|
||||||
error={getModuleError(index)}
|
error={getModuleError(index)}
|
||||||
|
|||||||
@ -43,6 +43,7 @@ import { z } from "zod";
|
|||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import fileAttachmentService, {
|
import fileAttachmentService, {
|
||||||
type CategoriesFilterOptions,
|
type CategoriesFilterOptions,
|
||||||
|
type StorageQuota,
|
||||||
} from "@/services/file-attachment-service";
|
} from "@/services/file-attachment-service";
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
@ -61,9 +62,9 @@ function getExt(name: string) {
|
|||||||
return name.slice(((name.lastIndexOf(".") - 1) >>> 0) + 1).toLowerCase();
|
return name.slice(((name.lastIndexOf(".") - 1) >>> 0) + 1).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function isBlocked(name: string) {
|
// function isBlocked(name: string) {
|
||||||
return BLOCKED_EXTENSIONS.includes(getExt(name) ? `.${getExt(name)}` : "");
|
// return BLOCKED_EXTENSIONS.includes(getExt(name) ? `.${getExt(name)}` : "");
|
||||||
}
|
// }
|
||||||
|
|
||||||
function formatBytes(bytes: number): string {
|
function formatBytes(bytes: number): string {
|
||||||
if (bytes === 0) return "0 B";
|
if (bytes === 0) return "0 B";
|
||||||
@ -205,6 +206,23 @@ export const FileUploadModal = ({
|
|||||||
// File entries with upload progress (internal state kept separate from zod files array for progress tracking)
|
// File entries with upload progress (internal state kept separate from zod files array for progress tracking)
|
||||||
const [fileEntries, setFileEntries] = useState<FileEntry[]>([]);
|
const [fileEntries, setFileEntries] = useState<FileEntry[]>([]);
|
||||||
|
|
||||||
|
// Storage quota settings fetched dynamically from backend
|
||||||
|
const [quota, setQuota] = useState<StorageQuota | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen) {
|
||||||
|
fileAttachmentService.getQuota()
|
||||||
|
.then((res) => {
|
||||||
|
if (res?.data) {
|
||||||
|
setQuota(res.data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Failed to load quota settings in FileUploadModal:", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
// ── Auto-generate Entity ID ──
|
// ── Auto-generate Entity ID ──
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen && !entityId && !defaultEntityId) {
|
if (isOpen && !entityId && !defaultEntityId) {
|
||||||
@ -242,15 +260,38 @@ export const FileUploadModal = ({
|
|||||||
|
|
||||||
// ── Add files ──
|
// ── Add files ──
|
||||||
const addFiles = useCallback((incoming: File[]) => {
|
const addFiles = useCallback((incoming: File[]) => {
|
||||||
|
const activeBlocked = quota?.blocked_extensions || BLOCKED_EXTENSIONS;
|
||||||
|
const activeMaxSizeBytes = quota?.max_file_size_bytes || (MAX_SIZE_MB * 1024 * 1024);
|
||||||
|
|
||||||
const newEntries: FileEntry[] = incoming
|
const newEntries: FileEntry[] = incoming
|
||||||
.slice(0, MAX_FILES)
|
.slice(0, MAX_FILES)
|
||||||
.map((file) => ({
|
.map((file) => {
|
||||||
|
const ext = getExt(file.name);
|
||||||
|
const fileExt = ext ? `.${ext}` : "";
|
||||||
|
const isBlockedType = activeBlocked.some(
|
||||||
|
(blockedExt) => blockedExt.toLowerCase() === fileExt.toLowerCase()
|
||||||
|
);
|
||||||
|
const isTooLarge = file.size > activeMaxSizeBytes;
|
||||||
|
|
||||||
|
let status: FileStatus = "idle";
|
||||||
|
let error: string | undefined;
|
||||||
|
|
||||||
|
if (isBlockedType) {
|
||||||
|
status = "blocked";
|
||||||
|
error = "Blocked file type";
|
||||||
|
} else if (isTooLarge) {
|
||||||
|
status = "blocked";
|
||||||
|
error = `Exceeds limit of ${formatBytes(activeMaxSizeBytes)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
file,
|
file,
|
||||||
id: `${file.name}-${file.size}-${Date.now()}-${Math.random()}`,
|
id: `${file.name}-${file.size}-${Date.now()}-${Math.random()}`,
|
||||||
status: isBlocked(file.name) ? "blocked" : "idle",
|
status,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
error: isBlocked(file.name) ? "Blocked file type" : undefined,
|
error,
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
|
||||||
setFileEntries((prev) => {
|
setFileEntries((prev) => {
|
||||||
const combined = [...prev, ...newEntries];
|
const combined = [...prev, ...newEntries];
|
||||||
@ -259,7 +300,7 @@ export const FileUploadModal = ({
|
|||||||
setValue("files", limited.map(e => e.file), { shouldValidate: true });
|
setValue("files", limited.map(e => e.file), { shouldValidate: true });
|
||||||
return limited;
|
return limited;
|
||||||
});
|
});
|
||||||
}, [setValue]);
|
}, [setValue, quota]);
|
||||||
|
|
||||||
const onDrop = useCallback(
|
const onDrop = useCallback(
|
||||||
(e: DragEvent<HTMLDivElement>) => {
|
(e: DragEvent<HTMLDivElement>) => {
|
||||||
@ -433,7 +474,9 @@ export const FileUploadModal = ({
|
|||||||
<p className="text-xs text-[#9aa6b2] mt-0.5">
|
<p className="text-xs text-[#9aa6b2] mt-0.5">
|
||||||
Attach supporting source files via File Attachment Service
|
Attach supporting source files via File Attachment Service
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-[#9aa6b2]">PDF, DOCX, XLSX up to {MAX_SIZE_MB}MB</p>
|
<p className="text-xs text-[#9aa6b2]">
|
||||||
|
Allowed formats up to {quota ? formatBytes(quota.max_file_size_bytes) : `${MAX_SIZE_MB}MB`}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -28,8 +28,8 @@ const assignmentSchema = z.object({
|
|||||||
const newUserSchema = z
|
const newUserSchema = z
|
||||||
.object({
|
.object({
|
||||||
email: z.email({ message: "Please enter a valid email address" }),
|
email: z.email({ message: "Please enter a valid email address" }),
|
||||||
first_name: z.string().min(1, "First name is required"),
|
first_name: z.string().min(1, "First name is required").max(255, "Maximum 255 characters allowed"),
|
||||||
last_name: z.string().min(1, "Last name is required"),
|
last_name: z.string().min(1, "Last name is required").max(255, "Maximum 255 characters allowed"),
|
||||||
status: z.enum(["active", "suspended", "deleted"], { message: "Status is required" }),
|
status: z.enum(["active", "suspended", "deleted"], { message: "Status is required" }),
|
||||||
auth_provider: z.enum(["local"], { message: "Auth provider is required" }),
|
auth_provider: z.enum(["local"], { message: "Auth provider is required" }),
|
||||||
role_module_assignments: z.array(assignmentSchema).min(1, "At least one role assignment is required")
|
role_module_assignments: z.array(assignmentSchema).min(1, "At least one role assignment is required")
|
||||||
|
|||||||
@ -145,7 +145,7 @@ export const RecentActivity = ({ variant }: RecentActivityProps) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="text-[15px] font-bold gap-1 h-7"
|
className="text-[15px] font-bold gap-1 h-7 cursor-pointer"
|
||||||
style={{ color: primaryColor }}
|
style={{ color: primaryColor }}
|
||||||
onClick={() => navigate(auditLogPath)}
|
onClick={() => navigate(auditLogPath)}
|
||||||
>
|
>
|
||||||
@ -214,7 +214,7 @@ export const RecentActivity = ({ variant }: RecentActivityProps) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-8 text-[11px] gap-1.5 border-[rgba(0,0,0,0.08)] hover:bg-gray-50"
|
className="h-8 text-[11px] gap-1.5 border-[rgba(0,0,0,0.08)] hover:bg-gray-50 cursor-pointer"
|
||||||
onClick={() => navigate(auditLogPath)}
|
onClick={() => navigate(auditLogPath)}
|
||||||
>
|
>
|
||||||
View All <ArrowRight className="w-3 h-3" />
|
View All <ArrowRight className="w-3 h-3" />
|
||||||
|
|||||||
@ -59,11 +59,16 @@ const tenantDetailsSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Step 2: Contact Details Schema - user creation + organization address
|
// Step 2: Contact Details Schema - user creation + organization address
|
||||||
const contactDetailsSchema = z
|
const contactDetailsSchema = z.object({
|
||||||
.object({
|
|
||||||
email: z.email({ message: "Please enter a valid email address" }),
|
email: z.email({ message: "Please enter a valid email address" }),
|
||||||
first_name: z.string().min(1, "First name is required"),
|
first_name: z
|
||||||
last_name: z.string().min(1, "Last name is required"),
|
.string()
|
||||||
|
.min(1, "First name is required")
|
||||||
|
.max(255, "Maximum 255 characters allowed"),
|
||||||
|
last_name: z
|
||||||
|
.string()
|
||||||
|
.min(1, "Last name is required")
|
||||||
|
.max(255, "Maximum 255 characters allowed"),
|
||||||
contact_phone: z
|
contact_phone: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
|
|||||||
@ -68,8 +68,14 @@ const tenantDetailsSchema = z.object({
|
|||||||
const contactDetailsSchema = z.object({
|
const contactDetailsSchema = z.object({
|
||||||
id: z.string().uuid().optional().nullable(),
|
id: z.string().uuid().optional().nullable(),
|
||||||
email: z.string().email({ message: "Please enter a valid email address" }),
|
email: z.string().email({ message: "Please enter a valid email address" }),
|
||||||
first_name: z.string().min(1, "First name is required"),
|
first_name: z
|
||||||
last_name: z.string().min(1, "Last name is required"),
|
.string()
|
||||||
|
.min(1, "First name is required")
|
||||||
|
.max(255, "Maximum 255 characters allowed"),
|
||||||
|
last_name: z
|
||||||
|
.string()
|
||||||
|
.min(1, "Last name is required")
|
||||||
|
.max(255, "Maximum 255 characters allowed"),
|
||||||
contact_phone: z
|
contact_phone: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
|
|||||||
@ -149,6 +149,8 @@ const StorageDashboard = (): ReactElement => {
|
|||||||
fileAttachmentService.getStorageStats(),
|
fileAttachmentService.getStorageStats(),
|
||||||
fileAttachmentService.getQuota(),
|
fileAttachmentService.getQuota(),
|
||||||
]);
|
]);
|
||||||
|
console.log(quotaRes.data);
|
||||||
|
|
||||||
setStats(statsRes.data);
|
setStats(statsRes.data);
|
||||||
setQuota(quotaRes.data);
|
setQuota(quotaRes.data);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user