refactor(bill-modal): extract TemplateSection (BM2, 7/n)

The save-as-template toggle + name input move to their own presentational
component. Behavior-preserving — BillModal 1105 -> 1090 lines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
null 2026-07-03 19:23:57 -05:00
parent ad68d965b6
commit 20b46c81df
2 changed files with 47 additions and 24 deletions

View File

@ -23,6 +23,7 @@ import PaymentHistoryList from '@/components/bill-modal/PaymentHistoryList';
import PaymentFormFields from '@/components/bill-modal/PaymentFormFields';
import UnmatchDialogs from '@/components/bill-modal/UnmatchDialogs';
import LinkedTransactionsSection from '@/components/bill-modal/LinkedTransactionsSection';
import TemplateSection from '@/components/bill-modal/TemplateSection';
import { transactionTitle, isSimilarPayee } from '@/components/bill-modal/transactionDisplay';
import {
BILLING_SCHEDULE_OPTIONS,
@ -916,30 +917,14 @@ export default function BillModal({ bill, initialBill, categories, onClose, onSa
/>
</div>
<div className="col-span-2 rounded-lg border border-border/60 bg-muted/20 p-3">
<label className="flex items-center gap-2.5 cursor-pointer group">
<input
type="checkbox"
checked={saveTemplate}
onChange={e => setSaveTemplate(e.target.checked)}
className="h-4 w-4 rounded border-border accent-primary"
/>
<span className="text-sm text-muted-foreground group-hover:text-foreground transition-colors">
Save this setup as a reusable template
</span>
</label>
{saveTemplate && (
<div className="mt-2 space-y-1.5">
<Label className="text-xs uppercase tracking-wider text-muted-foreground">Template Name</Label>
<Input
className={inp}
value={templateName}
onChange={e => setTemplateName(e.target.value)}
placeholder={name || 'My bill template'}
/>
</div>
)}
</div>
<TemplateSection
inp={inp}
saveTemplate={saveTemplate}
setSaveTemplate={setSaveTemplate}
templateName={templateName}
setTemplateName={setTemplateName}
namePlaceholder={name}
/>
</div>
</form>

View File

@ -0,0 +1,38 @@
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
// "Save this setup as a reusable template" toggle + optional template name.
// Presentational the parent owns the state and performs the save.
export default function TemplateSection({
inp,
saveTemplate, setSaveTemplate,
templateName, setTemplateName,
namePlaceholder,
}) {
return (
<div className="col-span-2 rounded-lg border border-border/60 bg-muted/20 p-3">
<label className="flex items-center gap-2.5 cursor-pointer group">
<input
type="checkbox"
checked={saveTemplate}
onChange={e => setSaveTemplate(e.target.checked)}
className="h-4 w-4 rounded border-border accent-primary"
/>
<span className="text-sm text-muted-foreground group-hover:text-foreground transition-colors">
Save this setup as a reusable template
</span>
</label>
{saveTemplate && (
<div className="mt-2 space-y-1.5">
<Label className="text-xs uppercase tracking-wider text-muted-foreground">Template Name</Label>
<Input
className={inp}
value={templateName}
onChange={e => setTemplateName(e.target.value)}
placeholder={namePlaceholder || 'My bill template'}
/>
</div>
)}
</div>
);
}