chore(lint): manual cleanup batch 4 — noNonNullAssertion + small fixes

- noNonNullAssertion (42 → 0): replaced ! assertions with explicit null guards across auth.module, storage.service, pl24-auth, categories.service, catalog.service, parts.service, emex.browser, emex.service, parts-catalogs-auth, pl24-ford-legacy, email.service, database.provider, jobs/processors, psa-variant-selector, vehicles/$id/categories, catalog/$brandName
- buildTree: skip orphaned items instead of asserting map.get
- emex.browser.acquirePage: explicit context check before newPage
- pcat-auth.getIstanbulTime: graceful UTC fallback if Intl parts missing
- email.send: gate on both postalApiUrl + postalApiKey for type narrowing
- categories.service: PSA root-fallback now early-returns when category.vehicleId missing (catalog-only categories don't have a sibling root)
- pl24-ford-legacy: createHash from "node:crypto", URL building uses single template literals, useDefaultParameterLast — required modelYear/engine/gearbox params (callers already supply them)
- pcat-auth: h.origin / h.referer literal-key access
- index.tsx: <button type="button"> on mobile menu toggle
- parts-panel + admin/users: keyboard handler for clickable rows (Enter/Space)
- ford-legacy: useOptionalChain on item.name?.toUpperCase()

Lint count: 155 → 114. Remaining: 121 noExplicitAny + 3 small.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sase Dev
2026-05-09 17:10:28 +00:00
parent 80fddf2864
commit 7bc78a6f69
19 changed files with 124 additions and 98 deletions

View File

@@ -32,7 +32,7 @@ export function PsaVariantSelector({ vehicleId, onSelect }: PsaVariantSelectorPr
queryKey: ["psa-engines", vehicleId, selectedBody],
queryFn: () =>
api.get<VariantItem[]>(
`/catalog/vehicles/${vehicleId}/psa-engines?body=${encodeURIComponent(selectedBody!)}`,
`/catalog/vehicles/${vehicleId}/psa-engines?body=${encodeURIComponent(selectedBody ?? "")}`,
),
enabled: !!vehicleId && !!selectedBody,
});
@@ -41,7 +41,7 @@ export function PsaVariantSelector({ vehicleId, onSelect }: PsaVariantSelectorPr
queryKey: ["psa-gearboxes", vehicleId, selectedBody, selectedEngine],
queryFn: () =>
api.get<VariantItem[]>(
`/catalog/vehicles/${vehicleId}/psa-gearboxes?body=${encodeURIComponent(selectedBody!)}&engine=${encodeURIComponent(selectedEngine!)}`,
`/catalog/vehicles/${vehicleId}/psa-gearboxes?body=${encodeURIComponent(selectedBody ?? "")}&engine=${encodeURIComponent(selectedEngine ?? "")}`,
),
enabled: !!vehicleId && !!selectedBody && !!selectedEngine,
});
@@ -58,7 +58,8 @@ export function PsaVariantSelector({ vehicleId, onSelect }: PsaVariantSelectorPr
const handleEngineSelect = (code: string | "_all_") => {
if (code === "_all_") {
onSelect(selectedBody!, "_all_", "_all_");
if (!selectedBody) return;
onSelect(selectedBody, "_all_", "_all_");
return;
}
setSelectedEngine(code);
@@ -67,7 +68,8 @@ export function PsaVariantSelector({ vehicleId, onSelect }: PsaVariantSelectorPr
const handleGearboxSelect = (code: string | "_all_") => {
if (code === "_all_") {
onSelect(selectedBody!, selectedEngine!, "_all_");
if (!selectedBody || !selectedEngine) return;
onSelect(selectedBody, selectedEngine, "_all_");
return;
}
setSelectedGearbox(code);

View File

@@ -120,6 +120,12 @@ export function PartsPanel({ parts, vehicleId, categoryId }: PartsPanelProps) {
onMouseEnter={() => setHighlightedGroup(group)}
onMouseLeave={() => setHighlightedGroup(null)}
onClick={() => setSelectedGroup(selectedGroup === group ? null : group)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
setSelectedGroup(selectedGroup === group ? null : group);
}
}}
>
<td className="px-3 py-2 text-muted-foreground">{part.hotspotIndex}</td>
<td className="px-3 py-2">

View File

@@ -461,7 +461,15 @@ function AdminUsersPage() {
<div
key={u.id}
className="grid cursor-pointer items-center gap-4 px-6 py-4 transition-colors hover:bg-muted/50 lg:grid-cols-7"
role="button"
tabIndex={0}
onClick={() => setSelectedUserId(u.id)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
setSelectedUserId(u.id);
}
}}
>
<div>
<p className="font-medium">{u.name}</p>

View File

@@ -134,9 +134,9 @@ function CatalogModelsPage() {
<Skeleton key={__k} className="h-24 w-full rounded-xl" />
))}
</div>
) : isMultiCatalog && !activeCatalog ? (
) : isMultiCatalog && !activeCatalog && catalogs ? (
// Sub-catalog selector
<CatalogSelector catalogs={catalogs!} brandName={brandName} brandLabel={decodedBrandName} />
<CatalogSelector catalogs={catalogs} brandName={brandName} brandLabel={decodedBrandName} />
) : modelsLoading ? (
<div>
<div className="mb-4 flex items-center gap-2 text-sm text-muted-foreground">

View File

@@ -143,12 +143,13 @@ function VehicleCategoryPage() {
{/* Parent category — show children */}
{hasChildren &&
data?.children &&
(viewMode === "grid" ? (
<CategoryGrid categories={data.children!} vehicleId={id} />
<CategoryGrid categories={data.children} vehicleId={id} />
) : viewMode === "tree" ? (
<CategoryTree categories={data.children!} vehicleId={id} />
<CategoryTree categories={data.children} vehicleId={id} />
) : (
<CategoryColumns categories={data.children!} vehicleId={id} />
<CategoryColumns categories={data.children} vehicleId={id} />
))}
{/* Leaf category — show schema viewer */}

View File

@@ -620,7 +620,7 @@ function HomePage() {
>
{isDark ? <Sun className="size-4" /> : <Moon className="size-4" />}
</button>
<button onClick={() => setMobileMenuOpen(!mobileMenuOpen)}>
<button type="button" onClick={() => setMobileMenuOpen(!mobileMenuOpen)}>
{mobileMenuOpen ? <X className="size-6" /> : <Menu className="size-6" />}
</button>
</div>