fix(09-01): fix propertyAddress pre-seed and polish PreparePanel text fill UI
- TextFillForm: add initialData prop; buildInitialRows seeds rows from
pre-seeded data so propertyAddress row renders populated on mount
- PreparePanel: pass initialData={...} to TextFillForm so the lazy
useState in PreparePanel correctly flows through to the visible UI
- TextFillForm: replace AcroForm jargon instruction with friendly copy
- TextFillForm: add Field name / Value column headers for clear layout
- TextFillForm: improve spacing (py-1.5), softer remove button (gray→red on hover)
- TypeScript: npx tsc --noEmit passes clean
This commit is contained in:
@@ -151,7 +151,10 @@ export function PreparePanel({ docId, defaultEmail, clientName, currentStatus, a
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">Text fill fields</label>
|
<label className="block text-sm font-medium text-gray-700 mb-2">Text fill fields</label>
|
||||||
<TextFillForm onChange={setTextFillData} />
|
<TextFillForm
|
||||||
|
onChange={setTextFillData}
|
||||||
|
initialData={clientPropertyAddress ? { propertyAddress: clientPropertyAddress } : undefined}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -5,10 +5,19 @@ interface TextRow { label: string; value: string; }
|
|||||||
|
|
||||||
interface TextFillFormProps {
|
interface TextFillFormProps {
|
||||||
onChange: (data: Record<string, string>) => void;
|
onChange: (data: Record<string, string>) => void;
|
||||||
|
initialData?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TextFillForm({ onChange }: TextFillFormProps) {
|
function buildInitialRows(initialData?: Record<string, string>): TextRow[] {
|
||||||
const [rows, setRows] = useState<TextRow[]>([{ label: '', value: '' }]);
|
if (initialData && Object.keys(initialData).length > 0) {
|
||||||
|
const seeded = Object.entries(initialData).map(([label, value]) => ({ label, value }));
|
||||||
|
return [...seeded, { label: '', value: '' }];
|
||||||
|
}
|
||||||
|
return [{ label: '', value: '' }];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TextFillForm({ onChange, initialData }: TextFillFormProps) {
|
||||||
|
const [rows, setRows] = useState<TextRow[]>(() => buildInitialRows(initialData));
|
||||||
|
|
||||||
function updateRow(index: number, field: 'label' | 'value', val: string) {
|
function updateRow(index: number, field: 'label' | 'value', val: string) {
|
||||||
const next = rows.map((r, i) => i === index ? { ...r, [field]: val } : r);
|
const next = rows.map((r, i) => i === index ? { ...r, [field]: val } : r);
|
||||||
@@ -29,26 +38,31 @@ export function TextFillForm({ onChange }: TextFillFormProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-xs text-gray-500">
|
<p className="text-xs text-gray-400 mt-0.5">
|
||||||
Field label = AcroForm field name in the PDF (e.g. "PropertyAddress"). Leave blank to skip.
|
Pre-fill text fields in the PDF before sending. Leave blank to skip a field.
|
||||||
</p>
|
</p>
|
||||||
|
<div className="flex gap-2 items-center px-1">
|
||||||
|
<span className="flex-1 text-xs font-medium text-gray-500 uppercase tracking-wide">Field name</span>
|
||||||
|
<span className="flex-1 text-xs font-medium text-gray-500 uppercase tracking-wide">Value</span>
|
||||||
|
<span className="w-6" />
|
||||||
|
</div>
|
||||||
{rows.map((row, i) => (
|
{rows.map((row, i) => (
|
||||||
<div key={i} className="flex gap-2 items-center">
|
<div key={i} className="flex gap-2 items-center">
|
||||||
<input
|
<input
|
||||||
placeholder="Field label"
|
placeholder="e.g. PropertyAddress"
|
||||||
value={row.label}
|
value={row.label}
|
||||||
onChange={e => updateRow(i, 'label', e.target.value)}
|
onChange={e => updateRow(i, 'label', e.target.value)}
|
||||||
className="flex-1 border rounded px-2 py-1 text-sm"
|
className="flex-1 border rounded px-2 py-1.5 text-sm focus:border-[var(--gold)] focus:ring-[var(--gold)]"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
placeholder="Value"
|
placeholder="Value to fill in"
|
||||||
value={row.value}
|
value={row.value}
|
||||||
onChange={e => updateRow(i, 'value', e.target.value)}
|
onChange={e => updateRow(i, 'value', e.target.value)}
|
||||||
className="flex-1 border rounded px-2 py-1 text-sm"
|
className="flex-1 border rounded px-2 py-1.5 text-sm focus:border-[var(--gold)] focus:ring-[var(--gold)]"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => removeRow(i)}
|
onClick={() => removeRow(i)}
|
||||||
className="text-red-400 hover:text-red-600 text-sm px-1"
|
className="w-6 text-gray-300 hover:text-red-500 text-base leading-none flex items-center justify-center"
|
||||||
aria-label="Remove row"
|
aria-label="Remove row"
|
||||||
type="button"
|
type="button"
|
||||||
>×</button>
|
>×</button>
|
||||||
@@ -57,7 +71,7 @@ export function TextFillForm({ onChange }: TextFillFormProps) {
|
|||||||
{rows.length < 10 && (
|
{rows.length < 10 && (
|
||||||
<button
|
<button
|
||||||
onClick={addRow}
|
onClick={addRow}
|
||||||
className="text-blue-600 hover:text-blue-800 text-sm"
|
className="text-sm text-gray-500 hover:text-gray-700"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
+ Add field
|
+ Add field
|
||||||
|
|||||||
Reference in New Issue
Block a user