From c2578f1c8f15b1c7deb88f5b4b68e560bd2d4499 Mon Sep 17 00:00:00 2001 From: i701 Date: Fri, 25 Jul 2025 10:39:15 +0500 Subject: [PATCH] =?UTF-8?q?feat(user-agreement):=20implement=20user=20agre?= =?UTF-8?q?ement=20upload=20functionality=20and=20update=20related=20compo?= =?UTF-8?q?nents=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- actions/user-actions.ts | 45 +++++++++++ .../users/[userId]/agreement/page.tsx | 47 +++++++++++ .../users/[userId]/verify/page.tsx | 10 ++- app/next-auth.d.ts | 4 +- components/device-cart.tsx | 2 +- components/user/user-agreement-form.tsx | 79 +++++++++++++++++++ lib/backend-types.ts | 2 +- next.config.ts | 5 ++ 9 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 app/(dashboard)/users/[userId]/agreement/page.tsx create mode 100644 components/user/user-agreement-form.tsx diff --git a/README.md b/README.md index cf12364..f426b1f 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ This is a web portal for SAR Link customers. ## Admin Controls ### Users - [x] Show users table -- [ ] handle verify api no response case +- [x] handle verify api no response case - [x] Add all relavant filters for users table - [x] Verify or reject users with a custom message - [ ] Add functionality to send custom sms to users in user:id page diff --git a/actions/user-actions.ts b/actions/user-actions.ts index 1fda4e7..1246066 100644 --- a/actions/user-actions.ts +++ b/actions/user-actions.ts @@ -160,4 +160,49 @@ export async function updateUser( ...updatedUser, message: "User updated successfully", }; +} + +export async function updateUserAgreement( + _prevState: UpdateUserFormState, + formData: FormData +): Promise { + const userId = formData.get("userId") as string; + // Remove userId from formData before sending to API + const apiFormData = new FormData(); + for (const [key, value] of formData.entries()) { + if (key !== "userId") { + apiFormData.append(key, value); + } + } + console.log({ apiFormData }) + const session = await getServerSession(authOptions); + const response = await fetch( + `${process.env.SARLINK_API_BASE_URL}/api/auth/users/${userId}/agreement/`, + { + method: "PUT", + headers: { + Authorization: `Token ${session?.apiToken}`, + }, + body: apiFormData, + }, + ); + console.log("response in update user agreement action", response) + if (!response.ok) { + const errorData = await response.json(); + return { + message: errorData.message || errorData.detail || "An error occurred while updating the user agreement.", + fieldErrors: errorData.field_errors || {}, + payload: formData, + } + } + + const updatedUserAgreement = await response.json() as { agreement: string }; + revalidatePath("/users/[userId]/update", "page"); + revalidatePath("/users/[userId]/verify", "page"); + revalidatePath("/users/[userId]/agreement", "page"); + + return { + ...updatedUserAgreement, + message: "User agreement updated successfully", + }; } \ No newline at end of file diff --git a/app/(dashboard)/users/[userId]/agreement/page.tsx b/app/(dashboard)/users/[userId]/agreement/page.tsx new file mode 100644 index 0000000..c4574cf --- /dev/null +++ b/app/(dashboard)/users/[userId]/agreement/page.tsx @@ -0,0 +1,47 @@ +import { redirect } from "next/navigation"; +import { getServerSession } from "next-auth"; +import { authOptions } from "@/app/auth"; +import ClientErrorMessage from "@/components/client-error-message"; +import UserAgreementForm from "@/components/user/user-agreement-form"; +import { getProfileById } from "@/queries/users"; +import { tryCatch } from "@/utils/tryCatch"; +// import { +// Select, +// SelectContent, +// SelectGroup, +// SelectItem, +// SelectLabel, +// SelectTrigger, +// SelectValue, +// } from "@/components/ui/select"; + +export default async function UserUpdate({ + params, +}: { + params: Promise<{ + userId: string; + }>; +}) { + const { userId } = await params; + const session = await getServerSession(authOptions); + if (!session?.user?.is_admin) return null + const [error, user] = await tryCatch(getProfileById(userId)); + + + if (error) { + if (error.message === "UNAUTHORIZED") { + redirect("/auth/signin"); + } else { + return ; + } + } + + return ( +
+
+

Upload user user agreement

+
+ +
+ ); +} diff --git a/app/(dashboard)/users/[userId]/verify/page.tsx b/app/(dashboard)/users/[userId]/verify/page.tsx index 318855b..e05a1a7 100644 --- a/app/(dashboard)/users/[userId]/verify/page.tsx +++ b/app/(dashboard)/users/[userId]/verify/page.tsx @@ -1,4 +1,4 @@ -import { PencilIcon } from "lucide-react"; +import { FileTextIcon, PencilIcon } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { redirect } from "next/navigation"; @@ -42,7 +42,7 @@ export default async function VerifyUserPage({ return (
-

Verify user

+

User Information

{dbUser && !dbUser?.verified && } @@ -53,6 +53,12 @@ export default async function VerifyUserPage({ Update User + + + {dbUser?.verified && ( Verified diff --git a/app/next-auth.d.ts b/app/next-auth.d.ts index d34126b..ed247ff 100644 --- a/app/next-auth.d.ts +++ b/app/next-auth.d.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ // @ts-expect-error importing unused types are required here -import NextAuth, { DefaultSession, type User, Session } from "next-auth"; +import NextAuth, { DefaultSession, Session, type User } from "next-auth"; + /* eslint-enable @typescript-eslint/no-unused-vars */ declare module "next-auth" { /** @@ -26,6 +27,7 @@ declare module "next-auth" { date_joined?: string; is_superuser?: boolean; is_admin?: boolean; + agreement?: string; }; expires: ISODateString; } diff --git a/components/device-cart.tsx b/components/device-cart.tsx index f1d5669..c832bbd 100644 --- a/components/device-cart.tsx +++ b/components/device-cart.tsx @@ -16,7 +16,7 @@ export function DeviceCartDrawer() { if (devices.length === 0) return null; return ( -
+
+
+

+ Upload User agreement +

+
+
+ + +
+ + +
+
+
+ ); +} diff --git a/lib/backend-types.ts b/lib/backend-types.ts index 9a43cfd..e40b441 100644 --- a/lib/backend-types.ts +++ b/lib/backend-types.ts @@ -1,4 +1,4 @@ -import { User } from "./types/user"; +import type { User } from "./types/user"; export interface Links { next_page: string | null; diff --git a/next.config.ts b/next.config.ts index ae7e156..5150fa0 100644 --- a/next.config.ts +++ b/next.config.ts @@ -2,6 +2,11 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ + experimental: { + serverActions: { + bodySizeLimit: '20mb', + } + }, images: { remotePatterns: [ new URL('http://people-api.sarlink.net/images/**'),