mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-06-20 21:01:08 +00:00
Initial commit - PezkuwiChain Web Governance App
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { useAuth } from '@/contexts/AuthContext';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { User, Mail, Phone, Globe, MapPin, Calendar, Shield, AlertCircle } from 'lucide-react';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
|
||||
export default function Dashboard() {
|
||||
const { user } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
const [profile, setProfile] = useState<any>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchProfile();
|
||||
}, [user]);
|
||||
|
||||
const fetchProfile = async () => {
|
||||
if (!user) return;
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('profiles')
|
||||
.select('*')
|
||||
.eq('id', user.id)
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
setProfile(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching profile:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const sendVerificationEmail = async () => {
|
||||
try {
|
||||
const { data, error } = await supabase.functions.invoke('email-verification', {
|
||||
body: { action: 'send', email: user?.email }
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
toast({
|
||||
title: "Verification Email Sent",
|
||||
description: "Please check your email for verification link",
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Failed to send verification email",
|
||||
variant: "destructive"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="flex justify-center items-center h-screen">Loading...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto p-6 max-w-6xl">
|
||||
<h1 className="text-3xl font-bold mb-6">User Dashboard</h1>
|
||||
|
||||
<div className="grid gap-6 md:grid-cols-3 mb-6">
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">Account Status</CardTitle>
|
||||
<Shield className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">
|
||||
{profile?.email_verified ? (
|
||||
<Badge className="bg-green-500">Verified</Badge>
|
||||
) : (
|
||||
<Badge variant="destructive">Unverified</Badge>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Email verification status
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">Member Since</CardTitle>
|
||||
<Calendar className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">
|
||||
{new Date(profile?.joined_at || user?.created_at).toLocaleDateString()}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Registration date
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">Role</CardTitle>
|
||||
<User className="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">
|
||||
{profile?.role || 'Member'}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Account type
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="profile" className="space-y-4">
|
||||
<TabsList>
|
||||
<TabsTrigger value="profile">Profile</TabsTrigger>
|
||||
<TabsTrigger value="security">Security</TabsTrigger>
|
||||
<TabsTrigger value="activity">Activity</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="profile" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Profile Information</CardTitle>
|
||||
<CardDescription>Your personal details and contact information</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<User className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">Full Name:</span>
|
||||
<span>{profile?.full_name || 'Not set'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Mail className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">Email:</span>
|
||||
<span>{user?.email}</span>
|
||||
{!profile?.email_verified && (
|
||||
<Button size="sm" variant="outline" onClick={sendVerificationEmail}>
|
||||
Verify Email
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Mail className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">Recovery Email:</span>
|
||||
<span>{profile?.recovery_email || 'Not set'}</span>
|
||||
{profile?.recovery_email_verified && (
|
||||
<Badge className="bg-green-500">Verified</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Phone className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">Phone:</span>
|
||||
<span>{profile?.phone_number || 'Not set'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Globe className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">Website:</span>
|
||||
<span>{profile?.website || 'Not set'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<MapPin className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">Location:</span>
|
||||
<span>{profile?.location || 'Not set'}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={() => navigate('/settings')}>Edit Profile</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="security" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Security Settings</CardTitle>
|
||||
<CardDescription>Manage your account security</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-medium">Password</h3>
|
||||
<p className="text-sm text-muted-foreground">Last changed: Never</p>
|
||||
<Button onClick={() => navigate('/reset-password')}>Change Password</Button>
|
||||
</div>
|
||||
|
||||
{!profile?.email_verified && (
|
||||
<div className="border-l-4 border-yellow-500 bg-yellow-50 p-4">
|
||||
<div className="flex items-center">
|
||||
<AlertCircle className="h-5 w-5 text-yellow-600 mr-2" />
|
||||
<div>
|
||||
<h4 className="font-medium">Verify your email</h4>
|
||||
<p className="text-sm">Please verify your email to access all features</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="activity" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Recent Activity</CardTitle>
|
||||
<CardDescription>Your recent actions and transactions</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-muted-foreground">No recent activity</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user