Rapport_React/src/modules/milestones.js

421 lines
16 KiB
JavaScript

import { signedGet, isSuccess } from '@/api/client';
import { dropdownMap } from '@/api/dropdowns';
import { metricOptions, toDateInput } from '@/helpers/metric';
const STATUS = { active: 'Active', disabled: 'Disabled' };
const YES_NO = { yes: 'Yes', no: 'No' };
const MANAGER_LEVELS = {
l1manager: 'L1 Manager',
l2manager: 'L2 Manager',
l3manager: 'L3 Manager',
l4manager: 'L4 Manager',
};
const DAYS = {
MON: 'Monday',
TUE: 'Tuesday',
WED: 'Wednesday',
THU: 'Thursday',
FRI: 'Friday',
SAT: 'Saturday',
SUN: 'Sunday',
};
function dateOptions() {
const values = { L: 'Last day of month' };
for (let day = 1; day <= 31; day += 1) values[String(day)] = String(day);
return values;
}
function toBool(value) {
if (value === true || value === 1) return true;
return ['yes', '1', 'true'].includes(String(value ?? '').toLowerCase());
}
function fromBool(value) {
return toBool(value) ? 'yes' : 'no';
}
function toStringList(value) {
if (value == null || value === '') return [];
if (Array.isArray(value)) return value.map(String).filter((part) => part !== '');
if (typeof value === 'object') return Object.values(value).map(String);
return [String(value)];
}
function titleMap(items) {
const values = {};
(items || []).forEach((item) => {
if (item?.id) values[item.id] = item.title || item.name || item.id;
});
return values;
}
async function getAllItems(service, path) {
const response = await signedGet(service, path);
return isSuccess(response) ? response.data?.items || [] : [];
}
function newMilestoneId() {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
}
function flattenMetrics(metrics) {
if (!Array.isArray(metrics)) return [];
return metrics.map((row) => {
const metric = row && typeof row === 'object' ? row : {};
return {
metric: metric.metric || '',
display: metric.display || '',
weight: metric.weight ?? 1,
target: metric.target ?? '',
};
});
}
function firstBadge(value) {
if (Array.isArray(value)) return value[0] || '';
return value || '';
}
function flattenMilestoneCards(milestones) {
if (!Array.isArray(milestones)) return [];
return milestones.map((row) => {
const card = row && typeof row === 'object' ? row : {};
const target = card.target && typeof card.target === 'object' ? card.target : {};
const actions = card.actions && typeof card.actions === 'object' ? card.actions : {};
const appreciation = Array.isArray(actions.send_appreciation)
? actions.send_appreciation[0] || {}
: actions.send_appreciation || {};
return {
milestone_id: card.milestone_id || '',
target_title: target.target_title ?? '',
target: target.value ?? (typeof card.target === 'number' || typeof card.target === 'string' ? card.target : ''),
repeat_target: card.repeat_target ? '1' : '0',
roles: toStringList(card.roles),
reporting_roles: toStringList(card.reporting_roles),
user_notification: Boolean(actions.user_notification),
user_email: Boolean(actions.user_email),
manager_notification: toStringList(actions.manager_notification),
manager_email: toStringList(actions.manager_email),
send_badge: firstBadge(actions.send_badge),
appreciation_category: appreciation.category_id || '',
appreciation_image: appreciation.image_id || '',
appreciation_message: appreciation.message || '',
};
});
}
function mapMetricsForSave(rows) {
return (Array.isArray(rows) ? rows : [])
.filter((row) => row?.metric)
.map((row) => ({
metric: row.metric,
display: row.display || '',
weight: row.weight !== '' && row.weight != null ? String(row.weight) : '1',
target: row.target !== '' && row.target != null ? String(row.target) : '',
}));
}
function mapMilestonesForSave(rows) {
return (Array.isArray(rows) ? rows : []).map((row) => ({
milestone_id: row.milestone_id || newMilestoneId(),
target: {
value: Number(row.target || 0),
target_title: row.target_title || '',
},
repeat_target: String(row.repeat_target) === '1',
roles: toStringList(row.roles),
reporting_roles: toStringList(row.reporting_roles),
actions: {
user_notification: Boolean(row.user_notification),
user_email: Boolean(row.user_email),
manager_notification: toStringList(row.manager_notification),
manager_email: toStringList(row.manager_email),
send_badge: row.send_badge ? [row.send_badge] : [],
send_appreciation: [
{
category_id: row.appreciation_category || null,
image_id: row.appreciation_image || null,
message: row.appreciation_message || null,
},
],
},
}));
}
const milestones = {
service: 'formreminders',
module: 'milestones',
title: 'Milestone',
subtitle: 'Recognition',
baseUrl: '/milestone',
listPath: '/milestones',
listFields: [
{ key: 'actions', title: 'Actions', buttons: ['edit', 'delete'] },
{ key: 'title', title: 'Name', type: 'text' },
{ key: 'status', title: 'Status', type: 'select' },
],
formFields: async () => {
const [metrics, roles, badges, categories, images, userAttrRes] = await Promise.all([
metricOptions(),
dropdownMap('ums', 'roles', (item) => item.name),
getAllItems('recognition', 'badge_list/get_all').then(titleMap),
getAllItems('recognition', 'appreciation_category/get_all').then(titleMap),
getAllItems('recognition', 'appreciation_image/get_all').then((items) => {
const values = {};
items.forEach((item) => {
if (item?.id) values[item.id] = { title: item.title || item.id, image: item.image || '' };
});
return values;
}),
signedGet('ums', 'userattribute/get_all'),
]);
const userAttributes = {};
const userAttrItems = isSuccess(userAttrRes) ? userAttrRes.data?.items || [] : [];
userAttrItems.forEach((attr) => {
if (!attr?.code || attr.status === 'disabled') return;
userAttributes[attr.code] = attr.attribute || attr.code;
});
return [
{ key: 'title', title: 'Title', type: 'text', required: true },
{ key: 'interval_start_date', title: 'Interval Start Date', type: 'date', required: true },
{ key: 'interval_end_date', title: 'Interval End Date', type: 'date', required: true },
{
key: 'period',
title: 'Period',
type: 'select',
required: true,
values: {
daily: 'Daily',
weekly: 'Weekly',
monthly: 'Monthly',
yearly: 'Yearly',
overall: 'Overall',
custom: 'Custom',
},
},
{ key: 'custom_start_date', title: 'Custom Start Date', type: 'date', showIf: { period: 'custom' } },
{ key: 'custom_end_date', title: 'Custom End Date', type: 'date', showIf: { period: 'custom' } },
{ key: 'status', title: 'Status', type: 'select', required: true, values: STATUS },
{ key: 'show_positions', title: 'Show Positions', type: 'select', required: true, values: YES_NO },
{
key: 'show_positions_type',
title: 'Show Positions Type',
type: 'select',
required: true,
values: { all: 'All', loggedin: 'Logged In' },
},
{ key: 'show_units_export', title: 'Show Units Export', type: 'select', required: true, values: YES_NO, default: 'yes' },
{ key: 'show_user_attributes', title: 'Show User Attributes', type: 'select', required: true, values: YES_NO, default: 'no' },
{
key: 'user_attributes',
title: 'Include User Attributes',
type: 'multiselect',
values: userAttributes,
default: [],
showIf: { show_user_attributes: 'yes' },
},
{ key: 'show_normal_metrics', title: 'Show Normal Metrics', type: 'select', required: true, values: YES_NO, default: 'yes' },
{ key: 'show_combined_metrics', title: 'Show Combined Metrics', type: 'select', required: true, values: YES_NO, default: 'yes' },
{ key: 'manager_details', title: 'Manager Details', type: 'multiselect', values: MANAGER_LEVELS, default: ['l1manager'] },
{ key: 'total_units_name', title: 'Total Units Name', type: 'text', default: '' },
{ key: 'send_report', title: 'Send Report', type: 'select', required: true, values: YES_NO },
{
key: 'performance_period',
title: 'Performance Period',
type: 'select',
values: { daily: 'Daily', weekly: 'Weekly', monthly: 'Monthly' },
showIf: { send_report: 'yes' },
},
{
key: 'days_or_dates',
title: 'Days or Dates',
type: 'radio',
fullwidth: true,
values: { days: 'Days', dates: 'Dates' },
showIf: { send_report: 'yes' },
},
{
key: 'days',
title: 'Days',
type: 'checkbox',
fullwidth: true,
values: DAYS,
showIf: { send_report: 'yes', days_or_dates: 'days' },
},
{
key: 'dates',
title: 'Dates',
type: 'multiselect',
values: dateOptions(),
showIf: { send_report: 'yes', days_or_dates: 'dates' },
},
{ key: 'send_time', title: 'Send Time', type: 'text', showIf: { send_report: 'yes' } },
{
key: 'send_report_roles',
title: 'Send Report Roles',
type: 'multiselect',
values: roles,
showIf: { send_report: 'yes' },
},
{
key: 'report_roles',
title: 'Report Roles',
type: 'multiselect',
values: roles,
showIf: { send_report: 'yes' },
},
{
key: 'send_user_performance',
title: 'Send User Performance',
type: 'select',
values: YES_NO,
showIf: { send_report: 'yes' },
},
{
key: 'ai_action_items',
title: 'AI Action Items',
type: 'select',
values: YES_NO,
showIf: { send_report: 'yes' },
},
{
key: 'send_pending_users',
title: 'Send Pending Users',
type: 'select',
values: YES_NO,
showIf: { send_report: 'yes' },
},
{
key: 'show_target_average',
title: 'Show Target Average',
type: 'select',
values: YES_NO,
showIf: { send_report: 'yes' },
},
{
key: 'show_overall_average',
title: 'Show Overall Average',
type: 'select',
values: YES_NO,
showIf: { send_report: 'yes' },
},
{
key: 'metrics',
title: 'Metric Mapping',
type: 'mapping',
variant: 'milestone_metrics',
required: true,
metrics,
fullwidth: true,
},
{
key: 'milestones',
title: 'Milestone',
type: 'milestonemapping',
required: true,
roles,
badges,
appreciationCategories: categories,
appreciationImages: images,
fullwidth: true,
},
];
},
beforeForm: (item) => {
const next = { ...item };
if (next.interval) {
const [start, end] = String(next.interval).split('_');
next.interval_start_date = toDateInput(start);
next.interval_end_date = toDateInput(end);
} else {
next.interval_start_date = toDateInput(next.interval_start_date);
next.interval_end_date = toDateInput(next.interval_end_date);
}
next.custom_start_date = toDateInput(next.custom_start_date);
next.custom_end_date = toDateInput(next.custom_end_date);
next.metrics = flattenMetrics(next.metrics);
next.milestones = flattenMilestoneCards(next.milestones);
const reportConfig = next.report_config && typeof next.report_config === 'object' ? next.report_config : {};
next.days_or_dates = reportConfig.days_or_dates || 'days';
next.days = toStringList(reportConfig.days);
next.dates = toStringList(reportConfig.dates).map(String);
next.send_time = reportConfig.send_time || '';
next.performance_period = reportConfig.performance_period || '';
next.send_report_roles = toStringList(reportConfig.send_report_roles);
next.report_roles = toStringList(reportConfig.report_roles);
next.send_user_performance = fromBool(reportConfig.send_user_performance ?? false);
next.ai_action_items = fromBool(reportConfig.ai_action_items ?? false);
next.send_pending_users = fromBool(reportConfig.send_pending_users ?? false);
next.show_target_average = fromBool(reportConfig.show_target_average ?? false);
next.show_overall_average = fromBool(reportConfig.show_overall_average ?? false);
next.send_report = fromBool(next.send_report ?? false);
next.show_units_export = next.show_units_export || 'yes';
next.show_user_attributes = next.show_user_attributes === 'yes' ? 'yes' : 'no';
next.user_attributes = toStringList(next.user_attributes);
next.show_normal_metrics = next.show_normal_metrics || 'yes';
next.show_combined_metrics = next.show_combined_metrics || 'yes';
next.manager_details = toStringList(next.manager_details);
if (!next.manager_details.length) next.manager_details = ['l1manager'];
next.total_units_name = next.total_units_name || '';
return next;
},
beforeSave: (data) => {
const payload = { ...data };
const start = toDateInput(payload.interval_start_date);
const end = toDateInput(payload.interval_end_date);
payload.interval = start && end ? `${start}_${end}` : '';
payload.custom_start_date = payload.period === 'custom' ? toDateInput(payload.custom_start_date) : '';
payload.custom_end_date = payload.period === 'custom' ? toDateInput(payload.custom_end_date) : '';
payload.metrics = mapMetricsForSave(payload.metrics);
payload.milestones = mapMilestonesForSave(payload.milestones);
const daysOrDates = payload.days_or_dates || 'days';
payload.show_units_export = payload.show_units_export || 'yes';
payload.show_user_attributes = payload.show_user_attributes === 'yes' ? 'yes' : 'no';
payload.user_attributes = toStringList(payload.user_attributes);
payload.show_normal_metrics = payload.show_normal_metrics || 'yes';
payload.show_combined_metrics = payload.show_combined_metrics || 'yes';
payload.manager_details = toStringList(payload.manager_details);
if (!payload.manager_details.length) payload.manager_details = ['l1manager'];
payload.total_units_name = payload.total_units_name || '';
payload.send_report = toBool(payload.send_report ?? 'no');
payload.report_config = {
days_or_dates: daysOrDates,
days: daysOrDates === 'days' ? toStringList(payload.days) : [],
dates: daysOrDates === 'dates' ? toStringList(payload.dates) : [],
send_time: payload.send_time || '13:00',
performance_period: payload.performance_period || 'monthly',
send_report_roles: toStringList(payload.send_report_roles),
report_roles: toStringList(payload.report_roles),
send_user_performance: toBool(payload.send_user_performance ?? 'no'),
ai_action_items: toBool(payload.ai_action_items ?? 'no'),
send_pending_users: toBool(payload.send_pending_users ?? 'no'),
show_target_average: toBool(payload.show_target_average ?? 'no'),
show_overall_average: toBool(payload.show_overall_average ?? 'no'),
};
delete payload.interval_start_date;
delete payload.interval_end_date;
delete payload.days_or_dates;
delete payload.days;
delete payload.dates;
delete payload.send_time;
delete payload.performance_period;
delete payload.send_report_roles;
delete payload.report_roles;
delete payload.send_user_performance;
delete payload.ai_action_items;
delete payload.send_pending_users;
delete payload.show_target_average;
delete payload.show_overall_average;
return payload;
},
};
export default milestones;