|
@@ -3,8 +3,9 @@
|
|
|
import { useState } from 'react';
|
|
import { useState } from 'react';
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
|
import { Button } from '@/components/ui/button';
|
|
import { Button } from '@/components/ui/button';
|
|
|
-import { Upload, FileText, Database, BarChart3, CheckCircle } from 'lucide-react';
|
|
|
|
|
|
|
+import { Upload, FileText, Database, BarChart3, CheckCircle, Loader2 } from 'lucide-react';
|
|
|
import { UploadForm } from '@/app/components/uploadForm';
|
|
import { UploadForm } from '@/app/components/uploadForm';
|
|
|
|
|
+import { createCintasImportRecord } from '@/app/actions/cintas-workflow';
|
|
|
|
|
|
|
|
interface FileData {
|
|
interface FileData {
|
|
|
id: string;
|
|
id: string;
|
|
@@ -15,14 +16,50 @@ interface FileData {
|
|
|
updatedAt: string;
|
|
updatedAt: string;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+interface CintasSummary {
|
|
|
|
|
+ id: number;
|
|
|
|
|
+ week: string;
|
|
|
|
|
+ trrTotal: number;
|
|
|
|
|
+ fourWkAverages: number;
|
|
|
|
|
+ trrPlus4Wk: number;
|
|
|
|
|
+ powerAdds: number;
|
|
|
|
|
+ weekId: number;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export default function CintasCalendarSummaryPage() {
|
|
export default function CintasCalendarSummaryPage() {
|
|
|
const [currentStep, setCurrentStep] = useState(1);
|
|
const [currentStep, setCurrentStep] = useState(1);
|
|
|
const [uploadedFile, setUploadedFile] = useState<FileData | null>(null);
|
|
const [uploadedFile, setUploadedFile] = useState<FileData | null>(null);
|
|
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
|
|
|
+ const [importRecord, setImportRecord] = useState<any>(null);
|
|
|
|
|
+ const [summaryData, setSummaryData] = useState<CintasSummary[]>([]);
|
|
|
|
|
+ const [error, setError] = useState<string | null>(null);
|
|
|
|
|
|
|
|
const handleFileUploaded = (file: FileData) => {
|
|
const handleFileUploaded = (file: FileData) => {
|
|
|
setUploadedFile(file);
|
|
setUploadedFile(file);
|
|
|
setCurrentStep(2);
|
|
setCurrentStep(2);
|
|
|
|
|
+ setError(null);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleCreateImportRecord = async () => {
|
|
|
|
|
+ if (!uploadedFile) return;
|
|
|
|
|
+
|
|
|
|
|
+ setIsProcessing(true);
|
|
|
|
|
+ setError(null);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const result = await createCintasImportRecord(uploadedFile.id, uploadedFile.filename);
|
|
|
|
|
+
|
|
|
|
|
+ if (result.success) {
|
|
|
|
|
+ setImportRecord(result.data);
|
|
|
|
|
+ setCurrentStep(3);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setError(result.error || 'Failed to create import record');
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ setError(err instanceof Error ? err.message : 'Unknown error occurred');
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setIsProcessing(false);
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const steps = [
|
|
const steps = [
|
|
@@ -31,14 +68,14 @@ export default function CintasCalendarSummaryPage() {
|
|
|
title: 'Upload Excel File',
|
|
title: 'Upload Excel File',
|
|
|
description: 'Upload the Cintas Install Calendar Excel file to blob storage',
|
|
description: 'Upload the Cintas Install Calendar Excel file to blob storage',
|
|
|
icon: Upload,
|
|
icon: Upload,
|
|
|
- status: currentStep >= 1 ? 'completed' : 'pending',
|
|
|
|
|
|
|
+ status: currentStep >= 1 ? (uploadedFile ? 'completed' : 'pending') : 'pending',
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
id: 2,
|
|
id: 2,
|
|
|
title: 'Create Import Record',
|
|
title: 'Create Import Record',
|
|
|
description: 'Create an import record with Cintas Install Calendar layout configuration',
|
|
description: 'Create an import record with Cintas Install Calendar layout configuration',
|
|
|
icon: FileText,
|
|
icon: FileText,
|
|
|
- status: currentStep >= 2 ? 'pending' : 'disabled',
|
|
|
|
|
|
|
+ status: currentStep >= 2 ? (importRecord ? 'completed' : 'pending') : 'disabled',
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
id: 3,
|
|
id: 3,
|
|
@@ -50,7 +87,7 @@ export default function CintasCalendarSummaryPage() {
|
|
|
{
|
|
{
|
|
|
id: 4,
|
|
id: 4,
|
|
|
title: 'Generate Summary',
|
|
title: 'Generate Summary',
|
|
|
- description: 'Run summary calculation and display results',
|
|
|
|
|
|
|
+ description: 'Run summary calculations and display results',
|
|
|
icon: BarChart3,
|
|
icon: BarChart3,
|
|
|
status: currentStep >= 4 ? 'pending' : 'disabled',
|
|
status: currentStep >= 4 ? 'pending' : 'disabled',
|
|
|
},
|
|
},
|
|
@@ -78,6 +115,12 @@ export default function CintasCalendarSummaryPage() {
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+ {error && (
|
|
|
|
|
+ <div className="mb-4 p-4 bg-red-50 border border-red-200 rounded-lg">
|
|
|
|
|
+ <p className="text-sm text-red-800">{error}</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+
|
|
|
{/* Workflow Steps */}
|
|
{/* Workflow Steps */}
|
|
|
<div className="mb-8">
|
|
<div className="mb-8">
|
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
@@ -91,9 +134,11 @@ export default function CintasCalendarSummaryPage() {
|
|
|
<CardHeader className="pb-3">
|
|
<CardHeader className="pb-3">
|
|
|
<div className="flex items-center space-x-2">
|
|
<div className="flex items-center space-x-2">
|
|
|
<Icon className="h-5 w-5" />
|
|
<Icon className="h-5 w-5" />
|
|
|
- <CardTitle className="text-sm font-medium">
|
|
|
|
|
- Step {step.id}: {step.title}
|
|
|
|
|
- </CardTitle>
|
|
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <CardTitle className="text-sm font-medium">
|
|
|
|
|
+ Step {step.id}: {step.title}
|
|
|
|
|
+ </CardTitle>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</CardHeader>
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
<CardContent>
|
|
@@ -149,14 +194,23 @@ export default function CintasCalendarSummaryPage() {
|
|
|
</CardHeader>
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
<CardContent>
|
|
|
<div className="space-y-4">
|
|
<div className="space-y-4">
|
|
|
- <div className="flex items-center justify-center py-8">
|
|
|
|
|
- <div className="text-center">
|
|
|
|
|
- <FileText className="h-12 w-12 text-gray-400 mx-auto mb-4" />
|
|
|
|
|
- <p className="text-muted-foreground">
|
|
|
|
|
- Import record creation functionality coming soon...
|
|
|
|
|
- </p>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
|
|
+ File: {uploadedFile?.filename}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ onClick={handleCreateImportRecord}
|
|
|
|
|
+ disabled={isProcessing}
|
|
|
|
|
+ className="w-full"
|
|
|
|
|
+ >
|
|
|
|
|
+ {isProcessing ? (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
|
|
|
+ Creating Import Record...
|
|
|
|
|
+ </>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ 'Create Import Record'
|
|
|
|
|
+ )}
|
|
|
|
|
+ </Button>
|
|
|
</div>
|
|
</div>
|
|
|
</CardContent>
|
|
</CardContent>
|
|
|
</Card>
|
|
</Card>
|
|
@@ -171,13 +225,24 @@ export default function CintasCalendarSummaryPage() {
|
|
|
</CardDescription>
|
|
</CardDescription>
|
|
|
</CardHeader>
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
<CardContent>
|
|
|
- <div className="flex items-center justify-center py-8">
|
|
|
|
|
- <div className="text-center">
|
|
|
|
|
- <Database className="h-12 w-12 text-gray-400 mx-auto mb-4" />
|
|
|
|
|
- <p className="text-muted-foreground">
|
|
|
|
|
- Data import functionality coming soon...
|
|
|
|
|
- </p>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div className="space-y-4">
|
|
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
|
|
+ Import ID: {importRecord?.id}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ onClick={() => setCurrentStep(4)}
|
|
|
|
|
+ disabled={isProcessing}
|
|
|
|
|
+ className="w-full"
|
|
|
|
|
+ >
|
|
|
|
|
+ {isProcessing ? (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
|
|
|
+ Processing Import...
|
|
|
|
|
+ </>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ 'Process Import'
|
|
|
|
|
+ )}
|
|
|
|
|
+ </Button>
|
|
|
</div>
|
|
</div>
|
|
|
</CardContent>
|
|
</CardContent>
|
|
|
</Card>
|
|
</Card>
|
|
@@ -192,13 +257,51 @@ export default function CintasCalendarSummaryPage() {
|
|
|
</CardDescription>
|
|
</CardDescription>
|
|
|
</CardHeader>
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
<CardContent>
|
|
|
- <div className="flex items-center justify-center py-8">
|
|
|
|
|
- <div className="text-center">
|
|
|
|
|
- <BarChart3 className="h-12 w-12 text-gray-400 mx-auto mb-4" />
|
|
|
|
|
- <p className="text-muted-foreground">
|
|
|
|
|
- Summary generation functionality coming soon...
|
|
|
|
|
- </p>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div className="space-y-4">
|
|
|
|
|
+ <Button
|
|
|
|
|
+ onClick={() => setCurrentStep(4)}
|
|
|
|
|
+ disabled={isProcessing}
|
|
|
|
|
+ className="w-full"
|
|
|
|
|
+ >
|
|
|
|
|
+ {isProcessing ? (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
|
|
|
+ Generating Summary...
|
|
|
|
|
+ </>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ 'Generate Summary'
|
|
|
|
|
+ )}
|
|
|
|
|
+ </Button>
|
|
|
|
|
+
|
|
|
|
|
+ {summaryData.length > 0 && (
|
|
|
|
|
+ <div className="mt-6">
|
|
|
|
|
+ <h3 className="text-lg font-semibold mb-4">Summary Results</h3>
|
|
|
|
|
+ <div className="overflow-x-auto">
|
|
|
|
|
+ <table className="min-w-full divide-y divide-gray-200">
|
|
|
|
|
+ <thead className="bg-gray-50">
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Week</th>
|
|
|
|
|
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">TRR Total</th>
|
|
|
|
|
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">4 Week Avg</th>
|
|
|
|
|
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">TRR + 4Wk</th>
|
|
|
|
|
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Power Adds</th>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </thead>
|
|
|
|
|
+ <tbody className="bg-white divide-y divide-gray-200">
|
|
|
|
|
+ {summaryData.map((item) => (
|
|
|
|
|
+ <tr key={item.id}>
|
|
|
|
|
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{item.week}</td>
|
|
|
|
|
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{item.trrTotal}</td>
|
|
|
|
|
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{item.fourWkAverages}</td>
|
|
|
|
|
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{item.trrPlus4Wk}</td>
|
|
|
|
|
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{item.powerAdds}</td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </tbody>
|
|
|
|
|
+ </table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
</div>
|
|
</div>
|
|
|
</CardContent>
|
|
</CardContent>
|
|
|
</Card>
|
|
</Card>
|
|
@@ -215,9 +318,9 @@ export default function CintasCalendarSummaryPage() {
|
|
|
</Button>
|
|
</Button>
|
|
|
<Button
|
|
<Button
|
|
|
onClick={() => setCurrentStep(Math.min(4, currentStep + 1))}
|
|
onClick={() => setCurrentStep(Math.min(4, currentStep + 1))}
|
|
|
- disabled={currentStep === 4 || !uploadedFile}
|
|
|
|
|
|
|
+ disabled={currentStep === 4 || (currentStep === 1 && !uploadedFile)}
|
|
|
>
|
|
>
|
|
|
- Next
|
|
|
|
|
|
|
+ {currentStep === 4 ? 'Complete' : 'Next'}
|
|
|
</Button>
|
|
</Button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|