Skip to content

Commit 4aca755

Browse files
committed
fix(payouts): prevent crash when preview has zero recipients
Backend: initialise BatchPreview.Lines to []BatchPreviewLine{} so it serialises as [] not null when no approved recipients exist. Frontend: guard all p.lines accesses with ?? [] and mark the type as BatchPreviewLine[] | null so the compiler enforces null-checks going forward. Fixes 'can't access property length, V.lines is null' crash on /steward/payouts.
1 parent e95894c commit 4aca755

2 files changed

Lines changed: 8 additions & 5 deletions

File tree

internal/service/payout.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ func (s *PayoutService) Preview() (*BatchPreview, error) {
107107
}
108108

109109
weekStart := models.WeekStartOf(time.Now()).AddDate(0, 0, -7)
110-
preview := &BatchPreview{WeekStart: weekStart.Format("2006-01-02")}
110+
preview := &BatchPreview{
111+
WeekStart: weekStart.Format("2006-01-02"),
112+
Lines: []BatchPreviewLine{},
113+
}
111114

112115
for _, r := range recipients {
113116
line := BatchPreviewLine{

web/app/src/routes/steward/StewardPayouts.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type BatchPreviewLine = {
1818

1919
type BatchPreview = {
2020
weekStart: string
21-
lines: BatchPreviewLine[]
21+
lines: BatchPreviewLine[] | null
2222
totalKobo: number
2323
eligible: number
2424
skipped: number
@@ -173,7 +173,7 @@ export function StewardPayouts() {
173173
<div className="w-16 h-3 rounded bg-[var(--color-cream-2)]" />
174174
</div>
175175
))
176-
: p?.lines.length === 0
176+
: (p?.lines ?? []).length === 0
177177
? (
178178
<div className="px-5 py-8 text-center">
179179
<p className="text-[13px] font-medium text-[var(--color-indigo)]">No approved recipients yet</p>
@@ -182,7 +182,7 @@ export function StewardPayouts() {
182182
</p>
183183
</div>
184184
)
185-
: p?.lines.map((line, i) => {
185+
: (p?.lines ?? []).map((line, i) => {
186186
const skip = line.skipReason ? SKIP_LABELS[line.skipReason] : null
187187
return (
188188
<motion.div
@@ -267,7 +267,7 @@ export function StewardPayouts() {
267267
<>
268268
{!p || preview.isLoading ? (
269269
<p className="text-[11px] text-[var(--color-stone)] flex-1">Calculating eligible recipients…</p>
270-
) : p.lines.length === 0 ? (
270+
) : (p.lines ?? []).length === 0 ? (
271271
<p className="text-[11px] text-[var(--color-stone)] flex-1">
272272
No recipients to pay out yet. Approve applications on the{' '}
273273
<Link to="/steward" className="underline underline-offset-2 text-[var(--color-indigo)]">Queue</Link>{' '}

0 commit comments

Comments
 (0)