phosphat-report-app/app/routes/dashboard.tsx
2025-07-24 14:03:05 +03:00

183 lines
7.2 KiB
TypeScript

import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { requireAuthLevel } from "~/utils/auth.server";
import DashboardLayout from "~/components/DashboardLayout";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export const meta: MetaFunction = () => [{ title: "Dashboard - Phosphat Report" }];
export const loader = async ({ request }: LoaderFunctionArgs) => {
const user = await requireAuthLevel(request, 1);
// Get dashboard statistics
const [reportCount, equipmentCount, areaCount] = await Promise.all([
prisma.report.count(),
prisma.equipment.count(),
prisma.area.count(),
]);
// Get recent reports
const recentReports = await prisma.report.findMany({
take: 5,
orderBy: { createdDate: 'desc' },
include: {
employee: { select: { name: true } },
area: { select: { name: true } },
},
});
return json({
user,
stats: {
reportCount,
equipmentCount,
areaCount,
},
recentReports,
});
};
export default function Dashboard() {
const { user, stats, recentReports } = useLoaderData<typeof loader>();
return (
<DashboardLayout user={user}>
<div className="space-y-6">
{/* Welcome Section */}
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="px-4 py-5 sm:p-6">
<h2 className="text-2xl font-bold text-gray-900 mb-2">
Welcome back, {user.name}!
</h2>
<p className="text-gray-600">
Here's what's happening with your phosphat operations today.
</p>
</div>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-1 gap-5 sm:grid-cols-3">
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<svg className="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">
Total Reports
</dt>
<dd className="text-lg font-medium text-gray-900">
{stats.reportCount}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<svg className="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
</svg>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">
Equipment Units
</dt>
<dd className="text-lg font-medium text-gray-900">
{stats.equipmentCount}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<svg className="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">
Active Areas
</dt>
<dd className="text-lg font-medium text-gray-900">
{stats.areaCount}
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
{/* Recent Reports */}
<div className="bg-white shadow overflow-hidden sm:rounded-md">
<div className="px-4 py-5 sm:px-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">
Recent Reports
</h3>
<p className="mt-1 max-w-2xl text-sm text-gray-500">
Latest activity from your team
</p>
</div>
<ul className="divide-y divide-gray-200">
{recentReports.length > 0 ? (
recentReports.map((report) => (
<li key={report.id}>
<div className="px-4 py-4 sm:px-6">
<div className="flex items-center justify-between">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="h-8 w-8 rounded-full bg-indigo-500 flex items-center justify-center">
<span className="text-sm font-medium text-white">
{report.employee.name.charAt(0)}
</span>
</div>
</div>
<div className="ml-4">
<div className="text-sm font-medium text-gray-900">
{report.employee.name}
</div>
<div className="text-sm text-gray-500">
{report.area.name} - {report.shift} shift
</div>
</div>
</div>
<div className="text-sm text-gray-500">
{new Date(report.createdDate).toLocaleDateString('en-GB')}
</div>
</div>
</div>
</li>
))
) : (
<li>
<div className="px-4 py-4 sm:px-6 text-center text-gray-500">
No reports yet. Create your first report to get started!
</div>
</li>
)}
</ul>
</div>
</div>
</DashboardLayout>
);
}