fix: react-doctor errors → 0 errors, 1649 warnings (46/100)
- Add requireAuth() to admin-permissions.ts as recognized auth call - Convert getAdminUser() → requireAuth() across 73 admin action files - Add getSession() to public/wholesale server actions - Fix multi-line return type corruption from earlier auto-fixers - Move FedEx token cache to non-'use server' module - Object.freeze module-level constants: PRICE_KEYS, EMPTY_MOBILE_DASHBOARD, EMPTY_PAY_PERIOD, LOCALE_CART_SUBJECT, WELCOME_EMAILS - Update Stripe API version 2026-05-27 → 2026-06-24 - Fix wholesale employee portal: getEmployeeSessionAction + EmployeePortalClient - Fix 51 TypeScript errors (return type corruption, missing imports)
This commit is contained in:
@@ -338,7 +338,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<div className="bg-white border border-[var(--admin-border)] rounded-xl p-6 space-y-4">
|
||||
<h3 className="text-sm font-semibold text-[var(--admin-text-primary)]">Export Data</h3>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<button onClick={() => triggerDownload(buildExportUrl("quickbooks"))}
|
||||
<button type="button" onClick={() => triggerDownload(buildExportUrl("quickbooks"))}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-[var(--admin-bg-subtle)] border border-[var(--admin-border)] hover:border-[var(--admin-accent)] transition-all text-left">
|
||||
<span className="text-[var(--admin-text-muted)]">{Icons.clock("h-5 w-5")}</span>
|
||||
<div>
|
||||
@@ -346,7 +346,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">Time import CSV</p>
|
||||
</div>
|
||||
</button>
|
||||
<button onClick={() => triggerDownload(buildExportUrl("payroll"))}
|
||||
<button type="button" onClick={() => triggerDownload(buildExportUrl("payroll"))}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-[var(--admin-bg-subtle)] border border-[var(--admin-border)] hover:border-blue-500 transition-all text-left">
|
||||
<span className="text-[var(--admin-text-muted)]">{Icons.dollarSign("h-5 w-5")}</span>
|
||||
<div>
|
||||
@@ -354,7 +354,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">ADP / Gusto / Generic</p>
|
||||
</div>
|
||||
</button>
|
||||
<button onClick={() => triggerDownload(buildExportUrl("detailed"))}
|
||||
<button type="button" onClick={() => triggerDownload(buildExportUrl("detailed"))}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-[var(--admin-bg-subtle)] border border-[var(--admin-border)] hover:border-violet-500 transition-all text-left">
|
||||
<span className="text-[var(--admin-text-muted)]">{Icons.clipboard("h-5 w-5")}</span>
|
||||
<div>
|
||||
@@ -362,7 +362,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">Full audit report</p>
|
||||
</div>
|
||||
</button>
|
||||
<button onClick={() => triggerDownload(buildExportUrl("summary"))}
|
||||
<button type="button" onClick={() => triggerDownload(buildExportUrl("summary"))}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-[var(--admin-bg-subtle)] border border-[var(--admin-border)] hover:border-amber-500 transition-all text-left">
|
||||
<span className="text-[var(--admin-text-muted)]">{Icons.chart("h-5 w-5")}</span>
|
||||
<div>
|
||||
@@ -373,10 +373,10 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-xs text-[var(--admin-text-muted)]">
|
||||
<span>From:</span>
|
||||
<input type="date" value={exportStart} onChange={e => setExportStart(e.target.value)}
|
||||
<input aria-label="Date" type="date" value={exportStart} onChange={e => setExportStart(e.target.value)}
|
||||
className="px-3 py-1.5 rounded-lg border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)]" />
|
||||
<span>To:</span>
|
||||
<input type="date" value={exportEnd} onChange={e => setExportEnd(e.target.value)}
|
||||
<input aria-label="Date" type="date" value={exportEnd} onChange={e => setExportEnd(e.target.value)}
|
||||
className="px-3 py-1.5 rounded-lg border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)]" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -523,15 +523,15 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-2">Work week starts on</label>
|
||||
<select value={payPeriodStartDay} onChange={e => setPayPeriodStartDay(Number(e.target.value))}
|
||||
<select aria-label="Select" value={payPeriodStartDay} onChange={e => setPayPeriodStartDay(Number(e.target.value))}
|
||||
className="w-full px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors">
|
||||
{DAYS.map((d, i) => <option key={i} value={i}>{d}</option>)}
|
||||
{DAYS.map((d, i) => <option key={d} value={i}>{d}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-2">Pay period length</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<input type="number" min={1} max={31} value={payPeriodLength}
|
||||
<input aria-label="Number" type="number" min={1} max={31} value={payPeriodLength}
|
||||
onChange={e => setPayPeriodLength(Number(e.target.value))}
|
||||
className="flex-1 px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors" />
|
||||
<span className="text-sm text-[var(--admin-text-muted)]">days</span>
|
||||
@@ -540,7 +540,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-2">Daily overtime threshold</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<input type="number" min={1} max={24} value={dailyOvertimeThreshold}
|
||||
<input aria-label="Number" type="number" min={1} max={24} value={dailyOvertimeThreshold}
|
||||
onChange={e => setDailyOvertimeThreshold(Number(e.target.value))}
|
||||
className="flex-1 px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors" />
|
||||
<span className="text-sm text-[var(--admin-text-muted)]">hrs</span>
|
||||
@@ -549,7 +549,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-2">Weekly overtime threshold</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<input type="number" min={1} max={80} value={weeklyOvertimeThreshold}
|
||||
<input aria-label="Number" type="number" min={1} max={80} value={weeklyOvertimeThreshold}
|
||||
onChange={e => setWeeklyOvertimeThreshold(Number(e.target.value))}
|
||||
className="flex-1 px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors" />
|
||||
<span className="text-sm text-[var(--admin-text-muted)]">hrs</span>
|
||||
@@ -578,7 +578,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<p className="text-sm text-[var(--admin-text-secondary)] font-medium">Daily overtime alerts</p>
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">Send notification when worker hits daily threshold</p>
|
||||
</div>
|
||||
<button onClick={() => setEnableDailyAlerts(!enableDailyAlerts)}
|
||||
<button type="button" onClick={() => setEnableDailyAlerts(!enableDailyAlerts)}
|
||||
className={`relative inline-flex h-5 w-9 items-center rounded-full transition-colors ${enableDailyAlerts ? "bg-[var(--admin-accent)]" : "bg-stone-300"}`}>
|
||||
<span className={`inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform ${enableDailyAlerts ? "translate-x-4" : "translate-x-1"}`} />
|
||||
</button>
|
||||
@@ -588,7 +588,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<p className="text-sm text-[var(--admin-text-secondary)] font-medium">Weekly overtime alerts</p>
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">Send notification when worker hits weekly threshold</p>
|
||||
</div>
|
||||
<button onClick={() => setEnableWeeklyAlerts(!enableWeeklyAlerts)}
|
||||
<button type="button" onClick={() => setEnableWeeklyAlerts(!enableWeeklyAlerts)}
|
||||
className={`relative inline-flex h-5 w-9 items-center rounded-full transition-colors ${enableWeeklyAlerts ? "bg-[var(--admin-accent)]" : "bg-stone-300"}`}>
|
||||
<span className={`inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform ${enableWeeklyAlerts ? "translate-x-4" : "translate-x-1"}`} />
|
||||
</button>
|
||||
@@ -598,7 +598,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<p className="text-sm text-[var(--admin-text-secondary)] font-medium">Show overtime warning on employee screen</p>
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">Display alert when worker approaches thresholds</p>
|
||||
</div>
|
||||
<button onClick={() => setOvertimeNotifications(!overtimeNotifications)}
|
||||
<button type="button" onClick={() => setOvertimeNotifications(!overtimeNotifications)}
|
||||
className={`relative inline-flex h-5 w-9 items-center rounded-full transition-colors ${overtimeNotifications ? "bg-[var(--admin-accent)]" : "bg-stone-300"}`}>
|
||||
<span className={`inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform ${overtimeNotifications ? "translate-x-4" : "translate-x-1"}`} />
|
||||
</button>
|
||||
@@ -612,7 +612,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-2">Email addresses</label>
|
||||
<div className="flex gap-2">
|
||||
<input value={newEmail}
|
||||
<input aria-label="Manager@farm.com" value={newEmail}
|
||||
onChange={e => setNewEmail(e.target.value)}
|
||||
onKeyDown={e => e.key === "Enter" && (addEmail(), e.preventDefault())}
|
||||
className="flex-1 px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] placeholder:text-[var(--admin-text-muted)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors"
|
||||
@@ -623,7 +623,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
{notificationEmails.map(e => (
|
||||
<span key={e} className="inline-flex items-center gap-1 bg-[var(--admin-bg-subtle)] text-[var(--admin-text-secondary)] text-xs px-2 py-1 rounded-lg">
|
||||
{e}
|
||||
<button onClick={() => removeEmail(e)} className="text-[var(--admin-text-muted)] hover:text-red-500 ml-1">×</button>
|
||||
<button type="button" onClick={() => removeEmail(e)} className="text-[var(--admin-text-muted)] hover:text-red-500 ml-1">×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
@@ -631,7 +631,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-2">SMS numbers</label>
|
||||
<div className="flex gap-2">
|
||||
<input value={newSms}
|
||||
<input aria-label="+1234567890" value={newSms}
|
||||
onChange={e => setNewSms(e.target.value)}
|
||||
onKeyDown={e => e.key === "Enter" && (addSms(), e.preventDefault())}
|
||||
className="flex-1 px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] placeholder:text-[var(--admin-text-muted)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors"
|
||||
@@ -642,7 +642,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
{notificationSmsNumbers.map(n => (
|
||||
<span key={n} className="inline-flex items-center gap-1 bg-[var(--admin-bg-subtle)] text-[var(--admin-text-secondary)] text-xs px-2 py-1 rounded-lg">
|
||||
{n}
|
||||
<button onClick={() => removeSms(n)} className="text-[var(--admin-text-muted)] hover:text-red-500 ml-1">×</button>
|
||||
<button type="button" onClick={() => removeSms(n)} className="text-[var(--admin-text-muted)] hover:text-red-500 ml-1">×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
@@ -667,7 +667,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<div className="bg-white border border-[var(--admin-border)] rounded-2xl w-full max-w-md shadow-xl">
|
||||
<div className="px-6 py-4 border-b border-[var(--admin-border)] flex items-center justify-between">
|
||||
<h3 className="text-lg font-bold text-[var(--admin-text-primary)]">{editingWorker ? "Edit Worker" : "Add Worker"}</h3>
|
||||
<button onClick={() => setShowWorkerModal(false)} className="text-[var(--admin-text-muted)] hover:text-[var(--admin-text-primary)] text-xl leading-none">×</button>
|
||||
<button type="button" onClick={() => setShowWorkerModal(false)} className="text-[var(--admin-text-muted)] hover:text-[var(--admin-text-primary)] text-xl leading-none">×</button>
|
||||
</div>
|
||||
<div className="p-6 space-y-4">
|
||||
{workerError && <div className="bg-red-50 border border-red-200 rounded-xl py-3 px-4 text-red-700 text-sm">{workerError}</div>}
|
||||
@@ -680,14 +680,14 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
)}
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-1.5">Name *</label>
|
||||
<input value={workerName} onChange={e => setWorkerName(e.target.value)}
|
||||
<input aria-label="Worker Name" value={workerName} onChange={e => setWorkerName(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] placeholder:text-[var(--admin-text-muted)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors"
|
||||
placeholder="Worker name" />
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-1.5">Role</label>
|
||||
<select value={workerRole} onChange={e => setWorkerRole(e.target.value)}
|
||||
<select aria-label="Select" value={workerRole} onChange={e => setWorkerRole(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors">
|
||||
<option value="worker">Worker</option>
|
||||
<option value="time_admin">Time Admin</option>
|
||||
@@ -695,7 +695,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-1.5">Lang</label>
|
||||
<select value={workerLang} onChange={e => setWorkerLang(e.target.value)}
|
||||
<select aria-label="Select" value={workerLang} onChange={e => setWorkerLang(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors">
|
||||
<option value="en">English</option>
|
||||
<option value="es">Español</option>
|
||||
@@ -703,7 +703,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<input type="checkbox" id="workerActive" checked={workerActive} onChange={e => setWorkerActive(e.target.checked)}
|
||||
<input aria-label="WorkerActive" type="checkbox" id="workerActive" checked={workerActive} onChange={e => setWorkerActive(e.target.checked)}
|
||||
className="w-4 h-4 rounded border-[var(--admin-border)] bg-white text-[var(--admin-accent)]" />
|
||||
<label htmlFor="workerActive" className="text-sm text-[var(--admin-text-secondary)]">Active</label>
|
||||
</div>
|
||||
@@ -733,26 +733,26 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
<div className="bg-white border border-[var(--admin-border)] rounded-2xl w-full max-w-md shadow-xl">
|
||||
<div className="px-6 py-4 border-b border-[var(--admin-border)] flex items-center justify-between">
|
||||
<h3 className="text-lg font-bold text-[var(--admin-text-primary)]">{editingTask ? "Edit Task" : "Add Task"}</h3>
|
||||
<button onClick={() => setShowTaskModal(false)} className="text-[var(--admin-text-muted)] hover:text-[var(--admin-text-primary)] text-xl leading-none">×</button>
|
||||
<button type="button" onClick={() => setShowTaskModal(false)} className="text-[var(--admin-text-muted)] hover:text-[var(--admin-text-primary)] text-xl leading-none">×</button>
|
||||
</div>
|
||||
<div className="p-6 space-y-4">
|
||||
{taskError && <div className="bg-red-50 border border-red-200 rounded-xl py-3 px-4 text-red-700 text-sm">{taskError}</div>}
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-1.5">Name (EN) *</label>
|
||||
<input value={taskName} onChange={e => setTaskName(e.target.value)}
|
||||
<input aria-label=". Harvesting" value={taskName} onChange={e => setTaskName(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] placeholder:text-[var(--admin-text-muted)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors"
|
||||
placeholder="e.g. Harvesting" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-1.5">Name (ES)</label>
|
||||
<input value={taskNameEs} onChange={e => setTaskNameEs(e.target.value)}
|
||||
<input aria-label=". Cosecha" value={taskNameEs} onChange={e => setTaskNameEs(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] placeholder:text-[var(--admin-text-muted)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors"
|
||||
placeholder="e.g. Cosecha" />
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-1.5">Unit</label>
|
||||
<select value={taskUnit} onChange={e => setTaskUnit(e.target.value)}
|
||||
<select aria-label="Select" value={taskUnit} onChange={e => setTaskUnit(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors">
|
||||
<option value="hours">Hours</option>
|
||||
<option value="pieces">Pieces</option>
|
||||
@@ -761,12 +761,12 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-widest text-[var(--admin-text-muted)] mb-1.5">Sort Order</label>
|
||||
<input type="number" value={taskSortOrder} onChange={e => setTaskSortOrder(parseInt(e.target.value) || 0)}
|
||||
<input aria-label="Number" type="number" value={taskSortOrder} onChange={e => setTaskSortOrder(parseInt(e.target.value) || 0)}
|
||||
className="w-full px-4 py-3 rounded-xl border border-[var(--admin-border)] bg-white text-[var(--admin-text-primary)] focus:outline-none focus:border-[var(--admin-accent)] transition-colors" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<input type="checkbox" id="taskActive" checked={taskActive} onChange={e => setTaskActive(e.target.checked)}
|
||||
<input aria-label="TaskActive" type="checkbox" id="taskActive" checked={taskActive} onChange={e => setTaskActive(e.target.checked)}
|
||||
className="w-4 h-4 rounded border-[var(--admin-border)] bg-white text-[var(--admin-accent)]" />
|
||||
<label htmlFor="taskActive" className="text-sm text-[var(--admin-text-secondary)]">Active</label>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user