- Next.js 15.2.4 with React 19 and TypeScript - Monthly schedule generator with Excel-like formatting - Complete employee list from example.xlsx (18 employees) - Excel-style column naming (A, B, C, ..., Z, AA, AB, ...) - Counter-clockwise text rotation for data values - Weekend highlighting and shift color coding - Team selection for TKB, METRO, D8 - 7 days from previous month + full current month date range - jspreadsheet integration for Excel-like interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
157 lines
5.1 KiB
TypeScript
157 lines
5.1 KiB
TypeScript
"use client"
|
|
|
|
import * as React from "react"
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Search, Download, Eye, Calendar, Clock } from "lucide-react"
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
|
|
|
interface ScheduleHistoryProps {
|
|
teamId: string
|
|
teamName: string
|
|
}
|
|
|
|
// Sample historical data
|
|
const getHistoricalSchedules = (teamId: string) => [
|
|
{
|
|
id: "1",
|
|
name: "Week 45 - November 2024",
|
|
dateRange: "Nov 4-10, 2024",
|
|
createdBy: "John Manager",
|
|
createdAt: "2024-11-01",
|
|
status: "completed",
|
|
employees: 8,
|
|
},
|
|
{
|
|
id: "2",
|
|
name: "Week 44 - October 2024",
|
|
dateRange: "Oct 28 - Nov 3, 2024",
|
|
createdBy: "Sarah Admin",
|
|
createdAt: "2024-10-25",
|
|
status: "completed",
|
|
employees: 7,
|
|
},
|
|
{
|
|
id: "3",
|
|
name: "Week 43 - October 2024",
|
|
dateRange: "Oct 21-27, 2024",
|
|
createdBy: "John Manager",
|
|
createdAt: "2024-10-18",
|
|
status: "completed",
|
|
employees: 8,
|
|
},
|
|
{
|
|
id: "4",
|
|
name: "Holiday Schedule - Christmas",
|
|
dateRange: "Dec 23-29, 2023",
|
|
createdBy: "Admin",
|
|
createdAt: "2023-12-15",
|
|
status: "archived",
|
|
employees: 5,
|
|
},
|
|
]
|
|
|
|
export function ScheduleHistory({ teamId, teamName }: ScheduleHistoryProps) {
|
|
const [searchTerm, setSearchTerm] = React.useState("")
|
|
const historicalSchedules = getHistoricalSchedules(teamId)
|
|
|
|
const filteredSchedules = historicalSchedules.filter(
|
|
(schedule) =>
|
|
schedule.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
schedule.dateRange.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
schedule.createdBy.toLowerCase().includes(searchTerm.toLowerCase()),
|
|
)
|
|
|
|
const getStatusColor = (status: string) => {
|
|
switch (status) {
|
|
case "completed":
|
|
return "bg-green-100 text-green-800"
|
|
case "archived":
|
|
return "bg-gray-100 text-gray-800"
|
|
default:
|
|
return "bg-blue-100 text-blue-800"
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Card className="w-full">
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Clock className="size-5" />
|
|
{teamName} - Schedule History
|
|
</CardTitle>
|
|
<CardDescription>Browse and restore previous schedules for your team</CardDescription>
|
|
<div className="flex items-center gap-4 mt-4">
|
|
<div className="relative flex-1 max-w-sm">
|
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 size-4 text-gray-400" />
|
|
<Input
|
|
placeholder="Search schedules..."
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
className="pl-10"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Schedule Name</TableHead>
|
|
<TableHead>Date Range</TableHead>
|
|
<TableHead>Created By</TableHead>
|
|
<TableHead>Created Date</TableHead>
|
|
<TableHead>Employees</TableHead>
|
|
<TableHead>Status</TableHead>
|
|
<TableHead>Actions</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{filteredSchedules.map((schedule) => (
|
|
<TableRow key={schedule.id}>
|
|
<TableCell className="font-medium">{schedule.name}</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center gap-2">
|
|
<Calendar className="size-4 text-gray-400" />
|
|
{schedule.dateRange}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>{schedule.createdBy}</TableCell>
|
|
<TableCell>{new Date(schedule.createdAt).toLocaleDateString()}</TableCell>
|
|
<TableCell>{schedule.employees}</TableCell>
|
|
<TableCell>
|
|
<Badge className={getStatusColor(schedule.status)}>{schedule.status}</Badge>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center gap-2">
|
|
<Button variant="outline" size="sm">
|
|
<Eye className="size-4 mr-1" />
|
|
View
|
|
</Button>
|
|
<Button variant="outline" size="sm">
|
|
<Download className="size-4 mr-1" />
|
|
Export
|
|
</Button>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
|
|
{filteredSchedules.length === 0 && (
|
|
<div className="text-center py-8">
|
|
<Clock className="size-12 mx-auto mb-4 text-gray-400" />
|
|
<h3 className="text-lg font-medium text-gray-900 mb-2">No schedules found</h3>
|
|
<p className="text-gray-500">
|
|
{searchTerm ? "Try adjusting your search terms" : "No historical schedules available yet"}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
}
|