Skip to content

Commit d5058e8

Browse files
authored
refactor: tighten TypeScript config and fix all type errors (#246)
Enable noUncheckedIndexedAccess and exactOptionalPropertyTypes in tsconfig.json. Fix all resulting errors across the codebase including: - Convert i18n JSON files from JS object literals to valid JSON - Fix SLATrendChart missing closing brace in early return - Add explicit | undefined to optional interface properties for EOPT compat - Fix noUncheckedIndexedAccess violations with non-null assertions - Fix actionLabel/onAction → primaryAction prop migration in route-state - Fix various type mismatches in API services, hooks, and components Closes #160
1 parent b8ec36c commit d5058e8

35 files changed

Lines changed: 156 additions & 144 deletions

package-lock.json

Lines changed: 13 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/config/page.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ export default function SlaConfigPage() {
144144
<RouteErrorState
145145
title="Configuration unavailable"
146146
description={error}
147-
actionLabel="Try again"
148-
onAction={() => void fetchConfigs()}
147+
primaryAction={{ label: "Try again", onClick: () => void fetchConfigs() }}
149148
/>
150149
);
151150
}

src/app/outages/[id]/page.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export default function OutageDetailsPage() {
4949
const [isResolveModalOpen, setIsResolveModalOpen] = useState(false);
5050
const [resolutionPayment, setResolutionPayment] = useState<OutageResolutionPayment | null>(null);
5151

52+
const isResolved = outage?.status === "resolved";
53+
5254
const [editing, setEditing] = useState(false);
5355
const [saving, setSaving] = useState(false);
5456
const [editForm, setEditForm] = useState<OutageUpdate>({});
@@ -87,7 +89,7 @@ export default function OutageDetailsPage() {
8789
// Poll for updates while outage is open
8890
useEffect(() => {
8991
const handlePaletteResolve = () => {
90-
if (!isResolved && !resolving) {
92+
if (!outage || outage.status !== "resolved" && !resolving) {
9193
setIsResolveModalOpen(true);
9294
}
9395
};
@@ -96,7 +98,7 @@ export default function OutageDetailsPage() {
9698
return () => {
9799
window.removeEventListener("command-palette:resolve-outage", handlePaletteResolve);
98100
};
99-
}, [isResolved, resolving]);
101+
}, [outage, resolving]);
100102

101103
useEffect(() => {
102104
if (!id || !outage || outage.status === "resolved") return;
@@ -196,8 +198,7 @@ export default function OutageDetailsPage() {
196198
<RouteErrorState
197199
title="Error loading outage"
198200
description={error}
199-
actionLabel="Reload page"
200-
onAction={() => window.location.reload()}
201+
primaryAction={{ label: "Reload page", onClick: () => window.location.reload() }}
201202
/>
202203
);
203204
}
@@ -211,7 +212,6 @@ export default function OutageDetailsPage() {
211212
);
212213
}
213214

214-
const isResolved = outage.status === "resolved";
215215
const timeline = buildTimeline(outage);
216216

217217
return (

src/app/setting/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ export default function SettingsPage() {
454454
try {
455455
await api.get(ENDPOINTS.wallets.friendbot(address));
456456

457-
const statusUserId = wallet?.user_id ?? activeUserId || address;
457+
const statusUserId = wallet?.user_id ?? (activeUserId || address);
458458
const [statusResponse, balanceResponse] = await Promise.all([
459459
api.get<WalletStatus>(ENDPOINTS.wallets.status(statusUserId)),
460460
api.get<WalletBalance>(ENDPOINTS.wallets.balance(address)),

src/components/bulk-import/bulk-import-view.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ function parseCSV(text: string): ParsedCSV {
8686
return result;
8787
};
8888

89-
const headers = parseLine(lines[0]).map((h) => h.replace(/^"|"$/g, ""));
89+
const firstLine = lines[0];
90+
const headers = firstLine ? parseLine(firstLine).map((h) => h.replace(/^"|"$/g, "")) : [];
9091
const allRows = lines.slice(1).map(parseLine);
9192

9293
return {
@@ -202,7 +203,7 @@ async function buildPreview(file: File): Promise<PreviewState> {
202203
return { headers: [], rows: [], errors, warnings: [], totalRows: 0 };
203204
}
204205

205-
const headers = parsed.length > 0 ? Object.keys(parsed[0]) : [];
206+
const headers = parsed.length > 0 && parsed[0] ? Object.keys(parsed[0]) : [];
206207
const rows = parsed.slice(0, MAX_PREVIEW_ROWS).map((r) =>
207208
headers.map((h) => String(r[h] ?? ""))
208209
);

src/components/dashboard/SLATrendChart.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const SLATrendChart: React.FC<SLATrendChartProps> = ({ data, onPointClick }) =>
4444
<p className="text-sm text-gray-500 dark:text-gray-400">No trend data available.</p>
4545
</div>
4646
);
47+
}
4748

4849
return (
4950
<div className="rounded-xl bg-white dark:bg-slate-900 p-5 shadow-sm">

src/components/dashboard/sla-dashboard-view.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,16 @@ export default function SLADashboardView() {
5252
queryKey: ["dashboard-metrics", filters],
5353
queryFn: () => fetchDashboardMetrics(filters),
5454
staleTime: 30_000,
55-
structuralSharing: (oldData, newData) => {
56-
if (!oldData || !newData) return newData;
57-
if (oldData.sla_compliance_percentage === newData.sla_compliance_percentage &&
58-
oldData.penalties.total === newData.penalties.total &&
59-
oldData.rewards.total === newData.rewards.total) {
60-
return oldData;
55+
structuralSharing: (oldData: unknown, newData: unknown) => {
56+
if (!oldData || !newData) return newData as DashboardMetrics;
57+
const o = oldData as DashboardMetrics;
58+
const n = newData as DashboardMetrics;
59+
if (o.sla_compliance_percentage === n.sla_compliance_percentage &&
60+
o.penalties.total === n.penalties.total &&
61+
o.rewards.total === n.rewards.total) {
62+
return o;
6163
}
62-
return newData;
64+
return n;
6365
},
6466
});
6567

@@ -119,8 +121,7 @@ export default function SLADashboardView() {
119121
<RouteErrorState
120122
title="Dashboard unavailable"
121123
description="We could not load the latest analytics right now."
122-
actionLabel="Retry"
123-
onAction={() => void primary.refetch()}
124+
primaryAction={{ label: "Retry", onClick: () => void primary.refetch() }}
124125
/>
125126
);
126127
}

src/components/data-table.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ export function DataTable<TData, TValue>({
296296
const next = typeof updater === "function" ? updater(rowSelection ?? {}) : updater;
297297
onRowSelectionChange(next);
298298
},
299-
getRowId,
299+
getRowId: getRowId ?? ((row, index) => String(index)),
300300
manualPagination: !!onPaginationChange,
301301
manualSorting: !!onSortingChange,
302302
pageCount: pageCount ?? -1,
@@ -323,8 +323,8 @@ export function DataTable<TData, TValue>({
323323
estimateSize: () => ROW_ESTIMATED_HEIGHT[density] ?? 48,
324324
overscan: OVERSCAN,
325325
getItemKey: (index) => {
326-
const row = rows[index];
327-
return row?.id ?? String(index);
326+
const row = rows[index]!;
327+
return row.id ?? String(index);
328328
},
329329
});
330330

@@ -395,7 +395,7 @@ export function DataTable<TData, TValue>({
395395
</thead>
396396
<tbody style={{ display: 'block', height: `${totalSize}px`, position: 'relative' }}>
397397
{virtualRows.map((virtualRow) => {
398-
const row = rows[virtualRow.index];
398+
const row = rows[virtualRow.index]!;
399399
return (
400400
<tr
401401
key={row.id}

src/components/onboarding/OnboardingTour.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import { useCallback, useEffect, useRef, useState } from "react";
1212
import { usePathname, useRouter } from "next/navigation";
13-
import { driver, type Config, type Driver } from "driver.js";
13+
import { driver, type Config, type Driver, type DriveStep } from "driver.js";
1414
import "driver.js/dist/driver.css";
1515

1616
import { useI18n } from "@/i18n/i18n";
@@ -70,8 +70,9 @@ export default function OnboardingTour() {
7070
startedRef.current = true;
7171

7272
// Ensure we're on the first step's route before highlighting.
73-
if (pathnameRef.current !== TOUR_STEPS[0].route) {
74-
routerRef.current.push(TOUR_STEPS[0].route);
73+
const firstStep = TOUR_STEPS[0]!;
74+
if (pathnameRef.current !== firstStep.route) {
75+
routerRef.current.push(firstStep.route);
7576
}
7677

7778
const steps = TOUR_STEPS.map((step) => ({
@@ -80,9 +81,9 @@ export default function OnboardingTour() {
8081
title: resolveCopy(`onboarding.steps.${step.id}.title`, step.title),
8182
description: resolveCopy(`onboarding.steps.${step.id}.body`, step.body),
8283
side: step.side,
83-
align: step.align,
84+
align: step.align as "start" | "center" | "end" | undefined,
8485
},
85-
}));
86+
})) as DriveStep[];
8687

8788
const config: Config = {
8889
steps,
@@ -110,7 +111,8 @@ export default function OnboardingTour() {
110111
d.destroy(); // last step → finish
111112
return;
112113
}
113-
if (nextStep.route !== TOUR_STEPS[index].route) {
114+
const currentStep = TOUR_STEPS[index]!;
115+
if (nextStep.route !== currentStep.route) {
114116
routerRef.current.push(nextStep.route);
115117
}
116118
d.moveNext();
@@ -121,7 +123,8 @@ export default function OnboardingTour() {
121123
const index = d.getActiveIndex() ?? 0;
122124
const prevStep = TOUR_STEPS[index - 1];
123125
if (!prevStep) return;
124-
if (prevStep.route !== TOUR_STEPS[index].route) {
126+
const currentPrevStep = TOUR_STEPS[index]!;
127+
if (prevStep.route !== currentPrevStep.route) {
125128
routerRef.current.push(prevStep.route);
126129
}
127130
d.movePrevious();

src/components/outages/SLADisputesPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ interface Props {
3939
interface ResolvePayload {
4040
disputeId: string;
4141
action: "resolve" | "reject";
42-
note?: string;
42+
note?: string | undefined;
4343
}
4444

4545
export function SLADisputesPanel({

0 commit comments

Comments
 (0)