wexts 4.0.0 → 4.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -49
- package/bin/wexts.cjs +2 -2
- package/package.json +153 -148
- package/templates/.dockerignore +43 -43
- package/templates/.env.example +17 -17
- package/templates/Dockerfile +60 -60
- package/templates/Procfile +1 -1
- package/templates/README.md +67 -67
- package/templates/api-sdk.ts +115 -115
- package/templates/docker-compose.yml +34 -34
- package/templates/nestjs-api/.env.example +3 -3
- package/templates/nestjs-api/README.md +87 -87
- package/templates/nestjs-api/nest-cli.json +6 -6
- package/templates/nestjs-api/package.json +40 -40
- package/templates/nestjs-api/prisma/migrations/20251123205437_init/migration.sql +24 -24
- package/templates/nestjs-api/prisma/migrations/migration_lock.toml +3 -3
- package/templates/nestjs-api/prisma/schema.prisma +29 -29
- package/templates/nestjs-api/src/app.module.ts +17 -17
- package/templates/nestjs-api/src/auth/auth.controller.ts +27 -27
- package/templates/nestjs-api/src/auth/auth.module.ts +37 -37
- package/templates/nestjs-api/src/auth/auth.service.ts +86 -86
- package/templates/nestjs-api/src/auth/dto/auth.dto.ts +22 -22
- package/templates/nestjs-api/src/auth/guards/jwt-auth.guard.ts +5 -5
- package/templates/nestjs-api/src/auth/strategies/jwt.strategy.ts +27 -27
- package/templates/nestjs-api/src/main.ts +32 -32
- package/templates/nestjs-api/src/prisma/prisma.module.ts +9 -9
- package/templates/nestjs-api/src/prisma/prisma.service.ts +14 -14
- package/templates/nestjs-api/src/todos/dto/todo.dto.ts +24 -24
- package/templates/nestjs-api/src/todos/todos.controller.ts +39 -39
- package/templates/nestjs-api/src/todos/todos.module.ts +11 -11
- package/templates/nestjs-api/src/todos/todos.service.ts +53 -53
- package/templates/nestjs-api/src/users/users.controller.ts +14 -14
- package/templates/nestjs-api/src/users/users.module.ts +12 -12
- package/templates/nestjs-api/src/users/users.service.ts +19 -19
- package/templates/nestjs-api/tsconfig.json +39 -39
- package/templates/nextjs-web/README.md +76 -76
- package/templates/nextjs-web/app/actions/auth.ts +108 -108
- package/templates/nextjs-web/app/dashboard/error.tsx +39 -39
- package/templates/nextjs-web/app/dashboard/loading.tsx +14 -14
- package/templates/nextjs-web/app/dashboard/page.tsx +5 -5
- package/templates/nextjs-web/app/globals.css +93 -93
- package/templates/nextjs-web/app/layout.tsx +29 -29
- package/templates/nextjs-web/app/login/page.tsx +5 -5
- package/templates/nextjs-web/app/page.tsx +28 -28
- package/templates/nextjs-web/app/register/page.tsx +5 -5
- package/templates/nextjs-web/components/ui/button.tsx +56 -56
- package/templates/nextjs-web/components/ui/card.tsx +79 -79
- package/templates/nextjs-web/components/ui/input.tsx +25 -25
- package/templates/nextjs-web/components/ui/label.tsx +24 -24
- package/templates/nextjs-web/features/auth/LoginForm.tsx +140 -140
- package/templates/nextjs-web/features/auth/RegisterForm.tsx +159 -159
- package/templates/nextjs-web/features/auth/api.ts +35 -35
- package/templates/nextjs-web/features/auth/index.ts +3 -3
- package/templates/nextjs-web/features/dashboard/DashboardView.tsx +204 -204
- package/templates/nextjs-web/features/dashboard/api.ts +9 -9
- package/templates/nextjs-web/features/dashboard/components.tsx +74 -74
- package/templates/nextjs-web/features/dashboard/index.ts +3 -3
- package/templates/nextjs-web/hooks/index.ts +4 -4
- package/templates/nextjs-web/lib/api-client.ts +89 -89
- package/templates/nextjs-web/lib/api.ts +115 -115
- package/templates/nextjs-web/lib/axios-global-config.ts +17 -17
- package/templates/nextjs-web/lib/utils.ts +6 -6
- package/templates/nextjs-web/lib/wexts-client.ts +4 -4
- package/templates/nextjs-web/next-env.d.ts +6 -6
- package/templates/nextjs-web/next.config.ts +20 -20
- package/templates/nextjs-web/package.json +37 -37
- package/templates/nextjs-web/postcss.config.js +6 -6
- package/templates/nextjs-web/tailwind.config.ts +69 -69
- package/templates/nextjs-web/tsconfig.json +41 -41
- package/templates/nixpacks.toml +11 -11
- package/templates/root-package.json +31 -31
- package/templates/server.ts +66 -66
- package/templates/tsconfig.json +30 -30
- package/dist/chunk-2KAQYLVN.js +0 -1
- package/dist/chunk-2KAQYLVN.js.map +0 -1
- package/dist/chunk-2LJVUMXW.js +0 -228
- package/dist/chunk-2LJVUMXW.js.map +0 -1
- package/dist/chunk-7QKLIVRF.js +0 -94
- package/dist/chunk-7QKLIVRF.js.map +0 -1
- package/dist/chunk-7WULUGLH.mjs +0 -22
- package/dist/chunk-7WULUGLH.mjs.map +0 -1
- package/dist/chunk-BG56B4DE.js +0 -106
- package/dist/chunk-BG56B4DE.js.map +0 -1
- package/dist/chunk-CLM5PNSG.mjs +0 -496
- package/dist/chunk-CLM5PNSG.mjs.map +0 -1
- package/dist/chunk-DNLGCKTT.js +0 -31
- package/dist/chunk-DNLGCKTT.js.map +0 -1
- package/dist/chunk-JHOVXH3X.mjs +0 -65
- package/dist/chunk-JHOVXH3X.mjs.map +0 -1
- package/dist/chunk-MXINIFPC.js +0 -105
- package/dist/chunk-MXINIFPC.js.map +0 -1
- package/dist/chunk-SE32ZPOZ.js +0 -496
- package/dist/chunk-SE32ZPOZ.js.map +0 -1
- package/dist/chunk-UAL54DVV.mjs +0 -106
- package/dist/chunk-UAL54DVV.mjs.map +0 -1
- package/dist/chunk-WCKSKU3C.js +0 -65
- package/dist/chunk-WCKSKU3C.js.map +0 -1
- package/dist/chunk-WU6FW77M.mjs +0 -105
- package/dist/chunk-WU6FW77M.mjs.map +0 -1
- package/dist/chunk-XE4OXN2W.js +0 -12
- package/dist/chunk-XE4OXN2W.js.map +0 -1
- package/dist/chunk-YBM3IJEA.mjs +0 -94
- package/dist/chunk-YBM3IJEA.mjs.map +0 -1
- package/dist/chunk-YN6WIWNQ.mjs +0 -228
- package/dist/chunk-YN6WIWNQ.mjs.map +0 -1
- package/dist/chunk-YSLEF5C5.mjs +0 -1
- package/dist/chunk-YSLEF5C5.mjs.map +0 -1
- package/dist/chunk-ZX7QIN24.mjs +0 -31
- package/dist/chunk-ZX7QIN24.mjs.map +0 -1
- package/dist/cli/index.d.mts +0 -11
- package/dist/cli/index.d.ts +0 -11
- package/dist/cli/index.js +0 -332
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/index.mjs +0 -334
- package/dist/cli/index.mjs.map +0 -1
- package/dist/client/index.d.mts +0 -21
- package/dist/client/index.d.ts +0 -21
- package/dist/client/index.js +0 -12
- package/dist/client/index.js.map +0 -1
- package/dist/client/index.mjs +0 -12
- package/dist/client/index.mjs.map +0 -1
- package/dist/codegen/index.d.mts +0 -2
- package/dist/codegen/index.d.ts +0 -2
- package/dist/codegen/index.js +0 -15
- package/dist/codegen/index.js.map +0 -1
- package/dist/codegen/index.mjs +0 -15
- package/dist/codegen/index.mjs.map +0 -1
- package/dist/decorators-BT1FFqN0.d.mts +0 -29
- package/dist/decorators-DvS58PqC.d.ts +0 -29
- package/dist/dev-server/index.d.mts +0 -1
- package/dist/dev-server/index.d.ts +0 -1
- package/dist/dev-server/index.js +0 -13
- package/dist/dev-server/index.js.map +0 -1
- package/dist/dev-server/index.mjs +0 -13
- package/dist/dev-server/index.mjs.map +0 -1
- package/dist/index-7QeQEf37.d.ts +0 -92
- package/dist/index-7RvU-jGE.d.mts +0 -66
- package/dist/index-7RvU-jGE.d.ts +0 -66
- package/dist/index-8nzxy0NN.d.mts +0 -92
- package/dist/index-Co5ZsLqq.d.ts +0 -58
- package/dist/index-D94W1__r.d.mts +0 -58
- package/dist/index-DQmyVp6F.d.mts +0 -27
- package/dist/index-KL_1BrQb.d.ts +0 -27
- package/dist/index.d.mts +0 -258
- package/dist/index.d.ts +0 -258
- package/dist/index.js +0 -410
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -410
- package/dist/index.mjs.map +0 -1
- package/dist/nest/index.d.mts +0 -3
- package/dist/nest/index.d.ts +0 -3
- package/dist/nest/index.js +0 -38
- package/dist/nest/index.js.map +0 -1
- package/dist/nest/index.mjs +0 -38
- package/dist/nest/index.mjs.map +0 -1
- package/dist/next/index.d.mts +0 -66
- package/dist/next/index.d.ts +0 -66
- package/dist/next/index.js +0 -226
- package/dist/next/index.js.map +0 -1
- package/dist/next/index.mjs +0 -188
- package/dist/next/index.mjs.map +0 -1
- package/dist/rpc/index.d.mts +0 -2
- package/dist/rpc/index.d.ts +0 -2
- package/dist/rpc/index.js +0 -23
- package/dist/rpc/index.js.map +0 -1
- package/dist/rpc/index.mjs +0 -23
- package/dist/rpc/index.mjs.map +0 -1
- package/dist/runtime/index.d.mts +0 -55
- package/dist/runtime/index.d.ts +0 -55
- package/dist/runtime/index.js +0 -213
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/index.mjs +0 -213
- package/dist/runtime/index.mjs.map +0 -1
- package/dist/types/index.d.mts +0 -12
- package/dist/types/index.d.ts +0 -12
- package/dist/types/index.js +0 -2
- package/dist/types/index.js.map +0 -1
- package/dist/types/index.mjs +0 -3
- package/dist/types/index.mjs.map +0 -1
- package/dist/types-7d_fC-C3.d.mts +0 -32
- package/dist/types-7d_fC-C3.d.ts +0 -32
- package/dist/vercel-builder/index.d.mts +0 -58
- package/dist/vercel-builder/index.d.ts +0 -58
- package/dist/vercel-builder/index.js +0 -330
- package/dist/vercel-builder/index.js.map +0 -1
- package/dist/vercel-builder/index.mjs +0 -330
- package/dist/vercel-builder/index.mjs.map +0 -1
- package/templates/nestjs-api/package-lock.json +0 -5623
- package/templates/nextjs-web/package-lock.json +0 -3254
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import { postData, applyLogin, applyLogout } from '@/lib/api-client';
|
|
2
|
-
import { toast } from 'react-hot-toast';
|
|
3
|
-
|
|
4
|
-
export const login = async (data: any) => {
|
|
5
|
-
try {
|
|
6
|
-
const response = await postData('/auth/login', data, false);
|
|
7
|
-
if (response.token) {
|
|
8
|
-
applyLogin(response.token);
|
|
9
|
-
toast.success('Logged in successfully! 🚀');
|
|
10
|
-
return response;
|
|
11
|
-
}
|
|
12
|
-
} catch (error: any) {
|
|
13
|
-
toast.error(error.response?.data?.message || 'Login failed');
|
|
14
|
-
throw error;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const register = async (data: any) => {
|
|
19
|
-
try {
|
|
20
|
-
const response = await postData('/auth/register', data, false);
|
|
21
|
-
if (response.token) {
|
|
22
|
-
applyLogin(response.token);
|
|
23
|
-
toast.success('Account created successfully! 🎉');
|
|
24
|
-
return response;
|
|
25
|
-
}
|
|
26
|
-
} catch (error: any) {
|
|
27
|
-
toast.error(error.response?.data?.message || 'Registration failed');
|
|
28
|
-
throw error;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const logout = async () => {
|
|
33
|
-
await applyLogout();
|
|
34
|
-
toast.success('Logged out');
|
|
35
|
-
};
|
|
1
|
+
import { postData, applyLogin, applyLogout } from '@/lib/api-client';
|
|
2
|
+
import { toast } from 'react-hot-toast';
|
|
3
|
+
|
|
4
|
+
export const login = async (data: any) => {
|
|
5
|
+
try {
|
|
6
|
+
const response = await postData('/auth/login', data, false);
|
|
7
|
+
if (response.token) {
|
|
8
|
+
applyLogin(response.token);
|
|
9
|
+
toast.success('Logged in successfully! 🚀');
|
|
10
|
+
return response;
|
|
11
|
+
}
|
|
12
|
+
} catch (error: any) {
|
|
13
|
+
toast.error(error.response?.data?.message || 'Login failed');
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const register = async (data: any) => {
|
|
19
|
+
try {
|
|
20
|
+
const response = await postData('/auth/register', data, false);
|
|
21
|
+
if (response.token) {
|
|
22
|
+
applyLogin(response.token);
|
|
23
|
+
toast.success('Account created successfully! 🎉');
|
|
24
|
+
return response;
|
|
25
|
+
}
|
|
26
|
+
} catch (error: any) {
|
|
27
|
+
toast.error(error.response?.data?.message || 'Registration failed');
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const logout = async () => {
|
|
33
|
+
await applyLogout();
|
|
34
|
+
toast.success('Logged out');
|
|
35
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './api';
|
|
2
|
-
export * from './LoginForm';
|
|
3
|
-
export * from './RegisterForm';
|
|
1
|
+
export * from './api';
|
|
2
|
+
export * from './LoginForm';
|
|
3
|
+
export * from './RegisterForm';
|
|
@@ -1,204 +1,204 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { motion } from 'framer-motion';
|
|
4
|
-
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
5
|
-
import { Button } from '@/components/ui/button';
|
|
6
|
-
import { logout } from '@/features/auth';
|
|
7
|
-
import { toast } from 'react-hot-toast';
|
|
8
|
-
import {
|
|
9
|
-
DollarSign,
|
|
10
|
-
Users,
|
|
11
|
-
ShoppingBag,
|
|
12
|
-
Activity,
|
|
13
|
-
ClipboardList,
|
|
14
|
-
CheckCircle2,
|
|
15
|
-
Clock,
|
|
16
|
-
Hourglass,
|
|
17
|
-
Bell,
|
|
18
|
-
LogOut
|
|
19
|
-
} from 'lucide-react';
|
|
20
|
-
|
|
21
|
-
// Mock Data for Demo
|
|
22
|
-
const MOCK_STATS = [
|
|
23
|
-
{ title: 'Total Revenue', value: '$45,231.89', change: '+20.1% from last month', icon: DollarSign, color: 'from-green-500/20 to-emerald-500/20', iconColor: 'text-green-500' },
|
|
24
|
-
{ title: 'Subscriptions', value: '+2350', change: '+180.1% from last month', icon: Users, color: 'from-blue-500/20 to-indigo-500/20', iconColor: 'text-blue-500' },
|
|
25
|
-
{ title: 'Sales', value: '+12,234', change: '+19% from last month', icon: ShoppingBag, color: 'from-orange-500/20 to-red-500/20', iconColor: 'text-orange-500' },
|
|
26
|
-
{ title: 'Active Now', value: '+573', change: '+201 since last hour', icon: Activity, color: 'from-purple-500/20 to-pink-500/20', iconColor: 'text-purple-500' },
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const MOCK_TODOS = [
|
|
30
|
-
{ id: 1, title: 'Review project proposal', status: 'completed', date: 'Today, 10:00 AM' },
|
|
31
|
-
{ id: 2, title: 'Team meeting with design team', status: 'pending', date: 'Today, 2:00 PM' },
|
|
32
|
-
{ id: 3, title: 'Update documentation', status: 'in-progress', date: 'Tomorrow, 11:00 AM' },
|
|
33
|
-
{ id: 4, title: 'Deploy to production', status: 'pending', date: 'Wed, 4:00 PM' },
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
const MOCK_ACTIVITIES = [
|
|
37
|
-
{ id: 1, user: 'Alice Smith', action: 'created a new project', time: '2 min ago' },
|
|
38
|
-
{ id: 2, user: 'Bob Johnson', action: 'commented on task #123', time: '15 min ago' },
|
|
39
|
-
{ id: 3, user: 'Charlie Brown', action: 'completed onboarding', time: '1 hour ago' },
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
export function DashboardView() {
|
|
43
|
-
const handleLogout = async () => {
|
|
44
|
-
await logout();
|
|
45
|
-
toast.success('Logged out successfully');
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const container = {
|
|
49
|
-
hidden: { opacity: 0 },
|
|
50
|
-
show: {
|
|
51
|
-
opacity: 1,
|
|
52
|
-
transition: {
|
|
53
|
-
staggerChildren: 0.1
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const item = {
|
|
59
|
-
hidden: { y: 20, opacity: 0 },
|
|
60
|
-
show: { y: 0, opacity: 1 }
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<div className="min-h-screen bg-background p-8 relative overflow-hidden">
|
|
65
|
-
{/* Animated Background */}
|
|
66
|
-
<div className="fixed inset-0 overflow-hidden pointer-events-none -z-10">
|
|
67
|
-
<div className="absolute -top-[40%] -right-[30%] w-[70%] h-[70%] rounded-full bg-primary/10 blur-[120px] animate-float" />
|
|
68
|
-
<div className="absolute top-[60%] -left-[20%] w-[50%] h-[50%] rounded-full bg-indigo-500/10 blur-[100px] animate-float" style={{ animationDelay: '3s' }} />
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
<div className="max-w-7xl mx-auto space-y-8">
|
|
72
|
-
{/* Header */}
|
|
73
|
-
<motion.div
|
|
74
|
-
initial={{ opacity: 0, y: -20 }}
|
|
75
|
-
animate={{ opacity: 1, y: 0 }}
|
|
76
|
-
className="flex items-center justify-between"
|
|
77
|
-
>
|
|
78
|
-
<div>
|
|
79
|
-
<h1 className="text-4xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-indigo-600 mb-2">
|
|
80
|
-
Dashboard Overview
|
|
81
|
-
</h1>
|
|
82
|
-
<p className="text-muted-foreground">Welcome back, Ziad! Here's what's happening today.</p>
|
|
83
|
-
</div>
|
|
84
|
-
<Button onClick={handleLogout} variant="outline" className="border-primary/20 hover:bg-primary/10 hover:text-primary transition-colors gap-2">
|
|
85
|
-
<LogOut className="w-4 h-4" />
|
|
86
|
-
Sign out
|
|
87
|
-
</Button>
|
|
88
|
-
</motion.div>
|
|
89
|
-
|
|
90
|
-
{/* Stats Grid */}
|
|
91
|
-
<motion.div
|
|
92
|
-
variants={container}
|
|
93
|
-
initial="hidden"
|
|
94
|
-
animate="show"
|
|
95
|
-
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"
|
|
96
|
-
>
|
|
97
|
-
{MOCK_STATS.map((stat, index) => (
|
|
98
|
-
<motion.div key={index} variants={item}>
|
|
99
|
-
<Card className={`glass border-white/10 hover:border-primary/20 transition-all duration-300 hover:shadow-lg hover:shadow-primary/5 group overflow-hidden relative`}>
|
|
100
|
-
<div className={`absolute inset-0 bg-gradient-to-br ${stat.color} opacity-0 group-hover:opacity-100 transition-opacity duration-500`} />
|
|
101
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2 relative z-10">
|
|
102
|
-
<CardTitle className="text-sm font-medium">{stat.title}</CardTitle>
|
|
103
|
-
<div className={`p-2 rounded-lg bg-background/50 ${stat.iconColor}`}>
|
|
104
|
-
<stat.icon className="w-5 h-5" />
|
|
105
|
-
</div>
|
|
106
|
-
</CardHeader>
|
|
107
|
-
<CardContent className="relative z-10">
|
|
108
|
-
<div className="text-2xl font-bold">{stat.value}</div>
|
|
109
|
-
<p className="text-xs text-muted-foreground mt-1">{stat.change}</p>
|
|
110
|
-
</CardContent>
|
|
111
|
-
</Card>
|
|
112
|
-
</motion.div>
|
|
113
|
-
))}
|
|
114
|
-
</motion.div>
|
|
115
|
-
|
|
116
|
-
{/* Main Content Grid */}
|
|
117
|
-
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
118
|
-
{/* Recent Tasks */}
|
|
119
|
-
<motion.div
|
|
120
|
-
initial={{ opacity: 0, x: -20 }}
|
|
121
|
-
animate={{ opacity: 1, x: 0 }}
|
|
122
|
-
transition={{ delay: 0.4 }}
|
|
123
|
-
className="lg:col-span-2"
|
|
124
|
-
>
|
|
125
|
-
<Card className="glass border-white/10 h-full">
|
|
126
|
-
<CardHeader>
|
|
127
|
-
<CardTitle className="flex items-center gap-2">
|
|
128
|
-
<ClipboardList className="w-5 h-5 text-primary" />
|
|
129
|
-
Recent Tasks
|
|
130
|
-
</CardTitle>
|
|
131
|
-
</CardHeader>
|
|
132
|
-
<CardContent>
|
|
133
|
-
<div className="space-y-4">
|
|
134
|
-
{MOCK_TODOS.map((todo) => (
|
|
135
|
-
<div key={todo.id} className="flex items-center justify-between p-4 rounded-xl bg-secondary/30 hover:bg-secondary/50 transition-colors group cursor-pointer border border-transparent hover:border-primary/10">
|
|
136
|
-
<div className="flex items-center gap-4">
|
|
137
|
-
<div className={`h-10 w-10 rounded-full flex items-center justify-center ${todo.status === 'completed' ? 'bg-green-500/10 text-green-500' :
|
|
138
|
-
todo.status === 'in-progress' ? 'bg-blue-500/10 text-blue-500' :
|
|
139
|
-
'bg-orange-500/10 text-orange-500'
|
|
140
|
-
}`}>
|
|
141
|
-
{todo.status === 'completed' ? <CheckCircle2 className="w-5 h-5" /> :
|
|
142
|
-
todo.status === 'in-progress' ? <Activity className="w-5 h-5" /> :
|
|
143
|
-
<Hourglass className="w-5 h-5" />}
|
|
144
|
-
</div>
|
|
145
|
-
<div>
|
|
146
|
-
<p className="font-medium group-hover:text-primary transition-colors">{todo.title}</p>
|
|
147
|
-
<p className="text-xs text-muted-foreground flex items-center gap-1">
|
|
148
|
-
<Clock className="w-3 h-3" /> {todo.date}
|
|
149
|
-
</p>
|
|
150
|
-
</div>
|
|
151
|
-
</div>
|
|
152
|
-
<span className={`text-xs px-2 py-1 rounded-full capitalize ${todo.status === 'completed' ? 'bg-green-500/10 text-green-500' :
|
|
153
|
-
todo.status === 'in-progress' ? 'bg-blue-500/10 text-blue-500' :
|
|
154
|
-
'bg-orange-500/10 text-orange-500'
|
|
155
|
-
}`}>
|
|
156
|
-
{todo.status.replace('-', ' ')}
|
|
157
|
-
</span>
|
|
158
|
-
</div>
|
|
159
|
-
))}
|
|
160
|
-
</div>
|
|
161
|
-
</CardContent>
|
|
162
|
-
</Card>
|
|
163
|
-
</motion.div>
|
|
164
|
-
|
|
165
|
-
{/* Recent Activity */}
|
|
166
|
-
<motion.div
|
|
167
|
-
initial={{ opacity: 0, x: 20 }}
|
|
168
|
-
animate={{ opacity: 1, x: 0 }}
|
|
169
|
-
transition={{ delay: 0.5 }}
|
|
170
|
-
>
|
|
171
|
-
<Card className="glass border-white/10 h-full">
|
|
172
|
-
<CardHeader>
|
|
173
|
-
<CardTitle className="flex items-center gap-2">
|
|
174
|
-
<Bell className="w-5 h-5 text-primary" />
|
|
175
|
-
Recent Activity
|
|
176
|
-
</CardTitle>
|
|
177
|
-
</CardHeader>
|
|
178
|
-
<CardContent>
|
|
179
|
-
<div className="space-y-6">
|
|
180
|
-
{MOCK_ACTIVITIES.map((activity, index) => (
|
|
181
|
-
<div key={activity.id} className="flex gap-4 relative">
|
|
182
|
-
{index !== MOCK_ACTIVITIES.length - 1 && (
|
|
183
|
-
<div className="absolute left-[19px] top-10 bottom-[-24px] w-[2px] bg-secondary" />
|
|
184
|
-
)}
|
|
185
|
-
<div className="h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center shrink-0 text-sm font-bold text-primary">
|
|
186
|
-
{activity.user[0]}
|
|
187
|
-
</div>
|
|
188
|
-
<div>
|
|
189
|
-
<p className="text-sm">
|
|
190
|
-
<span className="font-semibold">{activity.user}</span> {activity.action}
|
|
191
|
-
</p>
|
|
192
|
-
<p className="text-xs text-muted-foreground mt-1">{activity.time}</p>
|
|
193
|
-
</div>
|
|
194
|
-
</div>
|
|
195
|
-
))}
|
|
196
|
-
</div>
|
|
197
|
-
</CardContent>
|
|
198
|
-
</Card>
|
|
199
|
-
</motion.div>
|
|
200
|
-
</div>
|
|
201
|
-
</div>
|
|
202
|
-
</div>
|
|
203
|
-
);
|
|
204
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { motion } from 'framer-motion';
|
|
4
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
5
|
+
import { Button } from '@/components/ui/button';
|
|
6
|
+
import { logout } from '@/features/auth';
|
|
7
|
+
import { toast } from 'react-hot-toast';
|
|
8
|
+
import {
|
|
9
|
+
DollarSign,
|
|
10
|
+
Users,
|
|
11
|
+
ShoppingBag,
|
|
12
|
+
Activity,
|
|
13
|
+
ClipboardList,
|
|
14
|
+
CheckCircle2,
|
|
15
|
+
Clock,
|
|
16
|
+
Hourglass,
|
|
17
|
+
Bell,
|
|
18
|
+
LogOut
|
|
19
|
+
} from 'lucide-react';
|
|
20
|
+
|
|
21
|
+
// Mock Data for Demo
|
|
22
|
+
const MOCK_STATS = [
|
|
23
|
+
{ title: 'Total Revenue', value: '$45,231.89', change: '+20.1% from last month', icon: DollarSign, color: 'from-green-500/20 to-emerald-500/20', iconColor: 'text-green-500' },
|
|
24
|
+
{ title: 'Subscriptions', value: '+2350', change: '+180.1% from last month', icon: Users, color: 'from-blue-500/20 to-indigo-500/20', iconColor: 'text-blue-500' },
|
|
25
|
+
{ title: 'Sales', value: '+12,234', change: '+19% from last month', icon: ShoppingBag, color: 'from-orange-500/20 to-red-500/20', iconColor: 'text-orange-500' },
|
|
26
|
+
{ title: 'Active Now', value: '+573', change: '+201 since last hour', icon: Activity, color: 'from-purple-500/20 to-pink-500/20', iconColor: 'text-purple-500' },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const MOCK_TODOS = [
|
|
30
|
+
{ id: 1, title: 'Review project proposal', status: 'completed', date: 'Today, 10:00 AM' },
|
|
31
|
+
{ id: 2, title: 'Team meeting with design team', status: 'pending', date: 'Today, 2:00 PM' },
|
|
32
|
+
{ id: 3, title: 'Update documentation', status: 'in-progress', date: 'Tomorrow, 11:00 AM' },
|
|
33
|
+
{ id: 4, title: 'Deploy to production', status: 'pending', date: 'Wed, 4:00 PM' },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const MOCK_ACTIVITIES = [
|
|
37
|
+
{ id: 1, user: 'Alice Smith', action: 'created a new project', time: '2 min ago' },
|
|
38
|
+
{ id: 2, user: 'Bob Johnson', action: 'commented on task #123', time: '15 min ago' },
|
|
39
|
+
{ id: 3, user: 'Charlie Brown', action: 'completed onboarding', time: '1 hour ago' },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
export function DashboardView() {
|
|
43
|
+
const handleLogout = async () => {
|
|
44
|
+
await logout();
|
|
45
|
+
toast.success('Logged out successfully');
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const container = {
|
|
49
|
+
hidden: { opacity: 0 },
|
|
50
|
+
show: {
|
|
51
|
+
opacity: 1,
|
|
52
|
+
transition: {
|
|
53
|
+
staggerChildren: 0.1
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const item = {
|
|
59
|
+
hidden: { y: 20, opacity: 0 },
|
|
60
|
+
show: { y: 0, opacity: 1 }
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className="min-h-screen bg-background p-8 relative overflow-hidden">
|
|
65
|
+
{/* Animated Background */}
|
|
66
|
+
<div className="fixed inset-0 overflow-hidden pointer-events-none -z-10">
|
|
67
|
+
<div className="absolute -top-[40%] -right-[30%] w-[70%] h-[70%] rounded-full bg-primary/10 blur-[120px] animate-float" />
|
|
68
|
+
<div className="absolute top-[60%] -left-[20%] w-[50%] h-[50%] rounded-full bg-indigo-500/10 blur-[100px] animate-float" style={{ animationDelay: '3s' }} />
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div className="max-w-7xl mx-auto space-y-8">
|
|
72
|
+
{/* Header */}
|
|
73
|
+
<motion.div
|
|
74
|
+
initial={{ opacity: 0, y: -20 }}
|
|
75
|
+
animate={{ opacity: 1, y: 0 }}
|
|
76
|
+
className="flex items-center justify-between"
|
|
77
|
+
>
|
|
78
|
+
<div>
|
|
79
|
+
<h1 className="text-4xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-indigo-600 mb-2">
|
|
80
|
+
Dashboard Overview
|
|
81
|
+
</h1>
|
|
82
|
+
<p className="text-muted-foreground">Welcome back, Ziad! Here's what's happening today.</p>
|
|
83
|
+
</div>
|
|
84
|
+
<Button onClick={handleLogout} variant="outline" className="border-primary/20 hover:bg-primary/10 hover:text-primary transition-colors gap-2">
|
|
85
|
+
<LogOut className="w-4 h-4" />
|
|
86
|
+
Sign out
|
|
87
|
+
</Button>
|
|
88
|
+
</motion.div>
|
|
89
|
+
|
|
90
|
+
{/* Stats Grid */}
|
|
91
|
+
<motion.div
|
|
92
|
+
variants={container}
|
|
93
|
+
initial="hidden"
|
|
94
|
+
animate="show"
|
|
95
|
+
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"
|
|
96
|
+
>
|
|
97
|
+
{MOCK_STATS.map((stat, index) => (
|
|
98
|
+
<motion.div key={index} variants={item}>
|
|
99
|
+
<Card className={`glass border-white/10 hover:border-primary/20 transition-all duration-300 hover:shadow-lg hover:shadow-primary/5 group overflow-hidden relative`}>
|
|
100
|
+
<div className={`absolute inset-0 bg-gradient-to-br ${stat.color} opacity-0 group-hover:opacity-100 transition-opacity duration-500`} />
|
|
101
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2 relative z-10">
|
|
102
|
+
<CardTitle className="text-sm font-medium">{stat.title}</CardTitle>
|
|
103
|
+
<div className={`p-2 rounded-lg bg-background/50 ${stat.iconColor}`}>
|
|
104
|
+
<stat.icon className="w-5 h-5" />
|
|
105
|
+
</div>
|
|
106
|
+
</CardHeader>
|
|
107
|
+
<CardContent className="relative z-10">
|
|
108
|
+
<div className="text-2xl font-bold">{stat.value}</div>
|
|
109
|
+
<p className="text-xs text-muted-foreground mt-1">{stat.change}</p>
|
|
110
|
+
</CardContent>
|
|
111
|
+
</Card>
|
|
112
|
+
</motion.div>
|
|
113
|
+
))}
|
|
114
|
+
</motion.div>
|
|
115
|
+
|
|
116
|
+
{/* Main Content Grid */}
|
|
117
|
+
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
118
|
+
{/* Recent Tasks */}
|
|
119
|
+
<motion.div
|
|
120
|
+
initial={{ opacity: 0, x: -20 }}
|
|
121
|
+
animate={{ opacity: 1, x: 0 }}
|
|
122
|
+
transition={{ delay: 0.4 }}
|
|
123
|
+
className="lg:col-span-2"
|
|
124
|
+
>
|
|
125
|
+
<Card className="glass border-white/10 h-full">
|
|
126
|
+
<CardHeader>
|
|
127
|
+
<CardTitle className="flex items-center gap-2">
|
|
128
|
+
<ClipboardList className="w-5 h-5 text-primary" />
|
|
129
|
+
Recent Tasks
|
|
130
|
+
</CardTitle>
|
|
131
|
+
</CardHeader>
|
|
132
|
+
<CardContent>
|
|
133
|
+
<div className="space-y-4">
|
|
134
|
+
{MOCK_TODOS.map((todo) => (
|
|
135
|
+
<div key={todo.id} className="flex items-center justify-between p-4 rounded-xl bg-secondary/30 hover:bg-secondary/50 transition-colors group cursor-pointer border border-transparent hover:border-primary/10">
|
|
136
|
+
<div className="flex items-center gap-4">
|
|
137
|
+
<div className={`h-10 w-10 rounded-full flex items-center justify-center ${todo.status === 'completed' ? 'bg-green-500/10 text-green-500' :
|
|
138
|
+
todo.status === 'in-progress' ? 'bg-blue-500/10 text-blue-500' :
|
|
139
|
+
'bg-orange-500/10 text-orange-500'
|
|
140
|
+
}`}>
|
|
141
|
+
{todo.status === 'completed' ? <CheckCircle2 className="w-5 h-5" /> :
|
|
142
|
+
todo.status === 'in-progress' ? <Activity className="w-5 h-5" /> :
|
|
143
|
+
<Hourglass className="w-5 h-5" />}
|
|
144
|
+
</div>
|
|
145
|
+
<div>
|
|
146
|
+
<p className="font-medium group-hover:text-primary transition-colors">{todo.title}</p>
|
|
147
|
+
<p className="text-xs text-muted-foreground flex items-center gap-1">
|
|
148
|
+
<Clock className="w-3 h-3" /> {todo.date}
|
|
149
|
+
</p>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
<span className={`text-xs px-2 py-1 rounded-full capitalize ${todo.status === 'completed' ? 'bg-green-500/10 text-green-500' :
|
|
153
|
+
todo.status === 'in-progress' ? 'bg-blue-500/10 text-blue-500' :
|
|
154
|
+
'bg-orange-500/10 text-orange-500'
|
|
155
|
+
}`}>
|
|
156
|
+
{todo.status.replace('-', ' ')}
|
|
157
|
+
</span>
|
|
158
|
+
</div>
|
|
159
|
+
))}
|
|
160
|
+
</div>
|
|
161
|
+
</CardContent>
|
|
162
|
+
</Card>
|
|
163
|
+
</motion.div>
|
|
164
|
+
|
|
165
|
+
{/* Recent Activity */}
|
|
166
|
+
<motion.div
|
|
167
|
+
initial={{ opacity: 0, x: 20 }}
|
|
168
|
+
animate={{ opacity: 1, x: 0 }}
|
|
169
|
+
transition={{ delay: 0.5 }}
|
|
170
|
+
>
|
|
171
|
+
<Card className="glass border-white/10 h-full">
|
|
172
|
+
<CardHeader>
|
|
173
|
+
<CardTitle className="flex items-center gap-2">
|
|
174
|
+
<Bell className="w-5 h-5 text-primary" />
|
|
175
|
+
Recent Activity
|
|
176
|
+
</CardTitle>
|
|
177
|
+
</CardHeader>
|
|
178
|
+
<CardContent>
|
|
179
|
+
<div className="space-y-6">
|
|
180
|
+
{MOCK_ACTIVITIES.map((activity, index) => (
|
|
181
|
+
<div key={activity.id} className="flex gap-4 relative">
|
|
182
|
+
{index !== MOCK_ACTIVITIES.length - 1 && (
|
|
183
|
+
<div className="absolute left-[19px] top-10 bottom-[-24px] w-[2px] bg-secondary" />
|
|
184
|
+
)}
|
|
185
|
+
<div className="h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center shrink-0 text-sm font-bold text-primary">
|
|
186
|
+
{activity.user[0]}
|
|
187
|
+
</div>
|
|
188
|
+
<div>
|
|
189
|
+
<p className="text-sm">
|
|
190
|
+
<span className="font-semibold">{activity.user}</span> {activity.action}
|
|
191
|
+
</p>
|
|
192
|
+
<p className="text-xs text-muted-foreground mt-1">{activity.time}</p>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
))}
|
|
196
|
+
</div>
|
|
197
|
+
</CardContent>
|
|
198
|
+
</Card>
|
|
199
|
+
</motion.div>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { getData } from '@/lib/api-client';
|
|
2
|
-
|
|
3
|
-
export const getTodos = async () => {
|
|
4
|
-
return await getData('/todos');
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export const getUser = async () => {
|
|
8
|
-
return await getData('/auth/me');
|
|
9
|
-
};
|
|
1
|
+
import { getData } from '@/lib/api-client';
|
|
2
|
+
|
|
3
|
+
export const getTodos = async () => {
|
|
4
|
+
return await getData('/todos');
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const getUser = async () => {
|
|
8
|
+
return await getData('/auth/me');
|
|
9
|
+
};
|