@kahitsan/ksui 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/composite/ComboBox.tsx +615 -0
- package/src/components/composite/picker-engine.ts +158 -0
- package/src/components/composite/picker-types.ts +25 -0
- package/src/index.ts +14 -10
- package/src/components/composite/ClientPicker.tsx +0 -86
- package/src/components/composite/EntityPicker.tsx +0 -363
- package/src/components/composite/PayeePicker.tsx +0 -91
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
// PayeePicker — the payee preset of EntityPicker. A searchable combobox for the
|
|
2
|
-
// "Paid to" / "Received from" / "Payable to" field, backed by the sibling payees
|
|
3
|
-
// plugin's /api/payees. All the popup mechanics live in EntityPicker; this file
|
|
4
|
-
// only wires the payee endpoint, option shape, icon, and create-as-kind.
|
|
5
|
-
//
|
|
6
|
-
// Public API is unchanged from the standalone version, so existing callers keep
|
|
7
|
-
// working. Degrades gracefully — a missing payees plugin surfaces a notice and
|
|
8
|
-
// the free-text fallback (selectedName) keeps the trigger usable.
|
|
9
|
-
|
|
10
|
-
import { type JSX } from "solid-js";
|
|
11
|
-
import Store from "lucide-solid/icons/store";
|
|
12
|
-
import EntityPicker from "./EntityPicker";
|
|
13
|
-
|
|
14
|
-
export type PayeeKind = "vendor" | "customer" | "both";
|
|
15
|
-
|
|
16
|
-
export interface PayeeOption {
|
|
17
|
-
id: number;
|
|
18
|
-
name: string;
|
|
19
|
-
kind: PayeeKind;
|
|
20
|
-
default_subcategory?: string | null;
|
|
21
|
-
notes?: string | null;
|
|
22
|
-
is_active?: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface PayeePickerProps {
|
|
26
|
-
selected: PayeeOption | null;
|
|
27
|
-
selectedName?: string | null;
|
|
28
|
-
kind?: PayeeKind;
|
|
29
|
-
createAsKind?: PayeeKind;
|
|
30
|
-
placeholder?: string;
|
|
31
|
-
onChange: (next: PayeeOption | null) => void;
|
|
32
|
-
disabled?: boolean;
|
|
33
|
-
testIdPrefix?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async function searchPayees(query: string, kind?: PayeeKind): Promise<PayeeOption[]> {
|
|
37
|
-
const params = new URLSearchParams({ status: "active", limit: "20" });
|
|
38
|
-
if (query) params.set("search", query);
|
|
39
|
-
if (kind) params.set("kind", kind);
|
|
40
|
-
const r = await fetch(`/api/payees?${params.toString()}`, { credentials: "include" });
|
|
41
|
-
if (!r.ok) {
|
|
42
|
-
throw new Error(
|
|
43
|
-
r.status === 403
|
|
44
|
-
? "Permission denied"
|
|
45
|
-
: r.status === 404
|
|
46
|
-
? "Payees module isn't available — type a name instead"
|
|
47
|
-
: "Failed to load",
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
const json = await r.json();
|
|
51
|
-
return (json.data || []) as PayeeOption[];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function createPayee(name: string, kind: PayeeKind): Promise<PayeeOption> {
|
|
55
|
-
const res = await fetch("/api/payees", {
|
|
56
|
-
method: "POST",
|
|
57
|
-
credentials: "include",
|
|
58
|
-
headers: { "Content-Type": "application/json" },
|
|
59
|
-
body: JSON.stringify({ name, kind }),
|
|
60
|
-
});
|
|
61
|
-
if (!res.ok && res.status !== 200) {
|
|
62
|
-
const body = await res.json().catch(() => ({ error: "Failed to create payee" }));
|
|
63
|
-
throw new Error(body.error || "Failed to create payee");
|
|
64
|
-
}
|
|
65
|
-
return (await res.json()) as PayeeOption;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function payeeSecondary(p: PayeeOption): string | null {
|
|
69
|
-
if (!p.default_subcategory && p.kind === "vendor") return null;
|
|
70
|
-
return [p.kind === "vendor" ? null : p.kind, p.default_subcategory].filter(Boolean).join(" · ") || null;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export default function PayeePicker(props: PayeePickerProps): JSX.Element {
|
|
74
|
-
return (
|
|
75
|
-
<EntityPicker<PayeeOption>
|
|
76
|
-
selected={props.selected}
|
|
77
|
-
selectedName={props.selectedName}
|
|
78
|
-
onChange={props.onChange}
|
|
79
|
-
search={(q) => searchPayees(q, props.kind)}
|
|
80
|
-
onCreate={(name) => createPayee(name, props.createAsKind ?? props.kind ?? "vendor")}
|
|
81
|
-
idOf={(p) => p.id}
|
|
82
|
-
labelOf={(p) => p.name}
|
|
83
|
-
secondaryOf={payeeSecondary}
|
|
84
|
-
icon={Store}
|
|
85
|
-
noun="payee"
|
|
86
|
-
placeholder={props.placeholder}
|
|
87
|
-
disabled={props.disabled}
|
|
88
|
-
testIdPrefix={props.testIdPrefix ?? "payee-picker"}
|
|
89
|
-
/>
|
|
90
|
-
);
|
|
91
|
-
}
|