You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
6.5 KiB
TypeScript
112 lines
6.5 KiB
TypeScript
import { auth } from "@/auth";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { OvertimeForm } from "./overtime-form";
|
|
import {
|
|
Clock,
|
|
Calendar,
|
|
CheckCircle2,
|
|
AlertCircle,
|
|
Zap
|
|
} from "lucide-react";
|
|
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card";
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
export default async function OvertimePage() {
|
|
const session = await auth();
|
|
const userId = (session?.user as any)?.id;
|
|
|
|
const logs = await prisma.overtime.findMany({
|
|
where: { userId },
|
|
orderBy: { date: 'desc' },
|
|
take: 10
|
|
});
|
|
|
|
const totalYTD = logs.reduce((acc, curr) => acc + curr.hours, 0);
|
|
|
|
return (
|
|
<div className="space-y-8 animate-in fade-in slide-in-from-bottom-2 duration-500">
|
|
<div>
|
|
<h2 className="text-3xl font-bold tracking-tight">Overtime Management</h2>
|
|
<p className="text-neutral-500 mt-1">Log your extra hours and track approval status.</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
<div className="lg:col-span-2 space-y-8">
|
|
<OvertimeForm />
|
|
|
|
<Card className="border-none shadow-2xl shadow-black/5 bg-white dark:bg-neutral-900 rounded-3xl overflow-hidden">
|
|
<div className="p-8 border-b border-neutral-100 dark:border-neutral-800 flex justify-between items-center">
|
|
<h3 className="text-xl font-bold">Recent Logs</h3>
|
|
<Button variant="ghost" className="text-indigo-600 font-semibold hover:bg-indigo-50 rounded-xl px-4 py-2 h-auto text-sm">
|
|
View History
|
|
</Button>
|
|
</div>
|
|
<div className="divide-y divide-neutral-100 dark:divide-neutral-800">
|
|
{logs.map((log, i) => (
|
|
<div key={log.id} className="p-8 hover:bg-neutral-50/50 transition-colors flex items-center justify-between group">
|
|
<div className="flex items-center gap-6">
|
|
<div className="hidden sm:flex flex-col items-center">
|
|
<span className="text-xs font-bold text-neutral-400 uppercase tracking-tighter">Day</span>
|
|
<span className="text-2xl font-black text-neutral-300 group-hover:text-indigo-200 transition-colors">
|
|
{new Date(log.date).getDate().toString().padStart(2, '0')}
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<p className="font-bold text-neutral-900 dark:text-neutral-100">{log.reason}</p>
|
|
<div className="flex items-center gap-3 mt-1 text-sm text-neutral-500">
|
|
<span className="flex items-center gap-1">
|
|
<Calendar className="w-3 h-3" />
|
|
{new Date(log.date).toLocaleDateString()}
|
|
</span>
|
|
<span className="flex items-center gap-1">
|
|
<Clock className="w-3 h-3" />
|
|
{log.hours} hours
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-col items-end gap-2">
|
|
<span className={`text-[10px] font-bold uppercase px-2 py-1 rounded-full ${log.status === 'PAID' ? 'bg-emerald-100 text-emerald-700' :
|
|
log.status === 'APPROVED' ? 'bg-indigo-100 text-indigo-700' : 'bg-amber-100 text-amber-700'
|
|
}`}>
|
|
{log.status}
|
|
</span>
|
|
<p className="text-xs font-medium text-neutral-400">Payroll: Current Cycle</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
|
|
<div className="space-y-8">
|
|
<Card className="border-none shadow-2xl shadow-indigo-500/10 bg-gradient-to-br from-indigo-600 to-violet-700 rounded-3xl p-8 text-white relative overflow-hidden">
|
|
<div className="relative z-10">
|
|
<div className="w-12 h-12 bg-white/20 rounded-2xl flex items-center justify-center mb-6 backdrop-blur-md">
|
|
<Clock className="w-6 h-6 text-white" />
|
|
</div>
|
|
<h3 className="text-xl font-bold mb-2">Total Overtime (YTD)</h3>
|
|
<p className="text-4xl font-black mb-4">{totalYTD}h</p>
|
|
<div className="w-full bg-white/10 rounded-full h-2 mb-2">
|
|
<div className="bg-white h-full rounded-full w-[65%]" style={{ width: `${Math.min(100, (totalYTD / 60) * 100)}%` }} />
|
|
</div>
|
|
<p className="text-xs text-indigo-100">Relative to monthly capacity</p>
|
|
</div>
|
|
<div className="absolute top-[-20%] right-[-20%] w-48 h-48 bg-white/5 rounded-full blur-3xl pointer-events-none" />
|
|
</Card>
|
|
|
|
<Card className="border-none shadow-2xl shadow-black/5 bg-white dark:bg-neutral-900 rounded-3xl p-8">
|
|
<h3 className="text-lg font-bold mb-4 flex items-center gap-2">
|
|
<AlertCircle className="w-5 h-5 text-amber-500" />
|
|
Important Note
|
|
</h3>
|
|
<p className="text-sm text-neutral-500 leading-relaxed">
|
|
Overtime logs must be submitted within 48 hours of completion. All logs are subject to manager approval before being processed for payroll.
|
|
</p>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|