From f7ac9399b2232c668e357400c7e67600fa7cc4a8 Mon Sep 17 00:00:00 2001 From: Nora Date: Fri, 26 Jun 2026 04:08:56 -0600 Subject: [PATCH] =?UTF-8?q?fix:=20react-doctor=20control-has-associated-la?= =?UTF-8?q?bel=20137=E2=86=92=3F=20(auto=20aria-labels)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add aria-label to buttons (icon-only, pagination, action) and inputs (placeholder-derived) via balanced-brace JSX parser. Files with complex onClick expressions (deep brace nesting) skipped to avoid breakage. --- src/app/admin/settings/ai/AIClient.tsx | 40 +++++++++---------- .../settings/billing/BillingClientPage.tsx | 4 +- .../integrations/IntegrationsClient.tsx | 4 +- .../water-log/headgates/HeadgatesManager.tsx | 8 ++-- .../indian-river-direct/faq/FAQClientPage.tsx | 2 +- src/app/tuxedo/faq/FAQClientPage.tsx | 2 +- .../admin/AbandonedCartDashboard.tsx | 8 ++-- src/components/admin/AdminStopsPanel.tsx | 12 +++--- src/components/admin/AdvancedShipping.tsx | 2 +- src/components/admin/AdvancedSquareSync.tsx | 2 +- src/components/admin/BrandSettingsForm.tsx | 2 +- src/components/admin/CampaignListPanel.tsx | 4 +- src/components/admin/ContactListPanel.tsx | 8 ++-- src/components/admin/CreateUserModal.tsx | 8 ++-- src/components/admin/LocationsTab.tsx | 6 +-- src/components/admin/MessageLogPanel.tsx | 4 +- src/components/admin/ProductTableBody.tsx | 2 +- src/components/admin/ProductTableClient.tsx | 2 +- src/components/admin/ProductsClient.tsx | 4 +- src/components/admin/ReportsDashboard.tsx | 2 +- src/components/admin/ScheduleImportModal.tsx | 12 +++--- src/components/admin/SettingsSections.tsx | 34 ++++++++-------- src/components/admin/StopTableClient.tsx | 8 ++-- .../admin/TimeTrackingSettingsClient.tsx | 16 ++++---- src/components/admin/UsersPage.tsx | 32 +++++++-------- src/components/admin/WaterLogAdminPanel.tsx | 16 ++++---- .../admin/WelcomeSequenceDashboard.tsx | 4 +- .../admin/design-system/AdminFilterBar.tsx | 2 +- .../admin/design-system/AdminPagination.tsx | 8 ++-- src/components/admin/shared/DataTable.tsx | 4 +- src/components/legal/CookieConsentBanner.tsx | 10 ++--- .../route-trace/FsmaReportModal.tsx | 10 ++--- src/components/route-trace/LotCreateModal.tsx | 4 +- src/components/route-trace/LotListTable.tsx | 16 ++++---- src/components/route-trace/QRScanModal.tsx | 6 +-- .../route-trace/StickerPreviewModal.tsx | 10 ++--- src/components/storefront/TuxedoVideoHero.tsx | 2 +- src/components/water/WaterAdminClient.tsx | 10 ++--- .../wholesale/OrderDetailsModal.tsx | 6 +-- .../wholesale/admin/AddRecipientForm.tsx | 4 +- .../wholesale/admin/CustomerPricingPanel.tsx | 2 +- .../wholesale/admin/CustomersTab.tsx | 14 +++---- .../wholesale/admin/PriceSheetModal.tsx | 2 +- .../wholesale/admin/ProductsTab.tsx | 4 +- .../wholesale/admin/SettingsTab.tsx | 8 ++-- .../admin/WebhookSettingsSection.tsx | 4 +- 46 files changed, 187 insertions(+), 187 deletions(-) diff --git a/src/app/admin/settings/ai/AIClient.tsx b/src/app/admin/settings/ai/AIClient.tsx index 37611cf..da83174 100644 --- a/src/app/admin/settings/ai/AIClient.tsx +++ b/src/app/admin/settings/ai/AIClient.tsx @@ -131,7 +131,7 @@ function ToolCard({ tool, isConnected, onOpen }: ToolCardProps) { boxShadow: isConnected ? '0 2px 8px rgba(202, 117, 67, 0.25)' : 'none', }} title={!isConnected ? "Add your OpenAI API key in Settings to enable" : "Open tool"} - > + aria-label="Open Tool"> Open Tool )} @@ -140,7 +140,7 @@ function ToolCard({ tool, isConnected, onOpen }: ToolCardProps) { style={{ background: 'rgba(0, 0, 0, 0.04)', color: 'rgba(0, 0, 0, 0.4)', - }}> + }} aria-label="Coming Soon"> Coming Soon )} @@ -149,7 +149,7 @@ function ToolCard({ tool, isConnected, onOpen }: ToolCardProps) { style={{ background: 'rgba(171, 162, 120, 0.15)', color: '#92781e', - }}> + }} aria-label="Request Access"> Request Access )} @@ -225,7 +225,7 @@ function ConnectionStatusBanner({ isConnected, availableCount, onConfigure }: { color: 'white', boxShadow: '0 2px 8px rgba(202, 117, 67, 0.25)', }} - > + aria-label="Add API Key"> Add API Key @@ -783,7 +783,7 @@ function ReportExplainerTool({ brandId }: { brandId: string }) { onClick={() => copyToClipboard(JSON.stringify(result, null, 2))} className="text-xs flex items-center gap-1 transition-colors" style={{ color: 'var(--admin-text-muted)' }} - > + aria-label="Copy to clipboard"> Copy to clipboard @@ -898,7 +898,7 @@ function PricingAdvisorTool({ brandId }: { brandId: string }) {
- +
{priceTiers.map((tier, i) => (
@@ -922,7 +922,7 @@ function PricingAdvisorTool({ brandId }: { brandId: string }) { />
{priceTiers.length > 1 && ( - + )}
))} @@ -932,7 +932,7 @@ function PricingAdvisorTool({ brandId }: { brandId: string }) {
- +
@@ -971,7 +971,7 @@ function PricingAdvisorTool({ brandId }: { brandId: string }) { />
{historicalSales.length > 1 && ( - + )}
))} @@ -1048,7 +1048,7 @@ function PricingAdvisorTool({ brandId }: { brandId: string }) { onClick={() => copyToClipboard(JSON.stringify(result, null, 2))} className="text-xs flex items-center gap-1 transition-colors" style={{ color: 'var(--admin-text-muted)' }} - > + aria-label="Copy to clipboard"> Copy to clipboard @@ -1154,7 +1154,7 @@ function StopBlastAdvisorTool({ brandId }: { brandId: string }) {

Recommended Subject Line

{result.subjectLine}

-
@@ -1410,7 +1410,7 @@ function RouteOptimizerTool({ brandId }: { brandId: string }) { onClick={addStop} className="text-xs flex items-center gap-1 transition-colors" style={{ color: 'var(--admin-accent)' }} - > + aria-label="+ Add Stop"> + Add Stop @@ -1419,7 +1419,7 @@ function RouteOptimizerTool({ brandId }: { brandId: string }) {
Stop {i + 1} {stops.length > 2 && ( - )} @@ -1546,7 +1546,7 @@ function RouteOptimizerTool({ brandId }: { brandId: string }) { onClick={() => copyToClipboard(JSON.stringify(result, null, 2))} className="text-xs flex items-center gap-1 transition-colors" style={{ color: 'var(--admin-text-muted)' }} - > + aria-label="Copy to clipboard"> Copy to clipboard
@@ -1638,7 +1638,7 @@ function DemandForecastTool({ brandId }: { brandId: string }) {
- +
@@ -1674,7 +1674,7 @@ function DemandForecastTool({ brandId }: { brandId: string }) { style={{ borderColor: 'var(--admin-border)', backgroundColor: 'var(--admin-bg)', color: 'var(--admin-text-primary)' }} /> {historicalData.length > 1 && ( - + )}
))} @@ -1746,7 +1746,7 @@ function DemandForecastTool({ brandId }: { brandId: string }) { onClick={() => copyToClipboard(JSON.stringify(result, null, 2))} className="text-xs flex items-center gap-1 transition-colors" style={{ color: 'var(--admin-text-muted)' }} - > + aria-label="Copy to clipboard"> Copy to clipboard
@@ -1773,7 +1773,7 @@ function ToolModal({ tool, brandId, brandName, onClose }: ModalProps) { {tool.icon}

{tool.title}

- {modules.map((m) => { @@ -1885,7 +1885,7 @@ export default function AIsettingsClient({ key={m} onClick={() => setActiveModule(activeModule === m ? null : m)} className={`admin-filter-tab ${activeModule === m ? 'admin-filter-tab--active' : ''}`} - > + aria-label="()"> {m} ({count}) ); diff --git a/src/app/admin/settings/billing/BillingClientPage.tsx b/src/app/admin/settings/billing/BillingClientPage.tsx index 06f4a8a..635a83f 100644 --- a/src/app/admin/settings/billing/BillingClientPage.tsx +++ b/src/app/admin/settings/billing/BillingClientPage.tsx @@ -236,7 +236,7 @@ export default function BillingClientPage({ overview }: Props) { +

Headgates & QR Codes

Manage headgates and generate QR codes for field access

@@ -347,7 +347,7 @@ export default function HeadgatesManager({ initialHeadgates, brandId }: Props) { Edit {/* QR preview thumbnail */} - {page + 1}/{totalPages} @@ -168,10 +168,10 @@ export default function AbandonedCartDashboard({ brandId }: Props) {
+ className="text-xs text-[var(--admin-text-muted)] hover:text-[var(--admin-text-primary)] px-2 py-1 rounded-lg hover:bg-stone-100 transition-all" aria-label="View">View {c.status === "active" && ( + className="text-xs text-amber-600 hover:text-amber-700 px-2 py-1 rounded-lg hover:bg-amber-50 transition-all" aria-label="Close">Close )} {c.status === "active" && (
@@ -294,7 +294,7 @@ export default function AdminStopsPanel({ stops, brandId }: Props) { @@ -321,7 +321,7 @@ export default function AdminStopsPanel({ stops, brandId }: Props) { onClick={() => setPage((p) => Math.max(0, p - 1))} disabled={page === 0} className="flex h-9 w-9 items-center justify-center rounded-xl border border-stone-200 text-stone-500 hover:border-stone-300 hover:text-stone-700 hover:bg-white disabled:opacity-40 disabled:cursor-not-allowed" - > + aria-label="Previous"> @@ -331,7 +331,7 @@ export default function AdminStopsPanel({ stops, brandId }: Props) { onClick={() => setPage((p) => Math.min(totalPages - 1, p + 1))} disabled={page >= totalPages - 1} className="flex h-9 w-9 items-center justify-center rounded-xl border border-stone-200 text-stone-500 hover:border-stone-300 hover:text-stone-700 hover:bg-white disabled:opacity-40 disabled:cursor-not-allowed" - > + aria-label="Next"> diff --git a/src/components/admin/AdvancedShipping.tsx b/src/components/admin/AdvancedShipping.tsx index 21b45b6..8f12738 100644 --- a/src/components/admin/AdvancedShipping.tsx +++ b/src/components/admin/AdvancedShipping.tsx @@ -167,7 +167,7 @@ export default function AdvancedShipping({ brandId }: { brandId: string }) { onClick={handleTest} disabled={saving} className="rounded-lg border border-[var(--admin-border)] px-4 py-2 text-xs font-medium text-[var(--admin-text-secondary)] hover:bg-stone-50 disabled:opacity-50" - > + aria-label="Test Connection"> Test Connection diff --git a/src/components/admin/ContactListPanel.tsx b/src/components/admin/ContactListPanel.tsx index 5b64b02..ddf44f6 100644 --- a/src/components/admin/ContactListPanel.tsx +++ b/src/components/admin/ContactListPanel.tsx @@ -262,7 +262,7 @@ export default function ContactListPanel({ @@ -357,7 +357,7 @@ export default function ContactListPanel({ disabled={deleting === c.id} className="p-1.5 rounded-lg hover:bg-red-50 text-red-500 hover:text-red-700 disabled:opacity-50 transition-colors" title="Delete contact" - > + aria-label="Delete contact"> {Icons.trash("h-4 w-4")} @@ -424,7 +424,7 @@ export default function ContactListPanel({ onClick={() => handlePage(-1)} disabled={page === 0} className="inline-flex items-center gap-1.5 rounded-lg border border-stone-200 px-4 py-2 text-sm font-medium disabled:opacity-50 hover:bg-stone-50 transition-colors" - > + aria-label="Previous"> {Icons.chevronLeft("h-4 w-4")} Previous @@ -432,7 +432,7 @@ export default function ContactListPanel({ onClick={() => handlePage(1)} disabled={(page + 1) * limit >= total} className="inline-flex items-center gap-1.5 rounded-lg border border-stone-200 px-4 py-2 text-sm font-medium disabled:opacity-50 hover:bg-stone-50 transition-colors" - > + aria-label="Next"> Next {Icons.chevronRight("h-4 w-4")} diff --git a/src/components/admin/CreateUserModal.tsx b/src/components/admin/CreateUserModal.tsx index 1fd69c4..890d10b 100644 --- a/src/components/admin/CreateUserModal.tsx +++ b/src/components/admin/CreateUserModal.tsx @@ -270,7 +270,7 @@ export default function CreateUserModal({ isOpen, onClose, onSuccess, brands, cu @@ -291,7 +291,7 @@ export default function CreateUserModal({ isOpen, onClose, onSuccess, brands, cu {error && (
{error} -
@@ -334,7 +334,7 @@ export default function LocationsTab({ locations, brandId }: Props) { onClick={() => setEditing(loc as LocationForEdit)} className="rounded-lg p-1.5 text-[var(--admin-text-muted)] hover:text-[var(--admin-text-primary)] hover:bg-[var(--admin-bg-subtle)] transition-colors" title="Edit venue" - > + aria-label="Edit venue"> @@ -344,7 +344,7 @@ export default function LocationsTab({ locations, brandId }: Props) { disabled={pendingDeleteId === loc.id} className="rounded-lg p-1.5 text-[var(--admin-text-muted)] hover:text-red-600 hover:bg-red-50 transition-colors disabled:opacity-50" title="Delete venue" - > + aria-label="Delete venue"> {pendingDeleteId === loc.id ? ( diff --git a/src/components/admin/MessageLogPanel.tsx b/src/components/admin/MessageLogPanel.tsx index 1a01319..7dc632d 100644 --- a/src/components/admin/MessageLogPanel.tsx +++ b/src/components/admin/MessageLogPanel.tsx @@ -477,7 +477,7 @@ export default function MessageLogPanel({ brandId }: { brandId?: string }) { onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page === 1} className="px-4 py-2 text-sm border border-stone-200 rounded-xl bg-white text-stone-700 hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" - > + aria-label="Previous"> Previous {Array.from({ length: Math.min(5, totalPages) }, (_, i) => { @@ -500,7 +500,7 @@ export default function MessageLogPanel({ brandId }: { brandId?: string }) { onClick={() => setPage((p) => Math.min(totalPages, p + 1))} disabled={page === totalPages} className="px-4 py-2 text-sm border border-stone-200 rounded-xl bg-white text-stone-700 hover:bg-stone-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" - > + aria-label="Next"> Next diff --git a/src/components/admin/ProductTableBody.tsx b/src/components/admin/ProductTableBody.tsx index 5d09eaa..efe7d61 100644 --- a/src/components/admin/ProductTableBody.tsx +++ b/src/components/admin/ProductTableBody.tsx @@ -101,7 +101,7 @@ export default function ProductTableBody({ diff --git a/src/components/admin/ProductTableClient.tsx b/src/components/admin/ProductTableClient.tsx index fac83f6..14a52c9 100644 --- a/src/components/admin/ProductTableClient.tsx +++ b/src/components/admin/ProductTableClient.tsx @@ -81,7 +81,7 @@ export default function ProductTableClient({ products }: Props) { {deleteError && (
{deleteError}{" "} -
diff --git a/src/components/admin/ProductsClient.tsx b/src/components/admin/ProductsClient.tsx index 23c17e1..926bbc7 100644 --- a/src/components/admin/ProductsClient.tsx +++ b/src/components/admin/ProductsClient.tsx @@ -573,7 +573,7 @@ function TableView({ + aria-label="Cancel"> Cancel @@ -363,7 +363,7 @@ export default function ScheduleImportModal({ brandId, onClose, onComplete }: Pr @@ -380,7 +380,7 @@ export default function ScheduleImportModal({ brandId, onClose, onComplete }: Pr diff --git a/src/components/admin/SettingsSections.tsx b/src/components/admin/SettingsSections.tsx index bd71e43..a5b2241 100644 --- a/src/components/admin/SettingsSections.tsx +++ b/src/components/admin/SettingsSections.tsx @@ -51,7 +51,7 @@ function Accordion({ title, id, description, defaultOpen = false, accentColor = onClick={() => setOpen(!open)} className="w-full flex items-center justify-between px-5 py-4 hover:bg-stone-50 transition-colors" aria-expanded={open} - > + aria-label=")}">
{title} {description && ( @@ -412,13 +412,13 @@ export default function SettingsSections({ brandId, workersOnly, tasksOnly }: Pr onKeyDown={e => e.key === "Enter" && (addEmail(), e.preventDefault())} className="flex-1 px-4 py-3 rounded-xl border border-stone-200 bg-white text-stone-900 placeholder:text-stone-400 focus:outline-none focus:border-emerald-500" placeholder="manager@farm.com" /> - +
{notificationEmails.map(e => ( {e} - +
{notificationSmsNumbers.map(n => ( {n} - + className="text-xs bg-emerald-600 hover:bg-emerald-500 text-white px-3 py-1.5 rounded-lg font-semibold transition-all" aria-label="+ Add Worker">+ Add Worker
@@ -539,9 +539,9 @@ export default function SettingsSections({ brandId, workersOnly, tasksOnly }: Pr @@ -566,7 +566,7 @@ export default function SettingsSections({ brandId, workersOnly, tasksOnly }: Pr

Define tasks workers can clock into.

+ className="text-xs bg-amber-500 hover:bg-amber-600 text-white px-3 py-1.5 rounded-lg font-semibold transition-all" aria-label="+ Add Task">+ Add Task
{w.last_used_at ? new Date(w.last_used_at).toLocaleDateString() : "—"}
- - - + + +
@@ -596,8 +596,8 @@ export default function SettingsSections({ brandId, workersOnly, tasksOnly }: Pr @@ -615,7 +615,7 @@ export default function SettingsSections({ brandId, workersOnly, tasksOnly }: Pr

{editingWorker ? "Edit Worker" : "Add Worker"}

-
{editingWorker && (
-
)}
@@ -384,7 +384,7 @@ export default function StopTableClient({ stops, hideInternalFilterBar = false } {deleteError && (
{deleteError}{" "} -
@@ -888,7 +888,7 @@ function StopRow({ setConfirmDelete(stop.id); }} className="w-full text-left px-4 py-2.5 text-sm text-red-600 hover:bg-red-50 transition-colors flex items-center gap-2" - > + aria-label="Delete"> @@ -1066,7 +1066,7 @@ function StopCard({ + ))}
@@ -648,7 +648,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett {notificationSmsNumbers.map(n => ( {n} - + ))} @@ -673,7 +673,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett

{editingWorker ? "Edit Worker" : "Add Worker"}

- +
{workerError &&
{workerError}
} @@ -739,7 +739,7 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett

{editingTask ? "Edit Task" : "Add Task"}

- +
{taskError &&
{taskError}
} diff --git a/src/components/admin/UsersPage.tsx b/src/components/admin/UsersPage.tsx index 6a13f98..bb979ac 100644 --- a/src/components/admin/UsersPage.tsx +++ b/src/components/admin/UsersPage.tsx @@ -345,7 +345,7 @@ export default function UsersPage({ initialUsers, brands, currentUser, onUserCre )} @@ -367,7 +367,7 @@ export default function UsersPage({ initialUsers, brands, currentUser, onUserCre {error && (
{error} -
@@ -424,7 +424,7 @@ export default function UsersPage({ initialUsers, brands, currentUser, onUserCre onClick={() => setActionMenuId(actionMenuId === user.id ? null : user.id)} className="text-base font-medium text-stone-400 hover:text-stone-600 px-2 py-1" title="More actions" - > + aria-label="More actions"> ⁝ {actionMenuId === user.id && ( @@ -443,20 +443,20 @@ export default function UsersPage({ initialUsers, brands, currentUser, onUserCre {user.id !== currentUser.id && ( )} @@ -492,13 +492,13 @@ export default function UsersPage({ initialUsers, brands, currentUser, onUserCre
@@ -525,7 +525,7 @@ export default function UsersPage({ initialUsers, brands, currentUser, onUserCre

{editing.isNew ? "Create User" : "Edit User"}

- +
) : passwordModal.tempPassword ? (

Temporary password for {passwordModal.email}:

{passwordModal.tempPassword} - +

Share this password securely with the user. They will be required to change it on next login.

- +
) : passwordModal.message ? (

{passwordModal.message}

- +
) : null}
diff --git a/src/components/admin/WaterLogAdminPanel.tsx b/src/components/admin/WaterLogAdminPanel.tsx index c733bdb..515771c 100644 --- a/src/components/admin/WaterLogAdminPanel.tsx +++ b/src/components/admin/WaterLogAdminPanel.tsx @@ -590,21 +590,21 @@ export default function WaterLogAdminPanel({
·
@@ -723,14 +723,14 @@ export default function WaterLogAdminPanel({ ·
@@ -833,7 +833,7 @@ export default function WaterLogAdminPanel({ setFilterVia(""); }} className="text-xs font-medium text-[#57694e] hover:text-[#1a4d2e] hover:underline" - > + aria-label="Clear filters"> Clear filters )} @@ -907,7 +907,7 @@ export default function WaterLogAdminPanel({ router.push(`/admin/water-log/entries/${e.id}`) } className="font-medium text-[#1a4d2e] opacity-0 transition-opacity group-hover:opacity-100 hover:underline" - > + aria-label="Edit →"> Edit → @@ -1061,7 +1061,7 @@ function PinBanner({
diff --git a/src/components/admin/WelcomeSequenceDashboard.tsx b/src/components/admin/WelcomeSequenceDashboard.tsx index b404b5e..d813b5d 100644 --- a/src/components/admin/WelcomeSequenceDashboard.tsx +++ b/src/components/admin/WelcomeSequenceDashboard.tsx @@ -94,12 +94,12 @@ export default function WelcomeSequenceDashboard({ brandId }: Props) { {totalPages > 1 && (
{page + 1}/{totalPages}
diff --git a/src/components/admin/design-system/AdminFilterBar.tsx b/src/components/admin/design-system/AdminFilterBar.tsx index 73361b4..e23507c 100644 --- a/src/components/admin/design-system/AdminFilterBar.tsx +++ b/src/components/admin/design-system/AdminFilterBar.tsx @@ -122,7 +122,7 @@ export default function AdminFilterBar({ )} diff --git a/src/components/admin/design-system/AdminPagination.tsx b/src/components/admin/design-system/AdminPagination.tsx index 58ef5cd..e5b2d67 100644 --- a/src/components/admin/design-system/AdminPagination.tsx +++ b/src/components/admin/design-system/AdminPagination.tsx @@ -21,7 +21,7 @@ export default function AdminPagination({ onClick={() => onPageChange(currentPage - 1)} disabled={currentPage === 0} className="flex h-8 w-8 items-center justify-center rounded-lg border border-[var(--admin-border)] text-[var(--admin-text-muted)] hover:text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)] disabled:opacity-30 disabled:cursor-not-allowed transition-all duration-150" - > + aria-label="Previous"> @@ -69,7 +69,7 @@ export default function AdminPagination({ onClick={() => onPageChange(currentPage + 1)} disabled={currentPage >= totalPages - 1} className="flex h-8 w-8 items-center justify-center rounded-lg border border-[var(--admin-border)] text-[var(--admin-text-muted)] hover:text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)] disabled:opacity-30 disabled:cursor-not-allowed transition-all duration-150" - > + aria-label="Next"> @@ -102,7 +102,7 @@ export function AdminSimplePagination({ onClick={() => onPageChange(page - 1)} disabled={page === 0} className="flex h-7 w-7 items-center justify-center rounded border border-[var(--admin-border)] text-[var(--admin-text-muted)] hover:text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)] disabled:opacity-30 disabled:cursor-not-allowed transition-colors" - > + aria-label="Previous"> @@ -111,7 +111,7 @@ export function AdminSimplePagination({ onClick={() => onPageChange(page + 1)} disabled={page >= totalPages - 1} className="flex h-7 w-7 items-center justify-center rounded border border-[var(--admin-border)] text-[var(--admin-text-muted)] hover:text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)] disabled:opacity-30 disabled:cursor-not-allowed transition-colors" - > + aria-label="Next"> diff --git a/src/components/admin/shared/DataTable.tsx b/src/components/admin/shared/DataTable.tsx index dc64481..4a49135 100644 --- a/src/components/admin/shared/DataTable.tsx +++ b/src/components/admin/shared/DataTable.tsx @@ -101,7 +101,7 @@ export default function DataTable({ onClick={() => setPage((p) => Math.max(0, p - 1))} disabled={page === 0} className="flex h-7 w-7 items-center justify-center rounded border border-stone-200 text-stone-500 hover:text-stone-700 hover:bg-stone-50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors" - > + aria-label="Previous"> @@ -110,7 +110,7 @@ export default function DataTable({ onClick={() => setPage((p) => Math.min(totalPages - 1, p + 1))} disabled={page >= totalPages - 1} className="flex h-7 w-7 items-center justify-center rounded border border-stone-200 text-stone-500 hover:text-stone-700 hover:bg-stone-50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors" - > + aria-label="Next"> diff --git a/src/components/legal/CookieConsentBanner.tsx b/src/components/legal/CookieConsentBanner.tsx index 05cf400..2f422ec 100644 --- a/src/components/legal/CookieConsentBanner.tsx +++ b/src/components/legal/CookieConsentBanner.tsx @@ -145,13 +145,13 @@ export default function CookieConsentBanner() {
@@ -175,19 +175,19 @@ export default function CookieConsentBanner() { diff --git a/src/components/route-trace/FsmaReportModal.tsx b/src/components/route-trace/FsmaReportModal.tsx index 95398c1..9d6e9c8 100644 --- a/src/components/route-trace/FsmaReportModal.tsx +++ b/src/components/route-trace/FsmaReportModal.tsx @@ -267,7 +267,7 @@ export default function FsmaReportModal({ brandId }: { brandId: string }) { @@ -330,7 +330,7 @@ export default function FsmaReportModal({ brandId }: { brandId: string }) { onClick={() => setOpen(false)} className="flex h-9 w-9 items-center justify-center rounded-full transition-all" style={{ background: "rgba(0, 0, 0, 0.04)", color: "rgba(0, 0, 0, 0.4)" }} - > + aria-label="Close"> @@ -362,7 +362,7 @@ export default function FsmaReportModal({ brandId }: { brandId: string }) { @@ -616,14 +616,14 @@ export default function FsmaReportModal({ brandId }: { brandId: string }) { diff --git a/src/components/route-trace/LotCreateModal.tsx b/src/components/route-trace/LotCreateModal.tsx index 6a01454..b8cc540 100644 --- a/src/components/route-trace/LotCreateModal.tsx +++ b/src/components/route-trace/LotCreateModal.tsx @@ -404,7 +404,7 @@ export default function LotCreateModal({ isOpen, onClose, brandId }: Props) { onClick={() => setNotesOpen(!notesOpen)} className="flex items-center gap-2 text-xs font-semibold uppercase tracking-wider transition-colors" style={{ color: "var(--admin-text-muted)" }} - > + aria-label="Notes"> Notes @@ -436,7 +436,7 @@ export default function LotCreateModal({ isOpen, onClose, brandId }: Props) { borderColor: "var(--admin-border)", color: "var(--admin-text-muted)" }} - > + aria-label="Cancel"> Cancel New Lot @@ -232,7 +232,7 @@ export default function LotListTable({ className={`rounded-xl border px-4 py-3 text-sm font-semibold transition-colors flex items-center gap-2 ${ showBulk ? "border-emerald-600 bg-emerald-600 text-white" : "border-stone-200 text-stone-600 hover:bg-stone-50" }`} - > + aria-label="Bulk"> @@ -250,42 +250,42 @@ export default function LotListTable({ diff --git a/src/components/route-trace/QRScanModal.tsx b/src/components/route-trace/QRScanModal.tsx index 60091b1..fa5ce8c 100644 --- a/src/components/route-trace/QRScanModal.tsx +++ b/src/components/route-trace/QRScanModal.tsx @@ -211,7 +211,7 @@ export default function QRScanModal({ onClose, onScanResult }: QRScanModalProps) className={`flex-1 py-3 text-sm font-semibold transition-colors ${ mode === "camera" ? "text-[var(--admin-text-primary)] border-b-2 border-[var(--admin-text-primary)]" : "text-[var(--admin-text-muted)]" }`} - > + aria-label="Camera"> @@ -223,7 +223,7 @@ export default function QRScanModal({ onClose, onScanResult }: QRScanModalProps) className={`flex-1 py-3 text-sm font-semibold transition-colors ${ mode === "manual" ? "text-[var(--admin-text-primary)] border-b-2 border-[var(--admin-text-primary)]" : "text-[var(--admin-text-muted)]" }`} - > + aria-label="Manual"> @@ -296,7 +296,7 @@ export default function QRScanModal({ onClose, onScanResult }: QRScanModalProps) type="submit" disabled={!manualInput.trim() || isLoading} className="w-full rounded-xl bg-stone-800 py-3.5 text-base font-semibold text-white hover:bg-stone-700 disabled:opacity-50 transition-colors" - > + aria-label="Trace Lot}"> {isLoading ? "Loading..." : <>{Icons.search("h-4 w-4")} Trace Lot} diff --git a/src/components/route-trace/StickerPreviewModal.tsx b/src/components/route-trace/StickerPreviewModal.tsx index 9da046a..552b328 100644 --- a/src/components/route-trace/StickerPreviewModal.tsx +++ b/src/components/route-trace/StickerPreviewModal.tsx @@ -99,7 +99,7 @@ export default function StickerPreviewModal({ lot, onClose }: { lot: LotDetail;

{Icons.printer("h-5 w-5")} Print Sticker

{lot.lot_number} · {lot.crop_type}

- @@ -147,7 +147,7 @@ export default function StickerPreviewModal({ lot, onClose }: { lot: LotDetail; ? "border-emerald-600 bg-emerald-600 text-white" : "border-stone-200 hover:bg-stone-50" }`} - > + aria-label="×">
{w} × {h}
{s === "4x2" ? "Field sticker" : "Shed sticker"} @@ -299,14 +299,14 @@ export default function StickerPreviewModal({ lot, onClose }: { lot: LotDetail;
diff --git a/src/components/storefront/TuxedoVideoHero.tsx b/src/components/storefront/TuxedoVideoHero.tsx index caa5744..f3a768a 100644 --- a/src/components/storefront/TuxedoVideoHero.tsx +++ b/src/components/storefront/TuxedoVideoHero.tsx @@ -324,7 +324,7 @@ export default function TuxedoVideoHero({ onClick={onSecondaryClick} className="group flex items-center gap-3 text-sm font-semibold" style={{ color: "rgba(255,255,255,0.8)" }} - > + aria-label="Next"> {secondaryButton} + aria-label=")}"> {title} {count !== undefined && ( @@ -486,7 +486,7 @@ export default function WaterAdminClient() { } @@ -523,7 +523,7 @@ export default function WaterAdminClient() { type="button" onClick={() => { setShowAddHg(false); setNewHgError(null); }} className="rounded-lg border border-stone-300 px-3 py-2 text-sm text-stone-600 hover:bg-stone-50 min-h-[44px]" - > + aria-label="×"> × @@ -587,7 +587,7 @@ export default function WaterAdminClient() { } @@ -623,7 +623,7 @@ export default function WaterAdminClient() { type="button" onClick={() => { setShowAddUser(false); setNewUserError(null); }} className="rounded-lg border border-stone-300 px-3 py-2 text-sm text-stone-600 hover:bg-stone-50 min-h-[44px]" - > + aria-label="×"> × diff --git a/src/components/wholesale/OrderDetailsModal.tsx b/src/components/wholesale/OrderDetailsModal.tsx index f742c3f..fe5adda 100644 --- a/src/components/wholesale/OrderDetailsModal.tsx +++ b/src/components/wholesale/OrderDetailsModal.tsx @@ -45,7 +45,7 @@ export default function OrderDetailsModal({ order, onClose, onFulfill, onRecordD

Order Details

{order.invoice_number ?? order.id.slice(0, 8)}

- )} @@ -167,7 +167,7 @@ export default function OrderDetailsModal({ order, onClose, onFulfill, onRecordD diff --git a/src/components/wholesale/admin/AddRecipientForm.tsx b/src/components/wholesale/admin/AddRecipientForm.tsx index 5c9e778..92d89c6 100644 --- a/src/components/wholesale/admin/AddRecipientForm.tsx +++ b/src/components/wholesale/admin/AddRecipientForm.tsx @@ -30,14 +30,14 @@ export default function AddRecipientForm({ onAdd }: { onAdd: (email: string, nam type="email" placeholder="Email address" value={email} onChange={e => { setEmail(e.target.value); setError(""); }} onKeyDown={e => e.key === "Enter" && handleAdd()} - className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)]" /> + className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)]" aria-label="Email address"/>
setName(e.target.value)} onKeyDown={e => e.key === "Enter" && handleAdd()} - className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)]" /> + className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)]" aria-label="Name (optional)"/>
Pricing Overrides

{customer.company_name}

-
@@ -436,7 +436,7 @@ export default function CustomersTab({ onClick={(e) => toggleCustomerActions(c.id, e)} title="More actions" className="inline-flex items-center justify-center rounded-xl w-9 h-9 text-[var(--admin-text-muted)] hover:text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)] transition-colors" - > + aria-label="More actions"> {openCustomerActions === c.id && ( @@ -447,14 +447,14 @@ export default function CustomersTab({ diff --git a/src/components/wholesale/admin/PriceSheetModal.tsx b/src/components/wholesale/admin/PriceSheetModal.tsx index f998e3b..a3ce582 100644 --- a/src/components/wholesale/admin/PriceSheetModal.tsx +++ b/src/components/wholesale/admin/PriceSheetModal.tsx @@ -45,7 +45,7 @@ export default function PriceSheetModal({ {customerCount === 1 ? "1 customer" : `${customerCount} customers`}

- diff --git a/src/components/wholesale/admin/ProductsTab.tsx b/src/components/wholesale/admin/ProductsTab.tsx index 5dc7db2..9298b6c 100644 --- a/src/components/wholesale/admin/ProductsTab.tsx +++ b/src/components/wholesale/admin/ProductsTab.tsx @@ -223,7 +223,7 @@ export default function ProductsTab({ products, brandId, onMsg, onRefresh }: Pro onClick={(e) => toggleProductActions(p.id, e)} title="More actions" className="inline-flex items-center justify-center rounded-xl w-9 h-9 text-[var(--admin-text-muted)] hover:text-[var(--admin-text-secondary)] hover:bg-[var(--admin-bg-subtle)] transition-colors" - > + aria-label="More actions"> {openProductActions === p.id && ( @@ -234,7 +234,7 @@ export default function ProductsTab({ products, brandId, onMsg, onRefresh }: Pro diff --git a/src/components/wholesale/admin/SettingsTab.tsx b/src/components/wholesale/admin/SettingsTab.tsx index d469437..63f4b5b 100644 --- a/src/components/wholesale/admin/SettingsTab.tsx +++ b/src/components/wholesale/admin/SettingsTab.tsx @@ -172,7 +172,7 @@ export default function SettingsTab({ settings, brandId, onMsg, onRefresh, canMa
setForm(f => ({ ...f, minOrderAmount: e.target.value }))} - className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)]" step="0.01" placeholder="No minimum" /> + className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)]" step="0.01" placeholder="No minimum" aria-label="No minimum"/>
@@ -212,7 +212,7 @@ export default function SettingsTab({ settings, brandId, onMsg, onRefresh, canMa
setForm(f => ({ ...f, invoiceBusinessWebsite: e.target.value }))} - className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)]" placeholder="https://" /> + className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)]" placeholder="https://" aria-label="https://"/>
{/* Team Notification Recipients */} @@ -250,10 +250,10 @@ export default function SettingsTab({ settings, brandId, onMsg, onRefresh, canMa type="text" placeholder="Name (optional)" value={r.name ?? ""} onChange={e => updateRecipientName(idx, e.target.value)} - className="rounded-xl border border-[var(--admin-border)] px-2.5 py-1.5 text-xs w-36 outline-none focus:border-[var(--admin-accent)]" /> + className="rounded-xl border border-[var(--admin-border)] px-2.5 py-1.5 text-xs w-36 outline-none focus:border-[var(--admin-accent)]" aria-label="Name (optional)"/>
@@ -132,7 +132,7 @@ export default function WebhookSettingsSection({ brandId, onMsg }: WebhookSettin onChange={e => setSettings(s => ({ ...s, secret: e.target.value }))} placeholder="Leave blank to keep current secret" className="w-full rounded-xl border border-[var(--admin-border)] px-3 py-2 text-sm outline-none focus:border-[var(--admin-accent)] font-mono" - /> + aria-label="Leave blank to keep current secret"/>

The receiver should verify the X-Webhook-Signature header using this secret.

- - + +