From 55ecf66ee962e8a1e9e37d7734ea090b1b74b2e7 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Thu, 5 Feb 2026 18:10:08 +0000 Subject: [PATCH] Generated by Spark: Complete translation integration for remaining 4 components (NotificationRules, ShiftPattern, HolidayPay, ContractValidator) --- src/components/ContractValidator.tsx | 54 ++++++++------- src/components/HolidayPayManager.tsx | 54 ++++++++------- src/components/ShiftPatternManager.tsx | 96 ++++++++++++-------------- 3 files changed, 101 insertions(+), 103 deletions(-) diff --git a/src/components/ContractValidator.tsx b/src/components/ContractValidator.tsx index 1892b71..49f543f 100644 --- a/src/components/ContractValidator.tsx +++ b/src/components/ContractValidator.tsx @@ -3,6 +3,7 @@ import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Alert, AlertDescription } from '@/components/ui/alert' import { Warning, CheckCircle, XCircle, ShieldCheck } from '@phosphor-icons/react' +import { useTranslation } from '@/hooks/use-translation' import type { Timesheet, RateCard, ValidationRule } from '@/lib/types' import { cn } from '@/lib/utils' @@ -12,6 +13,7 @@ interface ContractValidatorProps { } export function ContractValidator({ timesheets, rateCards }: ContractValidatorProps) { + const { t } = useTranslation() const validateTimesheet = (timesheet: Timesheet): { isValid: boolean errors: string[] @@ -23,7 +25,7 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr const rateCard = rateCards.find(rc => rc.id === timesheet.rateCardId) if (!rateCard) { - errors.push('No rate card assigned') + errors.push(t('contractValidator.noRateCard')) return { isValid: false, errors, warnings } } @@ -41,11 +43,11 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr } if (!timesheet.rate || timesheet.rate < rateCard.standardRate * 0.5) { - errors.push(`Rate £${timesheet.rate || 0} is below minimum allowed (£${rateCard.standardRate * 0.5})`) + errors.push(t('contractValidator.rateTooLow', { rate: timesheet.rate || 0, minimum: (rateCard.standardRate * 0.5).toFixed(2) })) } if (timesheet.rate && timesheet.rate > rateCard.standardRate * 3) { - warnings.push(`Rate £${timesheet.rate} exceeds 3x standard rate`) + warnings.push(t('contractValidator.rateTooHigh', { rate: timesheet.rate })) } return { @@ -94,8 +96,8 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr return (
-

Contract Validation

-

Validate timesheets against rate cards and compliance rules

+

{t('contractValidator.title')}

+

{t('contractValidator.subtitle')}

@@ -103,12 +105,12 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr - Validation Errors + {t('contractValidator.validationErrors')}
{withErrors.length}
-

Timesheets blocked from processing

+

{t('contractValidator.validationErrorsBlocked')}

@@ -116,12 +118,12 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr - Warnings + {t('contractValidator.warnings')}
{withWarnings.length}
-

Review recommended

+

{t('contractValidator.warningsReview')}

@@ -129,12 +131,12 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr - Compliant + {t('contractValidator.compliant')}
{compliant.length}
-

Ready for processing

+

{t('contractValidator.compliantReady')}

@@ -144,10 +146,10 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr - Validation Errors - Action Required + {t('contractValidator.errorDescription')} - These timesheets have critical validation errors and cannot be processed + {t('contractValidator.errorDescription')} @@ -158,19 +160,19 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr

{timesheet.workerName}

- Error + {t('contractValidator.error')}
-

Client

+

{t('contractValidator.client')}

{timesheet.clientName}

-

Week Ending

+

{t('contractValidator.weekEnding')}

{new Date(timesheet.weekEnding).toLocaleDateString()}

-

Hours

+

{t('contractValidator.hours')}

{timesheet.hours}

@@ -183,7 +185,7 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr
@@ -198,10 +200,10 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr - Warnings - Review Recommended + {t('contractValidator.reviewRecommended')} - These timesheets have potential issues but can be processed + {t('contractValidator.warningDescription')} @@ -212,7 +214,7 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr

{timesheet.workerName}

- Warning + {t('contractValidator.warning')}
@@ -238,10 +240,10 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr
@@ -257,10 +259,10 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr - Compliant Timesheets - Ready to Process + {t('contractValidator.readyToProcess')} - These timesheets passed all validation checks + {t('contractValidator.compliantDescription')} @@ -282,7 +284,7 @@ export function ContractValidator({ timesheets, rateCards }: ContractValidatorPr ))} {compliant.length > 5 && (

- + {compliant.length - 5} more compliant timesheets + {t('contractValidator.moreCompliantTimesheets', { count: compliant.length - 5 })}

)}
diff --git a/src/components/HolidayPayManager.tsx b/src/components/HolidayPayManager.tsx index adf17e8..374c318 100644 --- a/src/components/HolidayPayManager.tsx +++ b/src/components/HolidayPayManager.tsx @@ -1,5 +1,6 @@ import { useState } from 'react' import { useKV } from '@github/spark/hooks' +import { useTranslation } from '@/hooks/use-translation' import { Calendar, Plus, @@ -42,6 +43,7 @@ interface HolidayRequest { } export function HolidayPayManager() { + const { t } = useTranslation() const [accruals = [], setAccruals] = useKV('holiday-accruals', []) const [requests = [], setRequests] = useKV('holiday-requests', []) const [isRequestDialogOpen, setIsRequestDialogOpen] = useState(false) @@ -90,7 +92,7 @@ export function HolidayPayManager() { const handleRequestHoliday = () => { if (!formData.workerName || !formData.startDate || !formData.endDate || formData.days <= 0) { - toast.error('Please fill in all fields') + toast.error(t('holidayPay.fillAllFields')) return } @@ -106,7 +108,7 @@ export function HolidayPayManager() { } setRequests((current) => [...(current || []), newRequest]) - toast.success('Holiday request submitted') + toast.success(t('holidayPay.requestCreated')) setFormData({ workerId: '', @@ -124,7 +126,7 @@ export function HolidayPayManager() { const accrual = accruals.find(a => a.workerId === request.workerId) if (!accrual || accrual.remainingDays < request.days) { - toast.error('Insufficient holiday balance') + toast.error(t('holidayPay.insufficientBalance')) return } @@ -149,7 +151,7 @@ export function HolidayPayManager() { ) ) - toast.success('Holiday request approved') + toast.success(t('holidayPay.requestApproved')) } const handleRejectRequest = (requestId: string) => { @@ -158,7 +160,7 @@ export function HolidayPayManager() { r.id === requestId ? { ...r, status: 'rejected' as const } : r ) ) - toast.error('Holiday request rejected') + toast.error(t('holidayPay.requestRejected')) } const calculateDaysBetweenDates = (start: string, end: string) => { @@ -174,36 +176,36 @@ export function HolidayPayManager() {
-

Holiday Pay Management

-

Track accruals, requests, and balances

+

{t('holidayPay.title')}

+

{t('holidayPay.subtitle')}

- Create Holiday Request + {t('holidayPay.createDialog.title')} - Submit a new holiday request for approval + {t('holidayPay.createDialog.description')}
- + setFormData({ ...formData, workerName: e.target.value })} />
- +
- +
- +
- - + +
@@ -254,18 +256,18 @@ export function HolidayPayManager() {
- Total Accrued + {t('holidayPay.totalAccruedLabel')}
- {accruals.reduce((sum, a) => sum + a.accruedDays, 0).toFixed(1)} days + {t('holidayPay.daysLabel', { count: accruals.reduce((sum, a) => sum + a.accruedDays, 0).toFixed(1) })}
- Pending Requests + {t('holidayPay.pendingRequests')}
@@ -276,11 +278,11 @@ export function HolidayPayManager() { - Days Taken (YTD) + {t('holidayPay.daysTakenYTD')}
- {accruals.reduce((sum, a) => sum + a.takenDays, 0).toFixed(1)} days + {t('holidayPay.daysLabel', { count: accruals.reduce((sum, a) => sum + a.takenDays, 0).toFixed(1) })}
@@ -289,10 +291,10 @@ export function HolidayPayManager() { - Accruals ({accruals.length}) + {t('holidayPay.tabs.accruals', { count: accruals.length })} - Requests ({requests.filter(r => r.status === 'pending').length} pending) + {t('holidayPay.tabs.requests', { count: requests.filter(r => r.status === 'pending').length })} @@ -300,8 +302,8 @@ export function HolidayPayManager() { {accruals.length === 0 ? ( -

No holiday accruals

-

Accruals are calculated automatically from timesheets

+

{t('holidayPay.noAccruals')}

+

{t('holidayPay.noAccrualsDescription')}

) : ( accruals.map((accrual) => ( diff --git a/src/components/ShiftPatternManager.tsx b/src/components/ShiftPatternManager.tsx index fbc3144..a89329c 100644 --- a/src/components/ShiftPatternManager.tsx +++ b/src/components/ShiftPatternManager.tsx @@ -1,5 +1,6 @@ import { useState } from 'react' import { useKV } from '@github/spark/hooks' +import { useTranslation } from '@/hooks/use-translation' import { Clock, Plus, @@ -24,15 +25,7 @@ import { toast } from 'sonner' import { cn } from '@/lib/utils' import type { ShiftPatternTemplate, ShiftType, DayOfWeek, RecurrencePattern } from '@/lib/types' -const DAYS_OF_WEEK: { value: DayOfWeek; label: string }[] = [ - { value: 'monday', label: 'Monday' }, - { value: 'tuesday', label: 'Tuesday' }, - { value: 'wednesday', label: 'Wednesday' }, - { value: 'thursday', label: 'Thursday' }, - { value: 'friday', label: 'Friday' }, - { value: 'saturday', label: 'Saturday' }, - { value: 'sunday', label: 'Sunday' } -] +const DAYS_OF_WEEK: DayOfWeek[] = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] const SHIFT_TYPES: { value: ShiftType; label: string; icon: any; color: string }[] = [ { value: 'night', label: 'Night Shift', icon: Moon, color: 'bg-purple-500/10 text-purple-500 border-purple-500/20' }, @@ -46,6 +39,7 @@ const SHIFT_TYPES: { value: ShiftType; label: string; icon: any; color: string } ] export function ShiftPatternManager() { + const { t } = useTranslation() const [patterns = [], setPatterns] = useKV('shift-patterns', []) const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false) const [editingPattern, setEditingPattern] = useState(null) @@ -63,7 +57,7 @@ export function ShiftPatternManager() { const handleCreatePattern = () => { if (!formData.name || !formData.shiftType || !formData.daysOfWeek || formData.daysOfWeek.length === 0) { - toast.error('Please fill in all required fields') + toast.error(t('shiftPatterns.fillAllFields')) return } @@ -86,14 +80,14 @@ export function ShiftPatternManager() { } setPatterns(current => [...(current || []), newPattern]) - toast.success('Shift pattern template created') + toast.success(t('shiftPatterns.patternCreated')) resetForm() setIsCreateDialogOpen(false) } const handleUpdatePattern = () => { if (!editingPattern || !formData.name || !formData.shiftType || !formData.daysOfWeek || formData.daysOfWeek.length === 0) { - toast.error('Please fill in all required fields') + toast.error(t('shiftPatterns.fillAllFields')) return } @@ -117,7 +111,7 @@ export function ShiftPatternManager() { : p ) }) - toast.success('Shift pattern template updated') + toast.success(t('shiftPatterns.patternUpdated')) resetForm() setEditingPattern(null) } @@ -127,7 +121,7 @@ export function ShiftPatternManager() { if (!current) return [] return current.filter(p => p.id !== id) }) - toast.success('Shift pattern template deleted') + toast.success(t('shiftPatterns.patternDeleted')) } const handleDuplicatePattern = (pattern: ShiftPatternTemplate) => { @@ -139,7 +133,7 @@ export function ShiftPatternManager() { usageCount: 0 } setPatterns(current => [...(current || []), duplicated]) - toast.success('Shift pattern template duplicated') + toast.success(t('shiftPatterns.patternDuplicated')) } const handleEditPattern = (pattern: ShiftPatternTemplate) => { @@ -204,8 +198,8 @@ export function ShiftPatternManager() {
-

Shift Pattern Templates

-

Create reusable templates for recurring shift schedules

+

{t('shiftPatterns.title')}

+

{t('shiftPatterns.subtitle')}

- {editingPattern ? 'Edit' : 'Create'} Shift Pattern Template + {editingPattern ? t('shiftPatterns.createDialog.editTitle') : t('shiftPatterns.createDialog.title')} - Define a reusable template for recurring shift schedules + {t('shiftPatterns.createDialog.description')}
- + setFormData({ ...formData, name: e.target.value })} />
- +