diff --git a/frontend/PR_DESCRIPTION.md b/frontend/PR_DESCRIPTION.md new file mode 100644 index 0000000..1a50056 --- /dev/null +++ b/frontend/PR_DESCRIPTION.md @@ -0,0 +1,52 @@ +# Frontend UI Improvements - Multiple Issues + +## Overview + +This PR addresses four frontend UI/UX issues to improve user experience, accessibility, and form validation feedback. + +## Issues Resolved + +### #111: Add Success Feedback for CSV Upload + +- **Implementation**: Added toast notification with success summary after CSV upload +- **Details**: Shows count of valid rows and any rows with errors +- **Files**: `CSVUploader.tsx` + +### #105: Standardize Modal Close Behaviors + +- **Implementation**: Ensured all modals support ESC key and backdrop click to close +- **Details**: + - `FeeEstimationConfirmModal`: Added proper backdrop click handler + - `UpgradeConfirmModal`: Added ESC key support + - `EmployeeRemovalConfirmModal`: Already had both features +- **Files**: `FeeEstimationConfirmModal.tsx`, `UpgradeConfirmModal.tsx` + +### #106: Improve Form Validation Feedback + +- **Implementation**: Created reusable `FormField` component with validation feedback +- **Details**: + - Red border on invalid fields + - Error messages displayed below inputs + - Accessibility support (aria-invalid, aria-describedby) + - Applied to EmployeeEntry and PayrollScheduler forms +- **Files**: `FormField.tsx`, `EmployeeEntry.tsx`, `PayrollScheduler.tsx` + +### #107: Add Slide-in Animations for Dashboard Cards + +- **Implementation**: Added Framer Motion animations to PayrollAnalytics dashboard +- **Details**: Staggered slide-in animations on page load with smooth easing +- **Files**: `PayrollAnalytics.tsx` + +## Testing + +- All components pass ESLint checks +- No TypeScript errors +- Responsive design maintained +- Accessibility features preserved + +## Accessibility + +- ARIA labels and descriptions for form fields +- Keyboard navigation support (ESC key for modals) +- Color contrast compliance maintained +- Screen reader friendly error messages diff --git a/frontend/src/components/CSVUploader.tsx b/frontend/src/components/CSVUploader.tsx index 0f62614..c8656cd 100644 --- a/frontend/src/components/CSVUploader.tsx +++ b/frontend/src/components/CSVUploader.tsx @@ -1,5 +1,6 @@ import React, { useState, useRef } from 'react'; import { Upload, AlertCircle, CheckCircle } from 'lucide-react'; +import { useNotification } from '../hooks/useNotification'; export interface CSVRow { rowNumber: number; @@ -25,6 +26,7 @@ export const CSVUploader: React.FC = ({ const [parsedData, setParsedData] = useState([]); const [fileName, setFileName] = useState(null); const fileInputRef = useRef(null); + const { notifySuccess } = useNotification(); const parseCSV = (content: string): CSVRow[] => { const lines = content.trim().split('\n'); @@ -116,6 +118,19 @@ export const CSVUploader: React.FC = ({ const rows = parseCSV(content); setParsedData(rows); onDataParsed(rows); + + // Show success feedback with summary + const validCount = rows.filter((r) => r.isValid).length; + const invalidCount = rows.filter((r) => !r.isValid).length; + + if (validCount > 0) { + const summary = + invalidCount > 0 + ? `${validCount} valid row${validCount !== 1 ? 's' : ''}, ${invalidCount} with error${invalidCount !== 1 ? 's' : ''}` + : `${validCount} row${validCount !== 1 ? 's' : ''} ready to upload`; + + notifySuccess('CSV uploaded successfully', summary); + } }; reader.readAsText(file); diff --git a/frontend/src/components/FeeEstimationConfirmModal.tsx b/frontend/src/components/FeeEstimationConfirmModal.tsx index 5c6f96d..4d55723 100644 --- a/frontend/src/components/FeeEstimationConfirmModal.tsx +++ b/frontend/src/components/FeeEstimationConfirmModal.tsx @@ -264,12 +264,23 @@ export const FeeEstimationConfirmModal: React.FC onConfirm(); }, [onConfirm]); + const handleBackdropClick = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + onCancel(); + } + }; + if (!isOpen) return null; return ( <> {/* Backdrop overlay */} -