mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-08-02 14:30:22 +00:00
feat(user-update-form): display field errors in user update form ✨
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 7m52s
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 7m52s
This commit is contained in:
@ -129,18 +129,19 @@ export type UpdateUserFormState = {
|
||||
payload?: FormData;
|
||||
};
|
||||
|
||||
|
||||
export async function updateUser(
|
||||
_prevState: UpdateUserFormState,
|
||||
formData: FormData,
|
||||
): Promise<UpdateUserFormState> {
|
||||
const userId = formData.get("userId") as string;
|
||||
const data: Record<string, string | number | boolean> = {};
|
||||
|
||||
for (const [key, value] of formData.entries()) {
|
||||
if (value !== undefined && value !== "") {
|
||||
data[key] = typeof value === "number" ? value : String(value);
|
||||
}
|
||||
}
|
||||
console.log("data in update user action", data);
|
||||
|
||||
const session = await getServerSession(authOptions);
|
||||
const response = await fetch(
|
||||
@ -154,29 +155,42 @@ export async function updateUser(
|
||||
body: JSON.stringify(data),
|
||||
},
|
||||
);
|
||||
console.log("response in update user action", response);
|
||||
|
||||
const json = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
const isFieldErrorObject =
|
||||
json &&
|
||||
typeof json === "object" &&
|
||||
!Array.isArray(json) &&
|
||||
Object.values(json).every(
|
||||
(val) => Array.isArray(val) && val.every((v) => typeof v === "string"),
|
||||
);
|
||||
|
||||
return {
|
||||
message:
|
||||
errorData.message ||
|
||||
errorData.detail ||
|
||||
"An error occurred while updating the user.",
|
||||
fieldErrors: errorData.field_errors || {},
|
||||
json.message ||
|
||||
json.detail ||
|
||||
(isFieldErrorObject
|
||||
? "Please correct the highlighted fields."
|
||||
: "An error occurred while updating the user."),
|
||||
fieldErrors: isFieldErrorObject ? json : json.field_errors || {},
|
||||
payload: formData,
|
||||
};
|
||||
}
|
||||
|
||||
const updatedUser = (await response.json()) as User;
|
||||
// Successful update
|
||||
const updatedUser = json as User;
|
||||
revalidatePath("/users/[userId]/update", "page");
|
||||
revalidatePath("/users/[userId]/verify", "page");
|
||||
|
||||
return {
|
||||
...updatedUser,
|
||||
message: "User updated successfully",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export async function updateUserAgreement(
|
||||
_prevState: UpdateUserFormState,
|
||||
formData: FormData,
|
||||
|
@ -1,17 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { signIn } from "next-auth/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { signIn } from "next-auth/react";
|
||||
import { useTransition } from "react";
|
||||
import { type SubmitHandler, useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
const OTPSchema = z.object({
|
||||
pin: z.string().min(6, {
|
||||
message: "Your one-time password must be 6 characters.",
|
||||
@ -59,7 +60,7 @@ export default function VerifyOTPForm({
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-full max-w-xs title-bg border rounded-lg shadow my-4"
|
||||
className="w-full max-w-xs title-bg border-2 border-sarLinkOrange/50 rounded-lg shadow my-4"
|
||||
>
|
||||
<div className="grid pb-4 pt-4 gap-4 px-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
|
@ -6,15 +6,6 @@ import { type UpdateUserFormState, updateUser } from "@/actions/user-actions";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { FloatingLabelInput } from "@/components/ui/floating-label";
|
||||
import type { UserProfile } from "@/lib/types/user";
|
||||
// import {
|
||||
// Select,
|
||||
// SelectContent,
|
||||
// SelectGroup,
|
||||
// SelectItem,
|
||||
// SelectLabel,
|
||||
// SelectTrigger,
|
||||
// SelectValue,
|
||||
// } from "@/components/ui/select";
|
||||
|
||||
export default function UserUpdateForm({ user }: { user: UserProfile }) {
|
||||
const initialState: UpdateUserFormState = {
|
||||
@ -59,6 +50,21 @@ export default function UserUpdateForm({ user }: { user: UserProfile }) {
|
||||
Update User Information
|
||||
</h4>
|
||||
<div className="border border-dashed border-sarLinkOrange p-4 rounded-lg max-w-2xl">
|
||||
<div>
|
||||
{state.fieldErrors && Object.keys(state.fieldErrors).length > 0 ? (
|
||||
<div className="text-red-500 mb-5 border border-red-500 p-2 rounded">
|
||||
{Object.entries(state.fieldErrors).map(([field, errors]) => (
|
||||
<div key={field}>
|
||||
{errors.map((error, index) => (
|
||||
<p key={`${index + 1}`}>
|
||||
Error in {field}: {error}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<fieldset
|
||||
disabled={isPending}
|
||||
className="space-y-1 my-2 grid grid-cols-1 md:grid-cols-2 gap-4"
|
||||
|
Reference in New Issue
Block a user