From 8c67dbad6ad7b33129aae002d6e37c07716e774b Mon Sep 17 00:00:00 2001
From: "gpt-engineer-app[bot]"
<159125892+gpt-engineer-app[bot]@users.noreply.github.com>
Date: Tue, 27 May 2025 10:30:31 +0000
Subject: [PATCH] Implement full-stack application
Develop ReactJS frontend with PHP backend, including login, data display, and dashboards based on the provided Figma design and specifications.
---
index.html | 9 +-
src/components/AdminDataEntryModal.tsx | 184 ++++++++++++++++++
src/components/EmployeePaymentReport.tsx | 130 +++++++++++++
src/components/OutstandingReportDashboard.tsx | 90 +++++++++
src/hooks/useEmployeeData.ts | 175 +++++++++++++++++
src/pages/Index.tsx | 87 ++++++++-
6 files changed, 666 insertions(+), 9 deletions(-)
create mode 100644 src/components/AdminDataEntryModal.tsx
create mode 100644 src/components/EmployeePaymentReport.tsx
create mode 100644 src/components/OutstandingReportDashboard.tsx
create mode 100644 src/hooks/useEmployeeData.ts
diff --git a/index.html b/index.html
index 7b09be9..526dbfb 100644
--- a/index.html
+++ b/index.html
@@ -1,14 +1,15 @@
+
- collect-track-report
-
+ Employee Collection Management System
+
-
-
+
+
diff --git a/src/components/AdminDataEntryModal.tsx b/src/components/AdminDataEntryModal.tsx
new file mode 100644
index 0000000..90d08e4
--- /dev/null
+++ b/src/components/AdminDataEntryModal.tsx
@@ -0,0 +1,184 @@
+
+import React, { useState } from 'react';
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+import { Calendar } from "@/components/ui/calendar";
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
+import { CalendarIcon } from "lucide-react";
+import { format } from "date-fns";
+import { cn } from "@/lib/utils";
+import { useEmployeeData } from "@/hooks/useEmployeeData";
+import { useToast } from "@/hooks/use-toast";
+
+interface AdminDataEntryModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ onDataUpdate: () => void;
+}
+
+export const AdminDataEntryModal = ({ isOpen, onClose, onDataUpdate }: AdminDataEntryModalProps) => {
+ const { employees, addTransaction } = useEmployeeData();
+ const { toast } = useToast();
+
+ const [selectedEmployeeId, setSelectedEmployeeId] = useState('');
+ const [collectionAmount, setCollectionAmount] = useState('');
+ const [depositAmount, setDepositAmount] = useState('');
+ const [selectedDate, setSelectedDate] = useState(new Date());
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (!selectedEmployeeId) {
+ toast({
+ title: "Error",
+ description: "Please select an employee",
+ variant: "destructive"
+ });
+ return;
+ }
+
+ const collection = parseFloat(collectionAmount) || 0;
+ const deposit = parseFloat(depositAmount) || 0;
+
+ if (collection === 0 && deposit === 0) {
+ toast({
+ title: "Error",
+ description: "Please enter at least one amount (collection or deposit)",
+ variant: "destructive"
+ });
+ return;
+ }
+
+ addTransaction(selectedEmployeeId, {
+ date: format(selectedDate, 'yyyy-MM-dd'),
+ collection,
+ deposit
+ });
+
+ toast({
+ title: "Success",
+ description: "Transaction added successfully",
+ });
+
+ // Reset form
+ setSelectedEmployeeId('');
+ setCollectionAmount('');
+ setDepositAmount('');
+ setSelectedDate(new Date());
+
+ onDataUpdate();
+ };
+
+ const handleClose = () => {
+ setSelectedEmployeeId('');
+ setCollectionAmount('');
+ setDepositAmount('');
+ setSelectedDate(new Date());
+ onClose();
+ };
+
+ return (
+
+
+
+ Insert Employee Data
+
+
+
+
+
+ );
+};
diff --git a/src/components/EmployeePaymentReport.tsx b/src/components/EmployeePaymentReport.tsx
new file mode 100644
index 0000000..f9566fb
--- /dev/null
+++ b/src/components/EmployeePaymentReport.tsx
@@ -0,0 +1,130 @@
+
+import React, { useState } from 'react';
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+import { Badge } from "@/components/ui/badge";
+import { useEmployeeData } from "@/hooks/useEmployeeData";
+
+export const EmployeePaymentReport = () => {
+ const { employees, getEmployeeTransactions } = useEmployeeData();
+ const [selectedEmployeeId, setSelectedEmployeeId] = useState('all');
+
+ const formatCurrency = (amount: number) => {
+ return new Intl.NumberFormat('en-IN', {
+ style: 'currency',
+ currency: 'INR'
+ }).format(amount);
+ };
+
+ const formatDate = (date: string) => {
+ return new Date(date).toLocaleDateString('en-IN');
+ };
+
+ const getTransactionsToShow = () => {
+ if (selectedEmployeeId === 'all') {
+ return employees.flatMap(employee =>
+ getEmployeeTransactions(employee.id).map(transaction => ({
+ ...transaction,
+ employeeName: employee.name,
+ employeeId: employee.id
+ }))
+ ).sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
+ } else {
+ const employee = employees.find(emp => emp.id === selectedEmployeeId);
+ return getEmployeeTransactions(selectedEmployeeId).map(transaction => ({
+ ...transaction,
+ employeeName: employee?.name || '',
+ employeeId: selectedEmployeeId
+ }));
+ }
+ };
+
+ const transactions = getTransactionsToShow();
+
+ return (
+
+
+
Filter by Employee
+
+
+
+
+
+ All Employees
+ {employees.map(employee => (
+
+ {employee.name} (ID: {employee.id})
+
+ ))}
+
+
+
+
+
+
+
+
+ Employee ID
+ Employee Name
+ Date
+ MM Collection
+ Deposit Amount
+ Difference
+ Running Balance
+ Status
+
+
+
+ {transactions.map((transaction, index) => (
+
+ {transaction.employeeId}
+
+
+
+
+ {transaction.employeeName.charAt(0)}
+
+
+
{transaction.employeeName}
+
+
+ {formatDate(transaction.date)}
+
+ {formatCurrency(transaction.collection)}
+
+
+ {formatCurrency(transaction.deposit)}
+
+
+ = 0 ? 'text-green-600' : 'text-red-600'}`}>
+ {formatCurrency(transaction.difference)}
+
+
+
+ = 0 ? 'text-green-600' : 'text-red-600'}`}>
+ {formatCurrency(Math.abs(transaction.runningBalance))}
+
+
+
+ = 0 ? "default" : "destructive"}
+ className={transaction.difference >= 0 ? "bg-green-100 text-green-800 hover:bg-green-200" : "bg-red-100 text-red-800 hover:bg-red-200"}
+ >
+ {transaction.difference >= 0 ? 'Balanced' : 'Deficit'}
+
+
+
+ ))}
+
+
+
+
+ {transactions.length === 0 && (
+
+
No transaction data available
+
Use the "Insert Employee Data" button to add records
+
+ )}
+
+ );
+};
diff --git a/src/components/OutstandingReportDashboard.tsx b/src/components/OutstandingReportDashboard.tsx
new file mode 100644
index 0000000..70edd81
--- /dev/null
+++ b/src/components/OutstandingReportDashboard.tsx
@@ -0,0 +1,90 @@
+
+import React from 'react';
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
+import { Badge } from "@/components/ui/badge";
+import { useEmployeeData } from "@/hooks/useEmployeeData";
+
+export const OutstandingReportDashboard = () => {
+ const { employees, getEmployeeSummary } = useEmployeeData();
+
+ const employeeSummaries = employees.map(employee => {
+ const summary = getEmployeeSummary(employee.id);
+ return {
+ ...employee,
+ ...summary
+ };
+ });
+
+ const formatCurrency = (amount: number) => {
+ return new Intl.NumberFormat('en-IN', {
+ style: 'currency',
+ currency: 'INR'
+ }).format(amount);
+ };
+
+ const formatDate = (date: string) => {
+ return new Date(date).toLocaleDateString('en-IN');
+ };
+
+ return (
+
+
+
+
+
+ Employee ID
+ Employee Name
+ Net Collection Till Date
+ Most Recent Transaction
+ Outstanding Amount
+ Status
+
+
+
+ {employeeSummaries.map((employee) => (
+
+ {employee.id}
+
+
+
+
+ {employee.name.charAt(0)}
+
+
+
{employee.name}
+
+
+
+ {formatCurrency(employee.totalCollection)}
+
+
+ {employee.lastTransactionDate ? formatDate(employee.lastTransactionDate) : 'No transactions'}
+
+
+ 0 ? 'text-red-600' : 'text-green-600'}`}>
+ {formatCurrency(Math.abs(employee.outstandingAmount))}
+
+
+
+ 0 ? "destructive" : "default"}
+ className={employee.outstandingAmount > 0 ? "bg-red-100 text-red-800 hover:bg-red-200" : "bg-green-100 text-green-800 hover:bg-green-200"}
+ >
+ {employee.outstandingAmount > 0 ? 'Pending' : 'Clear'}
+
+
+
+ ))}
+
+
+
+
+ {employeeSummaries.length === 0 && (
+
+
No employee data available
+
Use the "Insert Employee Data" button to add records
+
+ )}
+
+ );
+};
diff --git a/src/hooks/useEmployeeData.ts b/src/hooks/useEmployeeData.ts
new file mode 100644
index 0000000..3710665
--- /dev/null
+++ b/src/hooks/useEmployeeData.ts
@@ -0,0 +1,175 @@
+
+import { useState, useEffect } from 'react';
+
+export interface Employee {
+ id: string;
+ name: string;
+ email: string;
+ department: string;
+}
+
+export interface Transaction {
+ date: string;
+ collection: number;
+ deposit: number;
+}
+
+export interface ProcessedTransaction extends Transaction {
+ difference: number;
+ runningBalance: number;
+}
+
+export interface EmployeeSummary {
+ totalCollection: number;
+ totalDeposit: number;
+ outstandingAmount: number;
+ lastTransactionDate: string | null;
+}
+
+const STORAGE_KEY = 'employeeCollectionData';
+
+// Sample employee data
+const initialEmployees: Employee[] = [
+ {
+ id: 'EMP001',
+ name: 'Mayank Sharma',
+ email: 'mayank.sharma@company.com',
+ department: 'Collections'
+ },
+ {
+ id: 'EMP002',
+ name: 'Priya Patel',
+ email: 'priya.patel@company.com',
+ department: 'Collections'
+ },
+ {
+ id: 'EMP003',
+ name: 'Rajesh Kumar',
+ email: 'rajesh.kumar@company.com',
+ department: 'Collections'
+ },
+ {
+ id: 'EMP004',
+ name: 'Anjali Singh',
+ email: 'anjali.singh@company.com',
+ department: 'Collections'
+ },
+ {
+ id: 'EMP005',
+ name: 'Vikram Gupta',
+ email: 'vikram.gupta@company.com',
+ department: 'Collections'
+ }
+];
+
+// Sample transaction data for demonstration
+const initialTransactions: Record = {
+ 'EMP001': [
+ { date: '2025-03-26', collection: 10000, deposit: 0 },
+ { date: '2025-03-27', collection: 20000, deposit: 0 },
+ { date: '2025-03-28', collection: 0, deposit: 5000 },
+ { date: '2025-03-29', collection: 0, deposit: 7000 },
+ { date: '2025-03-30', collection: 0, deposit: 8000 },
+ { date: '2025-03-31', collection: 0, deposit: 15000 }
+ ],
+ 'EMP002': [
+ { date: '2025-03-25', collection: 15000, deposit: 0 },
+ { date: '2025-03-26', collection: 12000, deposit: 15000 },
+ { date: '2025-03-27', collection: 0, deposit: 12000 }
+ ],
+ 'EMP003': [
+ { date: '2025-03-24', collection: 8000, deposit: 0 },
+ { date: '2025-03-25', collection: 0, deposit: 8000 }
+ ]
+};
+
+export const useEmployeeData = () => {
+ const [employees] = useState(initialEmployees);
+ const [transactions, setTransactions] = useState>({});
+
+ // Load data from localStorage on mount
+ useEffect(() => {
+ const savedData = localStorage.getItem(STORAGE_KEY);
+ if (savedData) {
+ try {
+ const parsed = JSON.parse(savedData);
+ setTransactions(parsed);
+ } catch (error) {
+ console.error('Error loading saved data:', error);
+ setTransactions(initialTransactions);
+ }
+ } else {
+ setTransactions(initialTransactions);
+ }
+ }, []);
+
+ // Save data to localStorage whenever transactions change
+ useEffect(() => {
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(transactions));
+ }, [transactions]);
+
+ const addTransaction = (employeeId: string, transaction: Omit) => {
+ setTransactions(prev => ({
+ ...prev,
+ [employeeId]: [...(prev[employeeId] || []), transaction].sort((a, b) =>
+ new Date(a.date).getTime() - new Date(b.date).getTime()
+ )
+ }));
+ };
+
+ const processTransactions = (employeeTransactions: Transaction[]): ProcessedTransaction[] => {
+ let runningBalance = 0;
+
+ return employeeTransactions.map(transaction => {
+ const difference = transaction.deposit - transaction.collection;
+ runningBalance += difference;
+
+ return {
+ ...transaction,
+ difference,
+ runningBalance
+ };
+ });
+ };
+
+ const getEmployeeTransactions = (employeeId: string): ProcessedTransaction[] => {
+ const employeeTransactions = transactions[employeeId] || [];
+ return processTransactions(employeeTransactions);
+ };
+
+ const getEmployeeSummary = (employeeId: string): EmployeeSummary => {
+ const employeeTransactions = transactions[employeeId] || [];
+
+ if (employeeTransactions.length === 0) {
+ return {
+ totalCollection: 0,
+ totalDeposit: 0,
+ outstandingAmount: 0,
+ lastTransactionDate: null
+ };
+ }
+
+ const totalCollection = employeeTransactions.reduce((sum, t) => sum + t.collection, 0);
+ const totalDeposit = employeeTransactions.reduce((sum, t) => sum + t.deposit, 0);
+ const outstandingAmount = totalCollection - totalDeposit;
+
+ // Find the most recent transaction date
+ const lastTransactionDate = employeeTransactions
+ .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())[0]?.date || null;
+
+ return {
+ totalCollection,
+ totalDeposit,
+ outstandingAmount,
+ lastTransactionDate
+ };
+ };
+
+ return {
+ employees,
+ transactions,
+ addTransaction,
+ getEmployeeTransactions,
+ getEmployeeSummary
+ };
+};
diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx
index 52ea22c..0b16b97 100644
--- a/src/pages/Index.tsx
+++ b/src/pages/Index.tsx
@@ -1,11 +1,88 @@
-// Update this page (the content is just a fallback if you fail to update the page)
+
+import React, { useState } from 'react';
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { OutstandingReportDashboard } from "@/components/OutstandingReportDashboard";
+import { EmployeePaymentReport } from "@/components/EmployeePaymentReport";
+import { AdminDataEntryModal } from "@/components/AdminDataEntryModal";
+import { Plus } from "lucide-react";
const Index = () => {
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [refreshTrigger, setRefreshTrigger] = useState(0);
+
+ const handleDataUpdate = () => {
+ setRefreshTrigger(prev => prev + 1);
+ setIsModalOpen(false);
+ };
+
return (
-
-
-
Welcome to Your Blank App
-
Start building your amazing project here!
+
+
+
+
+ Employee Collection Management
+
+
+ Track and manage employee collections and deposits
+
+
+
+
+
setIsModalOpen(true)}
+ className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg shadow-lg hover:shadow-xl transition-all duration-200 flex items-center gap-2"
+ >
+
+ Insert Employee Data
+
+
+
+
+
+
+ Outstanding Report Dashboard
+
+
+ Employee Payment Report
+
+
+
+
+
+
+ Outstanding Report Dashboard
+
+
+
+
+
+
+
+
+
+
+ Employee Payment Report Dashboard
+
+
+
+
+
+
+
+
+
setIsModalOpen(false)}
+ onDataUpdate={handleDataUpdate}
+ />
);