Add bank account templates and default invoice payment text.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
8465a29ce1
commit
ff419603bf
@@ -1,10 +1,11 @@
|
||||
import { Pencil, Plus, X } from 'lucide-react'
|
||||
import type { ReactNode } from 'react'
|
||||
import { useT } from '../i18n/useT'
|
||||
import type { InvoiceItemTemplate } from '../types/invoice'
|
||||
import type { InvoiceAccountTemplate, InvoiceItemTemplate } from '../types/invoice'
|
||||
import { formatIrtInput } from '../utils/irtPrice'
|
||||
import type { DraftAccount, DraftKeyPoint, DraftLineItem, DraftPaymentMethod } from '../utils/invoiceDraft'
|
||||
import {
|
||||
draftAccountFromAccountTemplate,
|
||||
draftItemFromItemTemplate,
|
||||
emptyDraftAccount,
|
||||
emptyDraftItem,
|
||||
@@ -28,34 +29,42 @@ function focusPaymentMethodInput(index: number) {
|
||||
|
||||
type Props = {
|
||||
itemTemplates: InvoiceItemTemplate[]
|
||||
accountTemplates: InvoiceAccountTemplate[]
|
||||
items: DraftLineItem[]
|
||||
keyPoints: DraftKeyPoint[]
|
||||
paymentMethods: DraftPaymentMethod[]
|
||||
accounts: DraftAccount[]
|
||||
selectedItemTemplateId: string
|
||||
onSelectedItemTemplateId: (id: string) => void
|
||||
selectedAccountTemplateId: string
|
||||
onSelectedAccountTemplateId: (id: string) => void
|
||||
onItemsChange: (items: DraftLineItem[]) => void
|
||||
onKeyPointsChange: (points: DraftKeyPoint[]) => void
|
||||
onPaymentMethodsChange: (methods: DraftPaymentMethod[]) => void
|
||||
onAccountsChange: (accounts: DraftAccount[]) => void
|
||||
showItemTemplatePicker?: boolean
|
||||
showAccountTemplatePicker?: boolean
|
||||
/** Rendered after line items (before key points / accounts), e.g. totals row. */
|
||||
afterItems?: ReactNode
|
||||
}
|
||||
|
||||
export function InvoiceDraftFields({
|
||||
itemTemplates,
|
||||
accountTemplates,
|
||||
items,
|
||||
keyPoints,
|
||||
paymentMethods,
|
||||
accounts,
|
||||
selectedItemTemplateId,
|
||||
onSelectedItemTemplateId,
|
||||
selectedAccountTemplateId,
|
||||
onSelectedAccountTemplateId,
|
||||
onItemsChange,
|
||||
onKeyPointsChange,
|
||||
onPaymentMethodsChange,
|
||||
onAccountsChange,
|
||||
showItemTemplatePicker = true,
|
||||
showAccountTemplatePicker = true,
|
||||
afterItems,
|
||||
}: Props) {
|
||||
const t = useT()
|
||||
@@ -81,6 +90,13 @@ export function InvoiceDraftFields({
|
||||
onSelectedItemTemplateId('')
|
||||
}
|
||||
|
||||
function addFromAccountTemplate() {
|
||||
const template = accountTemplates.find((entry) => entry.id === selectedAccountTemplateId)
|
||||
if (!template) return
|
||||
onAccountsChange([...accounts, draftAccountFromAccountTemplate(template)])
|
||||
onSelectedAccountTemplateId('')
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.itemsStack}>
|
||||
@@ -323,14 +339,44 @@ export function InvoiceDraftFields({
|
||||
<div className={styles.blockSection}>
|
||||
<div className={styles.blockHeader}>
|
||||
<h4 className={styles.blockTitle}>{t('invoiceDraft.accounts')}</h4>
|
||||
<button
|
||||
type="button"
|
||||
className={`${formStyles.btn} ${formStyles.btnGhost}`}
|
||||
onClick={() => onAccountsChange([...accounts, emptyDraftAccount()])}
|
||||
>
|
||||
<Plus size={16} />
|
||||
{t('invoiceDraft.addAccount')}
|
||||
</button>
|
||||
<div className={styles.blockHeaderActions}>
|
||||
{showAccountTemplatePicker ? (
|
||||
<div className={styles.itemActionsLeft}>
|
||||
<select
|
||||
id="account-template-pick"
|
||||
className={styles.compactSelect}
|
||||
value={selectedAccountTemplateId}
|
||||
onChange={(e) => onSelectedAccountTemplateId(e.target.value)}
|
||||
aria-label={t('invoiceDraft.addFromAccountTemplateAria')}
|
||||
>
|
||||
<option value="">{t('invoiceDraft.addFromAccountTemplate')}</option>
|
||||
{accountTemplates.map((template) => (
|
||||
<option key={template.id} value={template.id}>
|
||||
{template.bankName}
|
||||
{template.accountHolderName ? ` — ${template.accountHolderName}` : ''}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
type="button"
|
||||
className={`${formStyles.btn} ${formStyles.btnGhost} ${styles.compactBtn}`}
|
||||
onClick={addFromAccountTemplate}
|
||||
disabled={!selectedAccountTemplateId}
|
||||
>
|
||||
<Plus size={14} />
|
||||
{t('invoiceDraft.add')}
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
className={`${formStyles.btn} ${formStyles.btnGhost}`}
|
||||
onClick={() => onAccountsChange([...accounts, emptyDraftAccount()])}
|
||||
>
|
||||
<Plus size={16} />
|
||||
{t('invoiceDraft.addAccount')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{accounts.length === 0 ? (
|
||||
<p className={styles.templateHint}>{t('invoiceDraft.noAccounts')}</p>
|
||||
|
||||
Reference in New Issue
Block a user