mirror of
				https://github.com/i701/sarlink-portal.git
				synced 2025-10-31 16:07:00 +00:00 
			
		
		
		
	feat(user): add admin topup functionality in user details page ✨
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Build and Push Docker Images / Build and Push Docker Images (push) Successful in 6m16s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Build and Push Docker Images / Build and Push Docker Images (push) Successful in 6m16s
				
			This commit is contained in:
		
							
								
								
									
										211
									
								
								app/(dashboard)/users/[userId]/details/page.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								app/(dashboard)/users/[userId]/details/page.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,211 @@ | ||||
| import { EyeIcon, FileTextIcon, PencilIcon } from "lucide-react"; | ||||
| import Image from "next/image"; | ||||
| import Link from "next/link"; | ||||
| import { redirect } from "next/navigation"; | ||||
| import AddTopupDialogForm from "@/components/admin/admin-topup-form"; | ||||
| import ClientErrorMessage from "@/components/client-error-message"; | ||||
| import InputReadOnly from "@/components/input-read-only"; | ||||
| import { Badge } from "@/components/ui/badge"; | ||||
| import { Button } from "@/components/ui/button"; | ||||
| import UserRejectDialog from "@/components/user/user-reject-dialog"; | ||||
| import { UserVerifyDialog } from "@/components/user/user-verify-dialog"; | ||||
| import { getNationalPerson } from "@/lib/person"; | ||||
| import { getProfileById } from "@/queries/users"; | ||||
| import { tryCatch } from "@/utils/tryCatch"; | ||||
|  | ||||
| export default async function VerifyUserPage({ | ||||
| 	params, | ||||
| }: { | ||||
| 	params: Promise<{ | ||||
| 		userId: string; | ||||
| 	}>; | ||||
| }) { | ||||
| 	const userId = (await params).userId; | ||||
| 	const [error, dbUser] = await tryCatch(getProfileById(userId)); | ||||
|  | ||||
| 	const [nationalDataEror, nationalData] = await tryCatch( | ||||
| 		getNationalPerson({ idCard: dbUser?.id_card ?? "" }), | ||||
| 	); | ||||
| 	if (nationalDataEror) { | ||||
| 		console.warn("Error fetching national data:", nationalDataEror); | ||||
| 	} | ||||
| 	if (error) { | ||||
| 		if (error.message === "UNAUTHORIZED") { | ||||
| 			redirect("/auth/signin"); | ||||
| 		} else { | ||||
| 			return <ClientErrorMessage message={error.message} />; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// return <pre>{JSON.stringify(nationalData, null, 2)}</pre> | ||||
| 	const fullName = `${dbUser?.first_name} ${dbUser?.last_name}`; | ||||
| 	const nationalDob = nationalData?.dob?.split("T")[0]; | ||||
| 	const dbUserDob = new Date(dbUser?.dob).toISOString().split("T")[0]; | ||||
|  | ||||
| 	return ( | ||||
| 		<div> | ||||
| 			<div className="flex flex-wrap gap-2 items-center justify-between text-gray-500 text-2xl font-bold title-bg py-4 px-2 mb-4"> | ||||
| 				<h3 className="text-sarLinkOrange text-2xl">User Information</h3> | ||||
|  | ||||
| 				<div className="flex flex-wrap gap-2"> | ||||
| 					{dbUser && !dbUser?.verified && <UserVerifyDialog user={dbUser} />} | ||||
| 					{dbUser && !dbUser?.verified && <UserRejectDialog user={dbUser} />} | ||||
| 					<AddTopupDialogForm user_id={userId} /> | ||||
| 					<Link href={"update"}> | ||||
| 						<Button className="hover:cursor-pointer"> | ||||
| 							<PencilIcon /> | ||||
| 							Update User | ||||
| 						</Button> | ||||
| 					</Link> | ||||
| 					<Link href={"agreement"}> | ||||
| 						<Button className="hover:cursor-pointer"> | ||||
| 							<FileTextIcon /> | ||||
| 							Update Agreement | ||||
| 						</Button> | ||||
| 					</Link> | ||||
| 					<Link | ||||
| 						href={dbUser?.agreement || "#"} | ||||
| 						target="_blank" | ||||
| 						rel="noopener noreferrer" | ||||
| 					> | ||||
| 						<Button className="hover:cursor-pointer"> | ||||
| 							<EyeIcon /> | ||||
| 							View Agreement | ||||
| 						</Button> | ||||
| 					</Link> | ||||
| 					{dbUser?.verified && ( | ||||
| 						<Badge variant={"secondary"} className="bg-lime-500"> | ||||
| 							Verified | ||||
| 						</Badge> | ||||
| 					)} | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<div className="grid grid-cols-1 md:grid-cols-2 gap-4 items-start justify-start"> | ||||
| 				<div id="database-information"> | ||||
| 					<h4 className="p-2 rounded font-semibold">Database Information</h4> | ||||
| 					<div className="shadow-md p-2 bg-sarLinkOrange/10 border border-dashed border-sarLinkOrange rounded-lg space-y-1 my-2 grid grid-cols-1 md:grid-cols-2 gap-2"> | ||||
| 						<InputReadOnly | ||||
| 							showCheck | ||||
| 							checkTrue={dbUser?.id_card === nationalData?.nic} | ||||
| 							labelClassName="text-sarLinkOrange" | ||||
| 							label="ID Card" | ||||
| 							value={dbUser?.id_card ?? ""} | ||||
| 						/> | ||||
| 						<InputReadOnly | ||||
| 							showCheck | ||||
| 							checkTrue={fullName === nationalData?.name_en} | ||||
| 							labelClassName="text-sarLinkOrange" | ||||
| 							label="Name" | ||||
| 							value={fullName} | ||||
| 						/> | ||||
| 						<InputReadOnly | ||||
| 							showCheck | ||||
| 							checkTrue={dbUser?.address === nationalData?.house_name_en} | ||||
| 							labelClassName="text-sarLinkOrange" | ||||
| 							label="House Name" | ||||
| 							value={dbUser?.address ?? ""} | ||||
| 						/> | ||||
| 						<InputReadOnly | ||||
| 							showCheck | ||||
| 							checkTrue={dbUser?.island?.name === nationalData?.island_name_en} | ||||
| 							labelClassName="text-sarLinkOrange" | ||||
| 							label="Island" | ||||
| 							value={dbUser?.island?.name ?? ""} | ||||
| 						/> | ||||
| 						<InputReadOnly | ||||
| 							showCheck | ||||
| 							checkTrue={dbUser?.atoll.name === nationalData?.atoll_en} | ||||
| 							labelClassName="text-sarLinkOrange" | ||||
| 							label="Atoll" | ||||
| 							value={dbUser?.atoll?.name ?? ""} | ||||
| 						/> | ||||
|  | ||||
| 						<InputReadOnly | ||||
| 							showCheck | ||||
| 							checkTrue={dbUserDob === nationalDob} | ||||
| 							labelClassName="text-sarLinkOrange" | ||||
| 							label="DOB" | ||||
| 							value={new Date(dbUser?.dob ?? "").toLocaleDateString("en-US", { | ||||
| 								month: "short", | ||||
| 								day: "2-digit", | ||||
| 								year: "numeric", | ||||
| 							})} | ||||
| 						/> | ||||
| 						<InputReadOnly | ||||
| 							showCheck | ||||
| 							checkTrue={dbUser?.mobile === nationalData?.primary_contact} | ||||
| 							labelClassName="text-sarLinkOrange" | ||||
| 							label="Phone Number" | ||||
| 							value={dbUser?.mobile ?? ""} | ||||
| 						/> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				{ | ||||
| 					<div id="national-information"> | ||||
| 						<h4 className="p-2 rounded font-semibold">National Information</h4> | ||||
| 						<div className="bg-green-800/10 shadow p-2 rounded-lg border border-dashed border-green-800 space-y-1 my-2 grid grid-cols-1 md:grid-cols-2 gap-2"> | ||||
| 							<InputReadOnly | ||||
| 								showCheck={false} | ||||
| 								labelClassName="text-green-500" | ||||
| 								label="ID Card" | ||||
| 								value={nationalData?.nic ?? ""} | ||||
| 							/> | ||||
| 							<InputReadOnly | ||||
| 								showCheck={false} | ||||
| 								labelClassName="text-green-500" | ||||
| 								label="Name" | ||||
| 								value={nationalData?.name_en ?? ""} | ||||
| 							/> | ||||
| 							<InputReadOnly | ||||
| 								showCheck={false} | ||||
| 								labelClassName="text-green-500" | ||||
| 								label="House Name" | ||||
| 								value={nationalData?.house_name_en ?? ""} | ||||
| 							/> | ||||
| 							<InputReadOnly | ||||
| 								showCheck={false} | ||||
| 								labelClassName="text-green-500" | ||||
| 								label="Island" | ||||
| 								value={nationalData?.island_name_en ?? ""} | ||||
| 							/> | ||||
| 							<InputReadOnly | ||||
| 								showCheck={false} | ||||
| 								labelClassName="text-green-500" | ||||
| 								label="Atoll" | ||||
| 								value={nationalData?.atoll_en ?? ""} | ||||
| 							/> | ||||
| 							<InputReadOnly | ||||
| 								showCheck={false} | ||||
| 								labelClassName="text-green-500" | ||||
| 								label="DOB" | ||||
| 								value={new Date(nationalData?.dob ?? "").toLocaleDateString( | ||||
| 									"en-US", | ||||
| 									{ | ||||
| 										month: "short", | ||||
| 										day: "2-digit", | ||||
| 										year: "numeric", | ||||
| 									}, | ||||
| 								)} | ||||
| 							/> | ||||
| 							<InputReadOnly | ||||
| 								showCheck={false} | ||||
| 								labelClassName="text-green-500" | ||||
| 								label="Phone Number" | ||||
| 								value={nationalData?.primary_contact ?? ""} | ||||
| 							/> | ||||
| 							<div className="flex flex-col col-span-2 items-center justify-center"> | ||||
| 								<Image | ||||
| 									src={nationalData?.image_url || "https://i.pravatar.cc/300"} | ||||
| 									height={100} | ||||
| 									width={100} | ||||
| 									className="object-fit aspect-square rounded-full" | ||||
| 									alt="id photo" | ||||
| 								/> | ||||
| 							</div> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				} | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user