mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-07-17 11:28:47 +02:00
Fix all 20 pre-existing type errors; typecheck now green
- ui/chart.tsx: recharts 3 stopped exposing tooltip/legend content props on its public types; declare the ChartPayloadItem shape we consume - base-ui Select onValueChange passes string|null: guard null in BillingCycleSelector, PasteImportModal, TransactionModal - type the untyped api.get calls (cycles, categories) - push-notifications: back the VAPID key with an explicit ArrayBuffer so it satisfies BufferSource under TS 5.9 Unblocks gating CI on pnpm typecheck. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,7 @@ export default function BillingCycleSelector({ value, onChange }: Props) {
|
|||||||
const [cycles, setCycles] = useState<CycleOption[]>([]);
|
const [cycles, setCycles] = useState<CycleOption[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api.get('/transactions/cycles').then((r) => setCycles(r.data));
|
api.get<CycleOption[]>('/transactions/cycles').then((r) => setCycles(r.data));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const selectedKey = value ? `${value.year}-${value.month}` : 'all';
|
const selectedKey = value ? `${value.year}-${value.month}` : 'all';
|
||||||
@@ -37,7 +37,7 @@ export default function BillingCycleSelector({ value, onChange }: Props) {
|
|||||||
<Select
|
<Select
|
||||||
value={selectedKey}
|
value={selectedKey}
|
||||||
onValueChange={(val) => {
|
onValueChange={(val) => {
|
||||||
if (val === 'all') {
|
if (!val || val === 'all') {
|
||||||
onChange(null);
|
onChange(null);
|
||||||
} else {
|
} else {
|
||||||
const [y, m] = val.split('-').map(Number);
|
const [y, m] = val.split('-').map(Number);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export default function PasteImportModal({ onClose, onImported }: Props) {
|
|||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Bank</Label>
|
<Label>Bank</Label>
|
||||||
<Select value={bank} onValueChange={setBank}>
|
<Select value={bank} onValueChange={(v) => v && setBank(v)}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
@@ -74,7 +74,7 @@ export default function PasteImportModal({ onClose, onImported }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Source</Label>
|
<Label>Source</Label>
|
||||||
<Select value={source} onValueChange={setSource}>
|
<Select value={source} onValueChange={(v) => v && setSource(v)}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ export default function TransactionModal({ transaction, source, onClose, onSaved
|
|||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api.get('/categories/').then((r) => {
|
api.get<Category[]>('/categories/').then((r) => {
|
||||||
const sorted = [...r.data].sort((a: Category, b: Category) => a.name.localeCompare(b.name));
|
const sorted = [...r.data].sort((a, b) => a.name.localeCompare(b.name));
|
||||||
setCategories(sorted);
|
setCategories(sorted);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@@ -144,7 +144,7 @@ export default function TransactionModal({ transaction, source, onClose, onSaved
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Currency</Label>
|
<Label>Currency</Label>
|
||||||
<Select value={form.currency} onValueChange={(v) => setForm({ ...form, currency: v })}>
|
<Select value={form.currency} onValueChange={(v) => v && setForm({ ...form, currency: v })}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
@@ -166,7 +166,7 @@ export default function TransactionModal({ transaction, source, onClose, onSaved
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Type</Label>
|
<Label>Type</Label>
|
||||||
<Select value={form.transaction_type} onValueChange={(v) => setForm({ ...form, transaction_type: v })}>
|
<Select value={form.transaction_type} onValueChange={(v) => v && setForm({ ...form, transaction_type: v })}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
@@ -180,7 +180,7 @@ export default function TransactionModal({ transaction, source, onClose, onSaved
|
|||||||
<Label>Category</Label>
|
<Label>Category</Label>
|
||||||
<Select
|
<Select
|
||||||
value={form.category_id ? String(form.category_id) : 'auto'}
|
value={form.category_id ? String(form.category_id) : 'auto'}
|
||||||
onValueChange={(v) => setForm({ ...form, category_id: v === 'auto' ? '' : v })}
|
onValueChange={(v) => setForm({ ...form, category_id: v && v !== 'auto' ? v : '' })}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue>
|
<SelectValue>
|
||||||
@@ -201,7 +201,7 @@ export default function TransactionModal({ transaction, source, onClose, onSaved
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Bank</Label>
|
<Label>Bank</Label>
|
||||||
<Select value={form.bank} onValueChange={(v) => setForm({ ...form, bank: v })}>
|
<Select value={form.bank} onValueChange={(v) => v && setForm({ ...form, bank: v })}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
|
|||||||
@@ -104,6 +104,17 @@ ${colorConfig
|
|||||||
|
|
||||||
const ChartTooltip = RechartsPrimitive.Tooltip
|
const ChartTooltip = RechartsPrimitive.Tooltip
|
||||||
|
|
||||||
|
// recharts 3 no longer exposes the tooltip/legend content props on its public
|
||||||
|
// component types; declare the shape we actually consume.
|
||||||
|
type ChartPayloadItem = {
|
||||||
|
dataKey?: string | number
|
||||||
|
name?: string | number
|
||||||
|
value?: number | string
|
||||||
|
color?: string
|
||||||
|
type?: string
|
||||||
|
payload?: Record<string, unknown> & { fill?: string }
|
||||||
|
}
|
||||||
|
|
||||||
function ChartTooltipContent({
|
function ChartTooltipContent({
|
||||||
active,
|
active,
|
||||||
payload,
|
payload,
|
||||||
@@ -118,8 +129,23 @@ function ChartTooltipContent({
|
|||||||
color,
|
color,
|
||||||
nameKey,
|
nameKey,
|
||||||
labelKey,
|
labelKey,
|
||||||
}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
}: React.ComponentProps<"div"> & {
|
||||||
React.ComponentProps<"div"> & {
|
active?: boolean
|
||||||
|
payload?: ChartPayloadItem[]
|
||||||
|
label?: string | number
|
||||||
|
labelFormatter?: (
|
||||||
|
value: string | number,
|
||||||
|
payload: ChartPayloadItem[]
|
||||||
|
) => React.ReactNode
|
||||||
|
labelClassName?: string
|
||||||
|
formatter?: (
|
||||||
|
value: number | string,
|
||||||
|
name: string | number,
|
||||||
|
item: ChartPayloadItem,
|
||||||
|
index: number,
|
||||||
|
payload: unknown
|
||||||
|
) => React.ReactNode
|
||||||
|
color?: string
|
||||||
hideLabel?: boolean
|
hideLabel?: boolean
|
||||||
hideIndicator?: boolean
|
hideIndicator?: boolean
|
||||||
indicator?: "line" | "dot" | "dashed"
|
indicator?: "line" | "dot" | "dashed"
|
||||||
@@ -144,7 +170,7 @@ function ChartTooltipContent({
|
|||||||
if (labelFormatter) {
|
if (labelFormatter) {
|
||||||
return (
|
return (
|
||||||
<div className={cn("font-medium", labelClassName)}>
|
<div className={cn("font-medium", labelClassName)}>
|
||||||
{labelFormatter(value, payload)}
|
{labelFormatter(value as string | number, payload)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -184,7 +210,7 @@ function ChartTooltipContent({
|
|||||||
.map((item, index) => {
|
.map((item, index) => {
|
||||||
const key = `${nameKey || item.name || item.dataKey || "value"}`
|
const key = `${nameKey || item.name || item.dataKey || "value"}`
|
||||||
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||||
const indicatorColor = color || item.payload.fill || item.color
|
const indicatorColor = color || item.payload?.fill || item.color
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -258,8 +284,9 @@ function ChartLegendContent({
|
|||||||
payload,
|
payload,
|
||||||
verticalAlign = "bottom",
|
verticalAlign = "bottom",
|
||||||
nameKey,
|
nameKey,
|
||||||
}: React.ComponentProps<"div"> &
|
}: React.ComponentProps<"div"> & {
|
||||||
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
payload?: ChartPayloadItem[]
|
||||||
|
verticalAlign?: "top" | "middle" | "bottom"
|
||||||
hideIcon?: boolean
|
hideIcon?: boolean
|
||||||
nameKey?: string
|
nameKey?: string
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
|
|
||||||
function urlBase64ToUint8Array(base64String: string): Uint8Array {
|
function urlBase64ToUint8Array(base64String: string): Uint8Array<ArrayBuffer> {
|
||||||
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
||||||
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
|
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
|
||||||
const rawData = window.atob(base64);
|
const rawData = window.atob(base64);
|
||||||
const outputArray = new Uint8Array(rawData.length);
|
// Explicit ArrayBuffer backing so the result satisfies BufferSource.
|
||||||
|
const outputArray = new Uint8Array(new ArrayBuffer(rawData.length));
|
||||||
for (let i = 0; i < rawData.length; ++i) {
|
for (let i = 0; i < rawData.length; ++i) {
|
||||||
outputArray[i] = rawData.charCodeAt(i);
|
outputArray[i] = rawData.charCodeAt(i);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user