- Added `useUserStatus` hook to manage user status fetching and state. - Integrated user status in Quick Action Dashboard and related pages. - Enhanced error handling and loading states for user status. - Updated profile completion and document upload flows to refresh user status after actions. - Created a centralized API utility for handling requests and responses. - Refactored authentication token management to use session storage.
279 lines
11 KiB
TypeScript
279 lines
11 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect } from 'react'
|
|
import { useRouter } from 'next/navigation'
|
|
import useAuthStore from '../store/authStore'
|
|
import Header from '../components/nav/Header'
|
|
import Footer from '../components/Footer'
|
|
import {
|
|
ShoppingBagIcon,
|
|
UsersIcon,
|
|
UserCircleIcon,
|
|
StarIcon,
|
|
ChartBarIcon,
|
|
HeartIcon,
|
|
BuildingOffice2Icon // <-- added
|
|
} from '@heroicons/react/24/outline'
|
|
|
|
export default function DashboardPage() {
|
|
const router = useRouter()
|
|
const user = useAuthStore(state => state.user)
|
|
const isAuthReady = useAuthStore(state => state.isAuthReady)
|
|
|
|
// Redirect if not logged in (only after auth is ready)
|
|
useEffect(() => {
|
|
if (isAuthReady && !user) {
|
|
router.push('/login')
|
|
}
|
|
}, [isAuthReady, user, router])
|
|
|
|
// Show loading until auth is ready or user is confirmed
|
|
if (!isAuthReady || !user) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center">
|
|
<div className="text-center">
|
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#8D6B1D] mx-auto mb-4"></div>
|
|
<p className="text-[#4A4A4A]">Loading...</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// Get user name
|
|
const getUserName = () => {
|
|
if (user.firstName && user.lastName) {
|
|
return `${user.firstName} ${user.lastName}`
|
|
}
|
|
if (user.firstName) return user.firstName
|
|
if (user.email) return user.email.split('@')[0]
|
|
return 'User'
|
|
}
|
|
|
|
// Quick actions
|
|
const quickActions = [
|
|
{
|
|
title: 'Browse Shop',
|
|
description: 'Explore sustainable products',
|
|
icon: ShoppingBagIcon,
|
|
href: '/shop',
|
|
color: 'bg-blue-500'
|
|
},
|
|
{
|
|
title: 'Join Community',
|
|
description: 'Connect with like-minded people',
|
|
icon: UsersIcon,
|
|
href: '/community',
|
|
color: 'bg-green-500'
|
|
},
|
|
{
|
|
title: 'Edit Profile',
|
|
description: 'Update your information',
|
|
icon: UserCircleIcon,
|
|
href: '/profile',
|
|
color: 'bg-purple-500'
|
|
}
|
|
]
|
|
|
|
// Stats (mock data for now)
|
|
const stats = [
|
|
{ label: 'Orders', value: '12', icon: ShoppingBagIcon },
|
|
{ label: 'Favorites', value: '8', icon: HeartIcon },
|
|
{ label: 'Gold Points', value: '250', icon: StarIcon },
|
|
{ label: 'Activity', value: '15', icon: ChartBarIcon }
|
|
]
|
|
|
|
// Referral statistics (mock values)
|
|
const referralStats = [
|
|
{ label: 'Registered Users', value: '123', icon: UsersIcon, color: 'bg-indigo-600' },
|
|
{ label: 'Personal Users', value: '85', icon: UserCircleIcon, color: 'bg-teal-600' },
|
|
{ label: 'Company Users', value: '38', icon: BuildingOffice2Icon, color: 'bg-amber-600' },
|
|
]
|
|
|
|
return (
|
|
<div className="min-h-screen flex flex-col bg-gray-50">
|
|
<Header />
|
|
|
|
<main className="flex-1 py-8 px-4 sm:px-6 lg:px-8">
|
|
<div className="max-w-7xl mx-auto">
|
|
{/* Welcome Section */}
|
|
<div className="mb-8">
|
|
<h1 className="text-3xl font-bold text-gray-900">
|
|
Welcome back, {getUserName()}! 👋
|
|
</h1>
|
|
<p className="text-gray-600 mt-2">
|
|
Here's what's happening with your Profit Planet account
|
|
</p>
|
|
</div>
|
|
|
|
{/* Account setup note */}
|
|
<div className="mb-8 bg-blue-50 border border-blue-200 rounded-lg p-4">
|
|
<div className="flex">
|
|
<div className="flex-shrink-0">
|
|
<UserCircleIcon className="h-5 w-5 text-blue-400" aria-hidden="true" />
|
|
</div>
|
|
<div className="ml-3">
|
|
<h3 className="text-sm font-medium text-blue-800">
|
|
Complete your account setup
|
|
</h3>
|
|
<div className="mt-2 text-sm text-blue-700">
|
|
<p>
|
|
Complete your verification process to unlock all features.{' '}
|
|
<button
|
|
onClick={() => router.push('/quickaction-dashboard')}
|
|
className="font-medium underline text-blue-800 hover:text-blue-900"
|
|
>
|
|
Start verification →
|
|
</button>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Stats Grid - Tailwind UI Plus "With brand icon" */}
|
|
<div className="mb-8">
|
|
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
|
|
{stats.map((stat, index) => {
|
|
// Define icon colors for each stat
|
|
const iconColors = [
|
|
'bg-blue-500', // Orders
|
|
'bg-red-500', // Favorites
|
|
'bg-yellow-500', // Gold Points
|
|
'bg-green-500' // Activity
|
|
];
|
|
|
|
return (
|
|
<div key={index} className="relative overflow-hidden rounded-lg bg-white px-4 pb-12 pt-5 shadow sm:px-6 sm:pt-6">
|
|
<dt>
|
|
<div className={`absolute rounded-md ${iconColors[index]} p-3`}>
|
|
<stat.icon aria-hidden="true" className="h-6 w-6 text-white" />
|
|
</div>
|
|
<p className="ml-16 truncate text-sm font-medium text-gray-500">{stat.label}</p>
|
|
</dt>
|
|
<dd className="ml-16 flex items-baseline pb-6 sm:pb-7">
|
|
<p className="text-2xl font-semibold text-gray-900">{stat.value}</p>
|
|
<div className="absolute inset-x-0 bottom-0 bg-gray-50 px-4 py-4 sm:px-6">
|
|
<div className="text-sm">
|
|
<a href="#" className="font-medium text-[#8D6B1D] hover:text-[#7A5E1A]">
|
|
View details
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</dd>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Referral Statistics */}
|
|
<div className="mb-8">
|
|
<h2 className="text-xl font-semibold text-gray-900 mb-4">Referral Statistics</h2>
|
|
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
|
|
{referralStats.map((stat, i) => (
|
|
<div key={i} className="relative overflow-hidden rounded-lg bg-white px-4 pb-10 pt-5 shadow sm:px-6 sm:pt-6">
|
|
<dt>
|
|
<div className={`absolute rounded-md ${stat.color} p-3`}>
|
|
<stat.icon aria-hidden="true" className="h-6 w-6 text-white" />
|
|
</div>
|
|
<p className="ml-16 truncate text-sm font-medium text-gray-500">{stat.label}</p>
|
|
</dt>
|
|
<dd className="ml-16 flex items-baseline pb-2">
|
|
<p className="text-2xl font-semibold text-gray-900">{stat.value}</p>
|
|
</dd>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Quick Actions */}
|
|
<div className="mb-8">
|
|
<h2 className="text-xl font-semibold text-gray-900 mb-4">Quick Actions</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
{quickActions.map((action, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => router.push(action.href)}
|
|
className="bg-white rounded-lg p-6 shadow-sm border border-gray-200 hover:shadow-md transition-shadow text-left group"
|
|
>
|
|
<div className="flex items-start">
|
|
<div className={`${action.color} rounded-lg p-3 group-hover:scale-105 transition-transform`}>
|
|
<action.icon className="h-6 w-6 text-white" />
|
|
</div>
|
|
<div className="ml-4 flex-1">
|
|
<h3 className="text-lg font-medium text-gray-900 group-hover:text-[#8D6B1D] transition-colors">
|
|
{action.title}
|
|
</h3>
|
|
<p className="text-sm text-gray-600 mt-1">
|
|
{action.description}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Gold Member Status */}
|
|
<div className="bg-gradient-to-r from-[#8D6B1D] to-[#B8860B] rounded-lg p-6 text-white mb-8">
|
|
<div className="flex items-center">
|
|
<StarIcon className="h-12 w-12 text-yellow-300" />
|
|
<div className="ml-4">
|
|
<h2 className="text-2xl font-bold">Gold Member Status</h2>
|
|
<p className="text-yellow-100 mt-1">
|
|
Enjoy exclusive benefits and discounts
|
|
</p>
|
|
</div>
|
|
<div className="ml-auto">
|
|
<button className="bg-white/20 hover:bg-white/30 px-4 py-2 rounded-lg text-white font-medium transition-colors">
|
|
View Benefits
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Recent Activity */}
|
|
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
<h2 className="text-xl font-semibold text-gray-900 mb-4">Recent Activity</h2>
|
|
<div className="space-y-4">
|
|
<div className="flex items-center py-3 border-b border-gray-100 last:border-b-0">
|
|
<div className="bg-green-100 rounded-full p-2">
|
|
<ShoppingBagIcon className="h-5 w-5 text-green-600" />
|
|
</div>
|
|
<div className="ml-4 flex-1">
|
|
<p className="text-sm font-medium text-gray-900">Order completed</p>
|
|
<p className="text-sm text-gray-600">Eco-friendly water bottle</p>
|
|
</div>
|
|
<span className="text-sm text-gray-500">2 days ago</span>
|
|
</div>
|
|
|
|
<div className="flex items-center py-3 border-b border-gray-100 last:border-b-0">
|
|
<div className="bg-blue-100 rounded-full p-2">
|
|
<HeartIcon className="h-5 w-5 text-blue-600" />
|
|
</div>
|
|
<div className="ml-4 flex-1">
|
|
<p className="text-sm font-medium text-gray-900">Added to favorites</p>
|
|
<p className="text-sm text-gray-600">Sustainable backpack</p>
|
|
</div>
|
|
<span className="text-sm text-gray-500">1 week ago</span>
|
|
</div>
|
|
|
|
<div className="flex items-center py-3">
|
|
<div className="bg-purple-100 rounded-full p-2">
|
|
<UsersIcon className="h-5 w-5 text-purple-600" />
|
|
</div>
|
|
<div className="ml-4 flex-1">
|
|
<p className="text-sm font-medium text-gray-900">Joined community</p>
|
|
<p className="text-sm text-gray-600">Eco Warriors Group</p>
|
|
</div>
|
|
<span className="text-sm text-gray-500">2 weeks ago</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<Footer />
|
|
</div>
|
|
)
|
|
} |