89 lines
2.9 KiB
JavaScript
89 lines
2.9 KiB
JavaScript
// @ts-check
|
|
/**
|
|
* Map a CiviCRM CustomField row (as returned by APIv4 CustomField.get with
|
|
* `custom_group_id.name` and `custom_group_id.title` joined in) to a
|
|
* StaffFieldDescriptor for the staff report.
|
|
*
|
|
* Unknown data_type/html_type combinations fall back to "text" and the
|
|
* caller should log a warning naming the field so we notice schema
|
|
* additions we haven't modeled yet.
|
|
*
|
|
* Written as JS+JSDoc rather than TS so Node's built-in --test runner
|
|
* can import this file directly without any tooling. TypeScript callers
|
|
* still get full types via the JSDoc annotations.
|
|
*
|
|
* @typedef {import("../types/form").StaffFieldDescriptor} StaffFieldDescriptor
|
|
* @typedef {import("../types/form").StaffRenderKind} StaffRenderKind
|
|
*
|
|
* The CustomFieldRow shape isn't fully expressible in JSDoc because two of
|
|
* its property names contain dots (the APIv4 joined-field syntax). TypeScript
|
|
* callers declare their own typed interface for the row; here we use a
|
|
* permissive shape so the @ts-check pass doesn't complain about the dotted
|
|
* accesses below.
|
|
*
|
|
* @typedef {Record<string, unknown> & {
|
|
* name: string;
|
|
* label: string;
|
|
* data_type: string;
|
|
* html_type: string;
|
|
* option_group_id: number | null | undefined;
|
|
* weight: number;
|
|
* }} CustomFieldRow
|
|
*/
|
|
|
|
const ORG_GROUP_NAMES = new Set(["Food_Co_op_Organizing"]);
|
|
|
|
/**
|
|
* @param {CustomFieldRow} row
|
|
* @returns {StaffFieldDescriptor}
|
|
*/
|
|
export function mapCustomFieldRow(row) {
|
|
const groupName = /** @type {string} */ (row["custom_group_id.name"]);
|
|
const groupTitle = /** @type {string} */ (row["custom_group_id.title"]);
|
|
/** @type {"activity" | "org"} */
|
|
const groupKind = ORG_GROUP_NAMES.has(groupName) ? "org" : "activity";
|
|
const optionGroupId =
|
|
typeof row.option_group_id === "number" && row.option_group_id > 0
|
|
? row.option_group_id
|
|
: undefined;
|
|
|
|
const render = inferRender(row.data_type, row.html_type, optionGroupId);
|
|
|
|
return {
|
|
groupName,
|
|
groupTitle,
|
|
groupKind,
|
|
civiField: `${groupName}.${row.name}`,
|
|
name: row.name,
|
|
label: row.label,
|
|
render,
|
|
optionGroupId,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param {string} dataType
|
|
* @param {string} htmlType
|
|
* @param {number | undefined} optionGroupId
|
|
* @returns {StaffRenderKind}
|
|
*/
|
|
function inferRender(dataType, htmlType, optionGroupId) {
|
|
if (dataType === "Money") return "currency";
|
|
if (dataType === "Date") return "date";
|
|
if (dataType === "Timestamp") return "datetime";
|
|
if (dataType === "Boolean") return "boolean";
|
|
if (dataType === "File") return "file";
|
|
if (dataType === "Memo") return "longtext";
|
|
|
|
if (optionGroupId !== undefined) {
|
|
if (htmlType === "CheckBox" || htmlType === "Multi-Select") return "multiselect";
|
|
if (htmlType === "Select" || htmlType === "Radio" || htmlType === "Autocomplete-Select") {
|
|
return "select";
|
|
}
|
|
}
|
|
|
|
if (dataType === "Int" || dataType === "Float") return "number";
|
|
|
|
return "text";
|
|
}
|