feat(invoices): expose the automatic reminder kill switch in settings (#1476)

* feat(invoices): expose the automatic reminder kill switch in settings

The send_invoice_reminders column, API schema, and cron processor check
already existed, but no UI ever exposed the toggle. Add a switch in
Settings -> Fakturering (day thresholds fold away when off, values
preserved), and make the invoice detail Paminnelser card say reminders
are off instead of promising emails that will never be sent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(invoices): do not assume reminders enabled before settings load

CodeRabbit finding on PR 1476: with no company_settings row loaded, the
Paminnelser card defaulted to promising the reminder schedule. Track the
toggle as boolean | null and render no schedule text until the settings
row has actually resolved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-08-10 11:24:15 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 741cdcc60e
commit d4b0bd3df1
5 changed files with 81 additions and 48 deletions
+60 -41
View File
@@ -1,9 +1,12 @@
'use client'
import { useState } from 'react'
import { useTranslations } from 'next-intl'
import { Switch } from '@/components/ui/switch'
import {
SettingsGroup,
SettingsInput,
SettingsReveal,
SettingsRow,
SettingsTextarea,
} from '@/components/settings/SettingsRows'
@@ -15,6 +18,7 @@ interface InvoiceSettingsFormProps {
export function InvoiceSettingsForm({ settings }: InvoiceSettingsFormProps) {
const t = useTranslations('settings_invoice_form')
const [sendReminders, setSendReminders] = useState(settings.send_invoice_reminders ?? true)
return (
<>
<SettingsGroup label={t('heading')}>
@@ -101,50 +105,65 @@ export function InvoiceSettingsForm({ settings }: InvoiceSettingsFormProps) {
<SettingsGroup label={t('reminder_days_heading')} help={t('reminder_days_help')}>
<SettingsRow
label={t('reminder_days_level_1')}
htmlFor="reminder_days_level_1"
align="baseline"
label={t('send_reminders_label')}
htmlFor="send_invoice_reminders"
help={t('send_reminders_help')}
borderless={sendReminders}
>
<SettingsInput
id="reminder_days_level_1"
name="reminder_days_level_1"
type="number"
min="1"
max="365"
defaultValue={settings.reminder_days_level_1 ?? 15}
className="max-w-24 flex-none tabular-nums"
/>
</SettingsRow>
<SettingsRow
label={t('reminder_days_level_2')}
htmlFor="reminder_days_level_2"
align="baseline"
>
<SettingsInput
id="reminder_days_level_2"
name="reminder_days_level_2"
type="number"
min="1"
max="365"
defaultValue={settings.reminder_days_level_2 ?? 30}
className="max-w-24 flex-none tabular-nums"
/>
</SettingsRow>
<SettingsRow
label={t('reminder_days_level_3')}
htmlFor="reminder_days_level_3"
align="baseline"
>
<SettingsInput
id="reminder_days_level_3"
name="reminder_days_level_3"
type="number"
min="1"
max="365"
defaultValue={settings.reminder_days_level_3 ?? 45}
className="max-w-24 flex-none tabular-nums"
<Switch
id="send_invoice_reminders"
checked={sendReminders}
onCheckedChange={(v) => setSendReminders(v === true)}
/>
<input type="hidden" name="send_invoice_reminders" value={sendReminders ? 'true' : 'false'} />
</SettingsRow>
<SettingsReveal open={sendReminders}>
<SettingsRow
label={t('reminder_days_level_1')}
htmlFor="reminder_days_level_1"
align="baseline"
>
<SettingsInput
id="reminder_days_level_1"
name="reminder_days_level_1"
type="number"
min="1"
max="365"
defaultValue={settings.reminder_days_level_1 ?? 15}
className="max-w-24 flex-none tabular-nums"
/>
</SettingsRow>
<SettingsRow
label={t('reminder_days_level_2')}
htmlFor="reminder_days_level_2"
align="baseline"
>
<SettingsInput
id="reminder_days_level_2"
name="reminder_days_level_2"
type="number"
min="1"
max="365"
defaultValue={settings.reminder_days_level_2 ?? 30}
className="max-w-24 flex-none tabular-nums"
/>
</SettingsRow>
<SettingsRow
label={t('reminder_days_level_3')}
htmlFor="reminder_days_level_3"
align="baseline"
>
<SettingsInput
id="reminder_days_level_3"
name="reminder_days_level_3"
type="number"
min="1"
max="365"
defaultValue={settings.reminder_days_level_3 ?? 45}
className="max-w-24 flex-none tabular-nums"
/>
</SettingsRow>
</SettingsReveal>
</SettingsGroup>
</>
)
@@ -37,6 +37,7 @@ export function InvoicingSettingsContent() {
Number.parseInt(formData.get('reminder_days_level_2') as string) || 30,
reminder_days_level_3:
Number.parseInt(formData.get('reminder_days_level_3') as string) || 45,
send_invoice_reminders: formData.get('send_invoice_reminders') === 'true',
}
return {
updates,