mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-25 11:57:56 +00:00
Reorganize repository into monorepo structure
Restructured the project to support multiple frontend applications: - Move web app to web/ directory - Create pezkuwi-sdk-ui/ for Polkadot SDK clone (planned) - Create mobile/ directory for mobile app development - Add shared/ directory with common utilities, types, and blockchain code - Update README.md with comprehensive documentation - Remove obsolete DKSweb/ directory This monorepo structure enables better code sharing and organized development across web, mobile, and SDK UI projects.
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { Users, Settings, Activity, Shield, Bell, Trash2, Monitor, Lock, AlertTriangle, ArrowLeft } from 'lucide-react';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { SessionMonitor } from '@/components/security/SessionMonitor';
|
||||
import { PermissionEditor } from '@/components/security/PermissionEditor';
|
||||
import { SecurityAudit } from '@/components/security/SecurityAudit';
|
||||
export default function AdminPanel() {
|
||||
const navigate = useNavigate();
|
||||
const [users, setUsers] = useState<any[]>([]);
|
||||
const [adminRoles, setAdminRoles] = useState<any[]>([]);
|
||||
const [systemSettings, setSystemSettings] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { toast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
loadAdminData();
|
||||
}, []);
|
||||
|
||||
const loadAdminData = async () => {
|
||||
try {
|
||||
// Load users
|
||||
const { data: profiles } = await supabase
|
||||
.from('profiles')
|
||||
.select('*')
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
// Load admin roles
|
||||
const { data: roles } = await supabase
|
||||
.from('admin_roles')
|
||||
.select('*');
|
||||
|
||||
// Load system settings
|
||||
const { data: settings } = await supabase
|
||||
.from('system_settings')
|
||||
.select('*');
|
||||
|
||||
setUsers(profiles || []);
|
||||
setAdminRoles(roles || []);
|
||||
setSystemSettings(settings || []);
|
||||
} catch (error) {
|
||||
console.error('Error loading admin data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const updateUserRole = async (userId: string, role: string) => {
|
||||
try {
|
||||
if (role === 'none') {
|
||||
await supabase
|
||||
.from('admin_roles')
|
||||
.delete()
|
||||
.eq('user_id', userId);
|
||||
} else {
|
||||
await supabase
|
||||
.from('admin_roles')
|
||||
.upsert({
|
||||
user_id: userId,
|
||||
role,
|
||||
updated_at: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
toast({
|
||||
title: 'Success',
|
||||
description: 'User role updated successfully',
|
||||
});
|
||||
loadAdminData();
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'Failed to update user role',
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const sendNotification = async (userId: string) => {
|
||||
const title = prompt('Notification Title:');
|
||||
const message = prompt('Notification Message:');
|
||||
|
||||
if (!title || !message) return;
|
||||
|
||||
try {
|
||||
const { error } = await supabase.functions.invoke('notifications-manager', {
|
||||
body: {
|
||||
action: 'create',
|
||||
userId,
|
||||
title,
|
||||
message,
|
||||
type: 'info'
|
||||
}
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
toast({
|
||||
title: 'Success',
|
||||
description: 'Notification sent successfully',
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'Failed to send notification',
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getUserRole = (userId: string) => {
|
||||
const role = adminRoles.find(r => r.user_id === userId);
|
||||
return role?.role || 'none';
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="flex justify-center items-center h-screen">Loading...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 relative">
|
||||
<button
|
||||
onClick={() => navigate('/')}
|
||||
className="absolute top-4 left-4 text-gray-400 hover:text-white transition-colors"
|
||||
>
|
||||
<ArrowLeft className="w-5 h-5" />
|
||||
</button>
|
||||
<h1 className="text-3xl font-bold mb-8">Admin Panel</h1>
|
||||
|
||||
<Tabs defaultValue="users" className="space-y-4">
|
||||
<TabsList className="grid w-full grid-cols-7">
|
||||
<TabsTrigger value="users">
|
||||
<Users className="mr-2 h-4 w-4" />
|
||||
Users
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="roles">
|
||||
<Shield className="mr-2 h-4 w-4" />
|
||||
Roles
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="sessions">
|
||||
<Monitor className="mr-2 h-4 w-4" />
|
||||
Sessions
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="permissions">
|
||||
<Lock className="mr-2 h-4 w-4" />
|
||||
Permissions
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="security">
|
||||
<AlertTriangle className="mr-2 h-4 w-4" />
|
||||
Security
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="activity">
|
||||
<Activity className="mr-2 h-4 w-4" />
|
||||
Activity
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="settings">
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
Settings
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="users">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>User Management</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Username</TableHead>
|
||||
<TableHead>Email</TableHead>
|
||||
<TableHead>Verified</TableHead>
|
||||
<TableHead>Role</TableHead>
|
||||
<TableHead>Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{users.map((user) => (
|
||||
<TableRow key={user.id}>
|
||||
<TableCell>{user.username}</TableCell>
|
||||
<TableCell>{user.email}</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant={user.email_verified ? 'default' : 'secondary'}>
|
||||
{user.email_verified ? 'Verified' : 'Unverified'}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Select
|
||||
value={getUserRole(user.id)}
|
||||
onValueChange={(value) => updateUserRole(user.id, value)}
|
||||
>
|
||||
<SelectTrigger className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">User</SelectItem>
|
||||
<SelectItem value="moderator">Moderator</SelectItem>
|
||||
<SelectItem value="admin">Admin</SelectItem>
|
||||
<SelectItem value="super_admin">Super Admin</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => sendNotification(user.id)}
|
||||
>
|
||||
<Bell className="h-4 w-4 mr-1" />
|
||||
Notify
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="roles">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Admin Roles</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{adminRoles.map((role) => {
|
||||
const user = users.find(u => u.id === role.user_id);
|
||||
return (
|
||||
<div key={role.id} className="flex items-center justify-between p-4 border rounded">
|
||||
<div>
|
||||
<p className="font-medium">{user?.username}</p>
|
||||
<p className="text-sm text-muted-foreground">{user?.email}</p>
|
||||
</div>
|
||||
<Badge variant="outline">{role.role}</Badge>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="sessions">
|
||||
<SessionMonitor />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="permissions">
|
||||
<PermissionEditor />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="security">
|
||||
<SecurityAudit />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="activity">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Recent Activity</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-muted-foreground">Activity logs will be displayed here</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
<TabsContent value="settings">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>System Settings</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label>Maintenance Mode</Label>
|
||||
<Select defaultValue="off">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="off">Off</SelectItem>
|
||||
<SelectItem value="on">On</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Registration</Label>
|
||||
<Select defaultValue="open">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="open">Open</SelectItem>
|
||||
<SelectItem value="closed">Closed</SelectItem>
|
||||
<SelectItem value="invite">Invite Only</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user