Unify category tree pickers and prefer free-text technical AI fields.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
838e84056e
commit
8465a29ce1
@@ -1,12 +1,13 @@
|
||||
import { Pencil, Plus, X } from 'lucide-react'
|
||||
import type { InvoiceItemTemplate } from '../types/invoice'
|
||||
import { formatIrtInput, formatIrtPrice } from '../utils/irtPrice'
|
||||
import type { DraftAccount, DraftKeyPoint, DraftLineItem } from '../utils/invoiceDraft'
|
||||
import type { DraftAccount, DraftKeyPoint, DraftLineItem, DraftPaymentMethod } from '../utils/invoiceDraft'
|
||||
import {
|
||||
draftItemFromItemTemplate,
|
||||
emptyDraftAccount,
|
||||
emptyDraftItem,
|
||||
emptyDraftKeyPoint,
|
||||
emptyDraftPaymentMethod,
|
||||
} from '../utils/invoiceDraft'
|
||||
import tableStyles from '../pages/BusinessesPage.module.css'
|
||||
import styles from '../pages/BusinessInvoicesPage.module.css'
|
||||
@@ -17,15 +18,23 @@ function focusKeyPointInput(index: number) {
|
||||
el?.select()
|
||||
}
|
||||
|
||||
function focusPaymentMethodInput(index: number) {
|
||||
const el = document.querySelector<HTMLInputElement>(`input[data-payment-method-index="${index}"]`)
|
||||
el?.focus()
|
||||
el?.select()
|
||||
}
|
||||
|
||||
type Props = {
|
||||
itemTemplates: InvoiceItemTemplate[]
|
||||
items: DraftLineItem[]
|
||||
keyPoints: DraftKeyPoint[]
|
||||
paymentMethods: DraftPaymentMethod[]
|
||||
accounts: DraftAccount[]
|
||||
selectedItemTemplateId: string
|
||||
onSelectedItemTemplateId: (id: string) => void
|
||||
onItemsChange: (items: DraftLineItem[]) => void
|
||||
onKeyPointsChange: (points: DraftKeyPoint[]) => void
|
||||
onPaymentMethodsChange: (methods: DraftPaymentMethod[]) => void
|
||||
onAccountsChange: (accounts: DraftAccount[]) => void
|
||||
showItemTemplatePicker?: boolean
|
||||
}
|
||||
@@ -34,11 +43,13 @@ export function InvoiceDraftFields({
|
||||
itemTemplates,
|
||||
items,
|
||||
keyPoints,
|
||||
paymentMethods,
|
||||
accounts,
|
||||
selectedItemTemplateId,
|
||||
onSelectedItemTemplateId,
|
||||
onItemsChange,
|
||||
onKeyPointsChange,
|
||||
onPaymentMethodsChange,
|
||||
onAccountsChange,
|
||||
showItemTemplatePicker = true,
|
||||
}: Props) {
|
||||
@@ -239,6 +250,67 @@ export function InvoiceDraftFields({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.blockSection}>
|
||||
<div className={styles.blockHeader}>
|
||||
<h4 className={styles.blockTitle}>Payment methods</h4>
|
||||
<button
|
||||
type="button"
|
||||
className={`${tableStyles.btn} ${tableStyles.btnGhost}`}
|
||||
onClick={() => onPaymentMethodsChange([...paymentMethods, emptyDraftPaymentMethod()])}
|
||||
>
|
||||
<Plus size={16} />
|
||||
Add payment method
|
||||
</button>
|
||||
</div>
|
||||
{paymentMethods.length === 0 ? (
|
||||
<p className={styles.templateHint}>No payment methods yet.</p>
|
||||
) : (
|
||||
<div className={styles.repeatStack}>
|
||||
{paymentMethods.map((method, index) => (
|
||||
<div key={method.key} className={styles.repeatRow}>
|
||||
<div className={`${tableStyles.field} ${styles.flexGrow} ${styles.fieldNoLabel}`}>
|
||||
<input
|
||||
data-payment-method-index={index}
|
||||
value={method.text}
|
||||
onChange={(e) =>
|
||||
onPaymentMethodsChange(
|
||||
paymentMethods.map((m) =>
|
||||
m.key === method.key ? { ...m, text: e.target.value } : m,
|
||||
),
|
||||
)
|
||||
}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key !== 'Enter') return
|
||||
e.preventDefault()
|
||||
const next = index + 1
|
||||
if (next < paymentMethods.length) {
|
||||
focusPaymentMethodInput(next)
|
||||
return
|
||||
}
|
||||
onPaymentMethodsChange([...paymentMethods, emptyDraftPaymentMethod()])
|
||||
window.setTimeout(() => focusPaymentMethodInput(next), 0)
|
||||
}}
|
||||
placeholder="e.g. Cash, card transfer, or installments"
|
||||
aria-label={`Payment method ${index + 1}`}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.removeFieldBtn}
|
||||
onClick={() =>
|
||||
onPaymentMethodsChange(paymentMethods.filter((m) => m.key !== method.key))
|
||||
}
|
||||
aria-label="Remove payment method"
|
||||
title="Remove"
|
||||
>
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.blockSection}>
|
||||
<div className={styles.blockHeader}>
|
||||
<h4 className={styles.blockTitle}>Account numbers</h4>
|
||||
|
||||
Reference in New Issue
Block a user