Adds four fields from the Organization Contact's Food_Co_op_Organizing
custom group to the Stage 0 (always-visible) section:
Date Incorporated (date, editable)
Name on Incorporation Certificate (text, editable)
Certificate of Incorporation (readonly; see note)
Equity share (currency, editable)
These live on the Organization Contact record, not on the Check-in
activity, so they read/write through a different code path:
- FieldConfig gains civiContactField, mutually exclusive with civiField
- /api/data extends the org Contact.get select to include them and
merges values into the prefill payload keyed by form-side name
- /api/submit splits incoming values: contact-bound fields go through
Contact.update (run first), activity-bound fields stay in the
Activity.create call (run second)
- FieldRenderer readonly branch now detects file-shaped values
({id, file_name}) and displays the filename rather than [object Object]
Certificate_of_Incorporation is wired readonly only: the form's
file-upload pipeline is not actually wired end-to-end (FileList drops
at JSON.stringify in onSubmit; no /api/upload endpoint exists). A
follow-up will close that gap.
Also adds scripts/inspect-org-custom-fields.mjs, a one-off introspection
script for dumping CustomField metadata when wiring a new group.
73 lines
2.1 KiB
JavaScript
73 lines
2.1 KiB
JavaScript
#!/usr/bin/env node
|
|
// scripts/inspect-org-custom-fields.mjs
|
|
//
|
|
// Dumps the CustomField metadata for the "Food_Co_op_Organizing" custom
|
|
// group (attached to Organization contacts) so we can wire the right
|
|
// machine names + types into config/form.ts.
|
|
//
|
|
// USAGE
|
|
// node --env-file=.env.local scripts/inspect-org-custom-fields.mjs
|
|
|
|
const GROUP = "Food_Co_op_Organizing";
|
|
|
|
async function civi(entity, action, params) {
|
|
const {
|
|
CIVI_BASE_URL,
|
|
CIVI_API_KEY,
|
|
CIVI_SITE_KEY,
|
|
CIVI_HTTP_AUTH_USER,
|
|
CIVI_HTTP_AUTH_PASS,
|
|
} = process.env;
|
|
if (!CIVI_BASE_URL || !CIVI_API_KEY || !CIVI_SITE_KEY) {
|
|
throw new Error("Missing CIVI_BASE_URL / CIVI_API_KEY / CIVI_SITE_KEY.");
|
|
}
|
|
const url = `${CIVI_BASE_URL}/civicrm/ajax/api4/${entity}/${action}`;
|
|
const headers = {
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
"X-Civi-Auth": `Bearer ${CIVI_API_KEY}`,
|
|
"X-Civi-Key": CIVI_SITE_KEY,
|
|
};
|
|
if (CIVI_HTTP_AUTH_USER && CIVI_HTTP_AUTH_PASS) {
|
|
headers["Authorization"] =
|
|
"Basic " +
|
|
Buffer.from(`${CIVI_HTTP_AUTH_USER}:${CIVI_HTTP_AUTH_PASS}`).toString("base64");
|
|
}
|
|
const res = await fetch(url, {
|
|
method: "POST",
|
|
headers,
|
|
body: new URLSearchParams({ params: JSON.stringify(params) }),
|
|
});
|
|
if (!res.ok) {
|
|
throw new Error(`${entity}.${action} HTTP ${res.status}: ${await res.text()}`);
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
const result = await civi("CustomField", "get", {
|
|
select: [
|
|
"name",
|
|
"label",
|
|
"data_type",
|
|
"html_type",
|
|
"is_active",
|
|
"option_group_id",
|
|
"custom_group_id.name",
|
|
"custom_group_id.extends",
|
|
],
|
|
where: [["custom_group_id.name", "=", GROUP]],
|
|
orderBy: { weight: "ASC" },
|
|
limit: 0,
|
|
});
|
|
|
|
const rows = result.values ?? [];
|
|
console.log(`Custom group: ${GROUP}`);
|
|
if (rows.length) {
|
|
console.log(`Extends: ${rows[0]["custom_group_id.extends"]}`);
|
|
}
|
|
console.log(`Found ${rows.length} fields:\n`);
|
|
for (const f of rows) {
|
|
console.log(
|
|
`- name=${f.name} label="${f.label}" data_type=${f.data_type} html_type=${f.html_type} option_group_id=${f.option_group_id ?? "-"} active=${f.is_active}`,
|
|
);
|
|
}
|