Rapport_React/src/modules/metricviews.js

379 lines
15 KiB
JavaScript

import { signedGet, isSuccess } from '@/api/client';
import { dropdownMap, fetchUserAttributes } from '@/api/dropdowns';
import {
DEFAULT_INTERVAL_VALUES,
INTERVAL_VALUES,
metricOptions,
parseCombinedMetrics,
splitHash,
stringifyCombinedMetrics,
toApiDate,
toDateInput,
VIEW_COMBINED_TYPES,
} from '@/helpers/metric';
function asArray(value) {
if (Array.isArray(value)) return value.filter((part) => part !== null && part !== undefined && part !== '');
return splitHash(value);
}
const metricviews = {
service: 'metric',
module: 'metric_view',
title: 'Metric View',
subtitle: 'Metric',
baseUrl: '/metricview',
listPath: '/metricviews',
defaultType: 'simple',
listFields: [
{ key: 'actions', title: 'Actions', buttons: ['edit', 'duplicate', 'delete'] },
{ key: 'name', title: 'Name', type: 'text' },
{ key: 'type', title: 'Type', type: 'text' },
{ key: 'roles', title: 'Roles', type: 'text' },
{ key: 'sort_order', title: 'Sort Order', type: 'number' },
{ key: 'validity_start', title: 'Validity start', type: 'date' },
{ key: 'validity_end', title: 'Validity end', type: 'date' },
{ key: 'agg_type', title: 'Aggregation type', type: 'text' },
{ key: 'status', title: 'Status', type: 'select' },
],
listButtons: [
{ title: 'Add A vs B', to: '/metricview/addnew?type=verses' },
{ title: 'Add Grouped', to: '/metricview/addnew?type=grouped' },
{ title: 'Add Simple', to: '/metricview/addnew?type=simple' },
],
mapItems: (items) =>
(items || []).map((item) => ({
...item,
roles: asArray(item.designations || item.roles).join(', '),
sort_order: item.sort_order ?? item.widget_sort_order ?? 0,
})),
formFields: async () => {
const [metrics, roles, contactRes, userAttrItems] = await Promise.all([
metricOptions(),
dropdownMap('ums', 'roles', (item) => item.name),
signedGet('contact', 'contactattribute/get_all'),
fetchUserAttributes(),
]);
const contactAttributes = {};
const contactItems = isSuccess(contactRes) ? contactRes.data?.items || [] : [];
contactItems.forEach((attr) => {
if (attr?.code) contactAttributes[attr.code] = attr.attribute || attr.code;
});
const userAttributes = {};
userAttrItems.forEach((attr) => {
if (!attr?.code || attr.status === 'disabled') return;
userAttributes[attr.code] = attr.attribute || attr.code;
});
const versesMetrics = { ...metrics, fixed: 'Fixed Value' };
return [
{ key: 'name', title: 'Name', type: 'text', required: true },
{
key: 'type',
title: 'Type',
type: 'select',
required: true,
values: { simple: 'Simple', grouped: 'Grouped', verses: 'A vs B' },
},
{ key: 'validity_start', title: 'Validity start', type: 'date', required: true },
{ key: 'validity_end', title: 'Validity end', type: 'date', required: true },
{ key: 'designations', title: 'Publish to Roles', type: 'multiselect', required: true, values: roles },
{ key: 'metric', title: 'Choose Metric', type: 'select', required: true, values: metrics, showIf: { type: 'simple' } },
{ key: 'display_unit', title: 'Display Unit', type: 'text', required: true, showIf: { type: 'simple' } },
{ key: 'metric_0', title: 'Choose Metric 1', type: 'select', required: true, values: metrics, showIf: { type: 'verses' } },
{ key: 'display_unit_0', title: 'Metric 1 Display Unit', type: 'text', required: true, showIf: { type: 'verses' } },
{ key: 'metric_1', title: 'Choose Metric 2', type: 'select', required: true, values: versesMetrics, showIf: { type: 'verses' } },
{ key: 'display_unit_1', title: 'Metric 2 Display Unit', type: 'text', required: true, showIf: { type: 'verses' } },
{ key: 'fixed_metric', title: 'Fixed Metric value if selected', type: 'text', required: true, showIf: { type: 'verses' } },
{ key: 'max_value_color', title: 'Max Value Color', type: 'color', showIf: { type: 'verses' } },
{ key: 'color_ranges', title: 'Color Ranges (%)', type: 'color_ranges', fullwidth: true, showIf: { type: 'verses' } },
{
key: 'list_chart_type',
title: 'List Chart Type',
type: 'select',
required: true,
showIf: { type: 'verses' },
values: {
donut: 'Donut',
progressbar: 'Progress Bar',
horizontal_barchart: 'Horizontal Bar Chart',
vertical_barchart: 'Vertical Bar Chart',
},
},
{
key: 'metrics',
title: 'Choose Metric',
type: 'mapping',
variant: 'grouped',
required: true,
fullwidth: true,
metrics,
showIf: { type: 'grouped' },
},
{ key: 'operation', title: 'Operation', type: 'select', required: true, values: { sum: 'Sum', avg: 'Avg', value_count: 'Count' } },
{
key: 'agg_type',
title: 'Aggregation Type',
type: 'select',
required: true,
values: { individual: 'Individual', team: 'Team' },
},
{
key: 'graphical_views',
title: 'Graphical views',
type: 'multiselect',
values: { progress: 'Progress', percentile: 'Percentile', pie: 'Pie chart', bar: 'Bar chart', line: 'Line chart' },
},
{
key: 'value_views',
title: 'Value views',
type: 'multiselect',
values: { value: 'Value' },
},
{
key: 'details_views',
title: 'Details views',
type: 'multiselect',
values: { tabular: 'Tabular', contacts: 'Doctor View', incremental: 'Incremental View' },
},
{
key: 'trend_views',
title: 'Trend views',
type: 'multiselect',
values: { bar: 'Bar chart', line: 'Line chart', tabular: 'Tabular' },
},
{
key: 'leaderboard_views',
title: 'My Team views',
type: 'multiselect',
values: { leaderboard: 'My Team View' },
},
{
key: 'scoreboard_views',
title: 'Leaderboard views',
type: 'multiselect',
values: { leaderboard: 'Leaderboard View' },
},
{
key: 'contacts_views',
title: 'Doctor views',
type: 'multiselect',
values: { contacts: 'Doctor View' },
},
{ key: 'doctor_view_name', title: 'Enter Doctor View Name', type: 'text' },
{ key: 'intervals', title: 'Intervals', type: 'multiselect', required: true, values: INTERVAL_VALUES },
{ key: 'default_interval', title: 'Default Interval', type: 'select', required: true, values: DEFAULT_INTERVAL_VALUES },
{
key: 'default_tab',
title: 'Default Tab',
type: 'select',
values: {
value: 'Value',
trend: 'Trend',
details: 'Detail',
leaderboard: 'My Team',
scoreboard: 'Leaderboard',
contacts: 'Doctor List',
incremental: 'Incremental',
},
},
{ key: 'widget_sort_order', title: 'Sort Order', type: 'number', required: true },
{ key: 'doctor_type', title: 'Doctor Type', type: 'text' },
{
key: 'combined_metrics',
title: 'Combined Metrics (if any)',
type: 'combined_metrics',
variant: 'view',
fullwidth: true,
metrics,
types: VIEW_COMBINED_TYPES,
},
{ key: 'report_roles', title: 'Data Report from Roles', type: 'multiselect', required: true, values: roles },
{ key: 'status', title: 'Status', type: 'select', required: true, values: { active: 'Active', disabled: 'Disabled' } },
{ key: 'show_positions', title: 'Show Positions', type: 'select', required: true, values: { yes: 'Yes', no: 'No' } },
{
key: 'show_positions_type',
title: 'Show Positions Type',
type: 'select',
required: true,
values: { all: 'All', loggedin: 'Logged In' },
},
{ key: 'contact_attributes', title: 'Include Doctor Attributes', type: 'multiselect', values: contactAttributes },
{
key: 'team_leaderboard_widget_roles',
title: 'Team Leaderboard Widget Roles',
type: 'multiselect',
values: roles,
},
{ key: 'show_user_attributes', title: 'Show User Attributes', type: 'yesno', required: true, default: 'no' },
{
key: 'user_attributes',
title: 'Include User Attributes',
type: 'multiselect',
values: userAttributes,
default: [],
},
{
key: 'stateheadwise_leaderboard',
title: 'Stateheadwise Leaderboard',
type: 'yesno',
required: true,
default: 'no',
},
];
},
beforeForm: (item) => {
const next = {
type: 'simple',
widget_sort_order: 0,
sort_order: 0,
show_positions: 'yes',
show_positions_type: 'all',
show_user_attributes: 'no',
user_attributes: [],
stateheadwise_leaderboard: 'no',
list_chart_type: 'progressbar',
value_views: ['value'],
default_tab: '',
team_leaderboard_widget_roles: [],
...item,
};
next.designations = asArray(next.designations);
next.report_roles = asArray(next.report_roles);
next.graphical_views = asArray(next.graphical_views);
next.details_views = asArray(next.details_views);
next.trend_views = asArray(next.trend_views);
next.leaderboard_views = asArray(next.leaderboard_views);
next.scoreboard_views = item && Object.prototype.hasOwnProperty.call(item, 'scoreboard_views')
? asArray(next.scoreboard_views)
: asArray(next.leaderboard_views);
next.value_views = item && Object.prototype.hasOwnProperty.call(item, 'value_views')
? asArray(next.value_views)
: ['value'];
next.contacts_views = asArray(next.contacts_views);
next.default_tab = next.default_tab || '';
next.intervals = asArray(next.intervals);
next.contact_attributes = asArray(next.contact_attributes);
next.team_leaderboard_widget_roles = asArray(
next.team_leaderboard_widget_roles || next.leaderboard_widget_roles || next.widget_roles,
);
next.show_user_attributes = ['yes', '1', 'true', true, 1].includes(next.show_user_attributes) ? 'yes' : 'no';
next.user_attributes = asArray(next.user_attributes);
if (next.user_attributes.length && next.show_user_attributes !== 'yes') {
next.show_user_attributes = 'yes';
}
next.stateheadwise_leaderboard = next.stateheadwise_leaderboard === 'yes' ? 'yes' : 'no';
next.combined_metrics = parseCombinedMetrics(next.combined_metrics);
next.validity_start = toDateInput(next.validity_start);
next.validity_end = toDateInput(next.validity_end);
if (next.sort_order === '' || next.sort_order == null) next.sort_order = next.widget_sort_order || 0;
if (next.widget_sort_order === '' || next.widget_sort_order == null) next.widget_sort_order = next.sort_order || 0;
if (next.show_positions) next.show_positions = String(next.show_positions).toLowerCase();
if (!Array.isArray(next.color_ranges)) next.color_ranges = [];
const metrics = Array.isArray(next.metrics) ? [...next.metrics] : [];
metrics.sort((a, b) => (Number(a?.sort_order) || 0) - (Number(b?.sort_order) || 0));
if (next.type === 'simple' && metrics[0]) {
next.metric = metrics[0].metric;
next.display_unit = metrics[0].display;
} else if (next.type === 'verses') {
next.metric_0 = metrics[0]?.metric || '';
next.display_unit_0 = metrics[0]?.display || '';
next.metric_1 = metrics[1]?.metric || '';
next.display_unit_1 = metrics[1]?.display || '';
if (!next.list_chart_type) next.list_chart_type = 'progressbar';
} else if (next.type === 'grouped') {
next.metrics = metrics.map((row) => ({
metric: row.metric || '',
display: row.display || '',
sort_order: row.sort_order ?? 0,
weight: row.weight ?? 1,
list_view: row.list_view || 'yes',
}));
}
return next;
},
beforeSave: (data) => {
const type = data.type || 'simple';
let metrics = [];
if (type === 'simple') {
metrics = [{ metric: data.metric, display: data.display_unit }];
} else if (type === 'verses') {
metrics = [
{ metric: data.metric_0, display: data.display_unit_0 },
{ metric: data.metric_1, display: data.display_unit_1 },
];
} else {
metrics = (data.metrics || [])
.filter((row) => row.metric)
.map((row) => ({
metric: row.metric,
display: row.display || '',
sort_order: Number(row.sort_order) || 0,
list_view: row.list_view || 'yes',
weight: row.weight === '' || row.weight == null ? 1 : Number(row.weight),
}));
}
const widgetSort = Number.parseInt(data.widget_sort_order, 10) || 0;
const payload = {
...data,
type,
metrics,
designations: asArray(data.designations),
report_roles: asArray(data.report_roles),
graphical_views: asArray(data.graphical_views),
details_views: asArray(data.details_views),
trend_views: asArray(data.trend_views),
leaderboard_views: asArray(data.leaderboard_views),
scoreboard_views: asArray(data.scoreboard_views),
value_views: asArray(data.value_views),
contacts_views: asArray(data.contacts_views),
default_tab: data.default_tab || '',
intervals: asArray(data.intervals),
contact_attributes: asArray(data.contact_attributes),
team_leaderboard_widget_roles: asArray(data.team_leaderboard_widget_roles),
show_user_attributes: data.show_user_attributes === 'yes' ? 'yes' : 'no',
user_attributes: asArray(data.user_attributes),
stateheadwise_leaderboard: data.stateheadwise_leaderboard === 'yes' ? 'yes' : 'no',
combined_metrics: stringifyCombinedMetrics(
(data.combined_metrics || [])
.filter((row) => row.type)
.map((row) => ({
type: row.type,
title: row.title || '',
fields: Array.isArray(row.fields) ? row.fields : [],
list_view: row.list_view || 'yes',
})),
),
widget_sort_order: widgetSort,
sort_order: widgetSort,
validity_start: toApiDate(data.validity_start),
validity_end: toApiDate(data.validity_end),
};
if (type === 'verses') {
payload.max_value_color = (data.max_value_color || '').trim();
payload.color_ranges = (data.color_ranges || [])
.filter((row) => row.min !== '' || row.max !== '' || row.color)
.map((row) => ({
min: Number(row.min) || 0,
max: Number(row.max) || 0,
color: row.color || '#000000',
}));
payload.list_chart_type = data.list_chart_type || 'progressbar';
} else {
delete payload.max_value_color;
delete payload.color_ranges;
delete payload.list_chart_type;
delete payload.fixed_metric;
}
delete payload.metric;
delete payload.display_unit;
delete payload.metric_0;
delete payload.display_unit_0;
delete payload.metric_1;
delete payload.display_unit_1;
if (payload.id === '' || payload.id == null) delete payload.id;
return payload;
},
};
export default metricviews;