feature: add register quick action dashboard
This commit is contained in:
parent
696174bbc4
commit
54f946461c
295
src/app/quickaction-dashboard/page.tsx
Normal file
295
src/app/quickaction-dashboard/page.tsx
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState, useCallback } from 'react'
|
||||||
|
import PageLayout from '../components/PageLayout'
|
||||||
|
import useAuthStore from '../store/authStore'
|
||||||
|
import {
|
||||||
|
CheckCircleIcon,
|
||||||
|
XCircleIcon,
|
||||||
|
EnvelopeOpenIcon,
|
||||||
|
IdentificationIcon,
|
||||||
|
InformationCircleIcon,
|
||||||
|
DocumentCheckIcon,
|
||||||
|
ArrowUpOnSquareIcon,
|
||||||
|
PencilSquareIcon,
|
||||||
|
ClipboardDocumentCheckIcon
|
||||||
|
} from '@heroicons/react/24/outline'
|
||||||
|
|
||||||
|
interface StatusItem {
|
||||||
|
key: string
|
||||||
|
label: string
|
||||||
|
description: string
|
||||||
|
complete: boolean
|
||||||
|
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function QuickActionDashboardPage() {
|
||||||
|
const user = useAuthStore(s => s.user)
|
||||||
|
|
||||||
|
// Mock status derivation (replace with real user flags)
|
||||||
|
const [emailVerified, setEmailVerified] = useState(!!user?.emailVerified)
|
||||||
|
const [idUploaded, setIdUploaded] = useState(false)
|
||||||
|
const [additionalInfo, setAdditionalInfo] = useState(false)
|
||||||
|
const [contractSigned, setContractSigned] = useState(false)
|
||||||
|
|
||||||
|
const statusItems: StatusItem[] = [
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
label: 'Email Verification',
|
||||||
|
description: emailVerified ? 'Verified' : 'Missing',
|
||||||
|
complete: emailVerified,
|
||||||
|
icon: EnvelopeOpenIcon
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'id',
|
||||||
|
label: 'ID Document',
|
||||||
|
description: idUploaded ? 'Uploaded' : 'Missing',
|
||||||
|
complete: idUploaded,
|
||||||
|
icon: IdentificationIcon
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'info',
|
||||||
|
label: 'Additional Info',
|
||||||
|
description: additionalInfo ? 'Completed' : 'Missing',
|
||||||
|
complete: additionalInfo,
|
||||||
|
icon: InformationCircleIcon
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contract',
|
||||||
|
label: 'Contract',
|
||||||
|
description: contractSigned ? 'Signed' : 'Missing',
|
||||||
|
complete: contractSigned,
|
||||||
|
icon: DocumentCheckIcon
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// Action handlers (placeholder async simulations)
|
||||||
|
const handleVerifyEmail = useCallback(async () => {
|
||||||
|
// TODO: trigger backend email verification flow
|
||||||
|
await new Promise(r => setTimeout(r, 600))
|
||||||
|
setEmailVerified(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleUploadId = useCallback(async () => {
|
||||||
|
// TODO: open upload modal / navigate
|
||||||
|
await new Promise(r => setTimeout(r, 600))
|
||||||
|
setIdUploaded(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleCompleteInfo = useCallback(async () => {
|
||||||
|
// TODO: navigate to profile completion
|
||||||
|
await new Promise(r => setTimeout(r, 600))
|
||||||
|
setAdditionalInfo(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleSignContract = useCallback(async () => {
|
||||||
|
// TODO: open contract signing flow
|
||||||
|
await new Promise(r => setTimeout(r, 600))
|
||||||
|
setContractSigned(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const canUploadId = emailVerified
|
||||||
|
const canCompleteInfo = emailVerified && idUploaded
|
||||||
|
const canSignContract = emailVerified && idUploaded && additionalInfo
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageLayout>
|
||||||
|
<div className="relative min-h-screen w-full px-3 sm:px-4 py-10">
|
||||||
|
{/* Background Pattern */}
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
className="absolute inset-0 -z-10 h-full w-full stroke-white/10"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<pattern
|
||||||
|
x="50%"
|
||||||
|
y={-1}
|
||||||
|
id="affiliate-pattern"
|
||||||
|
width={200}
|
||||||
|
height={200}
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<path d="M.5 200V.5H200" fill="none" stroke="rgba(255,255,255,0.05)" />
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
<rect fill="url(#affiliate-pattern)" width="100%" height="100%" strokeWidth={0} />
|
||||||
|
</svg>
|
||||||
|
{/* Colored Blur Effect */}
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="absolute top-0 right-0 left-1/2 -z-10 -ml-24 transform-gpu overflow-hidden blur-3xl lg:ml-24 xl:ml-48"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
clipPath:
|
||||||
|
'polygon(63.1% 29.5%, 100% 17.1%, 76.6% 3%, 48.4% 0%, 44.6% 4.7%, 54.5% 25.3%, 59.8% 49%, 55.2% 57.8%, 44.4% 57.2%, 27.8% 47.9%, 35.1% 81.5%, 0% 97.7%, 39.2% 100%, 35.2% 81.4%, 97.2% 52.8%, 63.1% 29.5%)',
|
||||||
|
}}
|
||||||
|
className="aspect-[801/1036] w-[50.0625rem] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-50"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* Gradient base */}
|
||||||
|
<div className="absolute inset-0 -z-20 bg-gradient-to-b from-gray-900/95 via-gray-900/80 to-gray-900" />
|
||||||
|
<div className="max-w-6xl mx-auto">
|
||||||
|
{/* Welcome */}
|
||||||
|
<div className="text-center mb-8">
|
||||||
|
<h1 className="text-3xl sm:text-4xl font-bold text-white tracking-tight">
|
||||||
|
Welcome{user?.firstName ? `, ${user.firstName}` : ''}!
|
||||||
|
</h1>
|
||||||
|
<p className="text-sm sm:text-base text-blue-100 font-medium mt-2">
|
||||||
|
Personal Account
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Outer container card mimic (like screenshot) */}
|
||||||
|
<section className="bg-[#f8f9fc] rounded-xl shadow-sm ring-1 ring-black/5">
|
||||||
|
<div className="p-4 sm:p-6">
|
||||||
|
<div className="bg-white rounded-xl shadow-sm ring-1 ring-black/5 p-5 sm:p-8 space-y-12">
|
||||||
|
{/* Status Overview */}
|
||||||
|
<div>
|
||||||
|
<h2 className="text-sm sm:text-base font-semibold text-[#112c55] mb-5">
|
||||||
|
Status Overview
|
||||||
|
</h2>
|
||||||
|
<div className="grid gap-4 sm:gap-6 grid-cols-1 md:grid-cols-2 xl:grid-cols-4">
|
||||||
|
{statusItems.map(item => {
|
||||||
|
const CompleteIcon = item.complete ? CheckCircleIcon : XCircleIcon
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.key}
|
||||||
|
className={`rounded-lg px-4 py-6 flex flex-col items-center text-center border transition-colors ${
|
||||||
|
item.complete ? 'bg-emerald-50 border-emerald-100' : 'bg-rose-50 border-rose-100'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<CompleteIcon
|
||||||
|
className={`h-6 w-6 mb-4 ${item.complete ? 'text-emerald-600' : 'text-rose-600'}`}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`text-xs font-medium uppercase tracking-wide ${
|
||||||
|
item.complete ? 'text-emerald-700' : 'text-rose-700'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`mt-1 text-xs font-semibold ${
|
||||||
|
item.complete ? 'text-emerald-600' : 'text-rose-600'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{item.description}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Divider */}
|
||||||
|
<div className="h-px w-full bg-gray-200" />
|
||||||
|
|
||||||
|
{/* Quick Actions */}
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center gap-2 mb-5">
|
||||||
|
<span className="inline-flex items-center justify-center h-7 w-7 rounded-full bg-blue-100 text-blue-600 text-sm font-semibold">
|
||||||
|
i
|
||||||
|
</span>
|
||||||
|
<h2 className="text-sm sm:text-base font-semibold text-[#112c55]">
|
||||||
|
Quick Actions
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-4 sm:gap-6 grid-cols-1 md:grid-cols-2 xl:grid-cols-4">
|
||||||
|
{/* Email Verification */}
|
||||||
|
<button
|
||||||
|
onClick={handleVerifyEmail}
|
||||||
|
disabled={emailVerified}
|
||||||
|
className={`relative flex flex-col items-center justify-center rounded-lg px-4 py-5 text-center border font-medium text-sm transition-all ${
|
||||||
|
emailVerified
|
||||||
|
? 'bg-emerald-50 border-emerald-100 text-emerald-600 cursor-default'
|
||||||
|
: 'bg-blue-600 hover:bg-blue-500 text-white border-blue-600 shadow'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<EnvelopeOpenIcon className="h-6 w-6 mb-2" />
|
||||||
|
{emailVerified ? 'Email Verified' : 'Verify Email'}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* ID Upload */}
|
||||||
|
<button
|
||||||
|
onClick={handleUploadId}
|
||||||
|
disabled={!canUploadId || idUploaded}
|
||||||
|
className={`relative flex flex-col items-center justify-center rounded-lg px-4 py-5 text-center border font-medium text-sm transition-all ${
|
||||||
|
idUploaded
|
||||||
|
? 'bg-emerald-50 border-emerald-100 text-emerald-600 cursor-default'
|
||||||
|
: canUploadId
|
||||||
|
? 'bg-blue-600 hover:bg-blue-500 text-white border-blue-600 shadow'
|
||||||
|
: 'bg-gray-200 text-gray-500 border-gray-200 cursor-not-allowed'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<ArrowUpOnSquareIcon className="h-6 w-6 mb-2" />
|
||||||
|
{idUploaded ? 'ID Uploaded' : 'Upload ID Document'}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Additional Info */}
|
||||||
|
<button
|
||||||
|
onClick={handleCompleteInfo}
|
||||||
|
disabled={!canCompleteInfo || additionalInfo}
|
||||||
|
className={`relative flex flex-col items-center justify-center rounded-lg px-4 py-5 text-center border font-medium text-sm transition-all ${
|
||||||
|
additionalInfo
|
||||||
|
? 'bg-emerald-50 border-emerald-100 text-emerald-600 cursor-default'
|
||||||
|
: canCompleteInfo
|
||||||
|
? 'bg-blue-600 hover:bg-blue-500 text-white border-blue-600 shadow'
|
||||||
|
: 'bg-gray-200 text-gray-500 border-gray-200 cursor-not-allowed'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<PencilSquareIcon className="h-6 w-6 mb-2" />
|
||||||
|
{additionalInfo ? 'Profile Completed' : 'Complete Profile'}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Sign Contract */}
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<button
|
||||||
|
onClick={handleSignContract}
|
||||||
|
disabled={!canSignContract || contractSigned}
|
||||||
|
className={`flex flex-col flex-1 items-center justify-center rounded-lg px-4 py-5 text-center border font-medium text-sm transition-all ${
|
||||||
|
contractSigned
|
||||||
|
? 'bg-emerald-50 border-emerald-100 text-emerald-600 cursor-default'
|
||||||
|
: canSignContract
|
||||||
|
? 'bg-blue-600 hover:bg-blue-500 text-white border-blue-600 shadow'
|
||||||
|
: 'bg-gray-300 text-gray-600 border-gray-300 cursor-not-allowed'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<ClipboardDocumentCheckIcon className="h-6 w-6 mb-2" />
|
||||||
|
{contractSigned ? 'Contract Signed' : 'Sign Contract'}
|
||||||
|
</button>
|
||||||
|
{!canSignContract && !contractSigned && (
|
||||||
|
<p className="mt-2 text-[11px] text-red-600 leading-snug text-center">
|
||||||
|
Complete previous steps (email, ID, profile) before signing the contract.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Divider */}
|
||||||
|
<div className="h-px w-full bg-gray-200" />
|
||||||
|
|
||||||
|
{/* Latest News */}
|
||||||
|
<div>
|
||||||
|
<h2 className="text-sm sm:text-base font-semibold text-[#112c55] mb-4">
|
||||||
|
Latest News
|
||||||
|
</h2>
|
||||||
|
<ul className="list-disc pl-5 space-y-2 text-sm text-[#1b3358]">
|
||||||
|
<li>
|
||||||
|
<span className="font-medium text-[#8D6B1D]">New:</span> Referral system
|
||||||
|
launch – invite friends and earn rewards.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Profile completion unlocks more features. Keep progressing!
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user