- Finish department cycle times.

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-01-26 16:09:46 -05:00
parent 89224e871c
commit 120a8a4576
7 changed files with 47735 additions and 71 deletions

View File

@@ -5,6 +5,7 @@ import {Badge, Card, Space, Table, Tag} from 'antd';
import {gql, useQuery} from "@apollo/client"; import {gql, useQuery} from "@apollo/client";
import {DateTimeFormatterFunction} from "../../utils/DateFormatter"; import {DateTimeFormatterFunction} from "../../utils/DateFormatter";
import {isEmpty} from "lodash"; import {isEmpty} from "lodash";
import {useTranslation} from "react-i18next";
require('./job-lifecycle.styles.scss'); require('./job-lifecycle.styles.scss');
@@ -12,8 +13,8 @@ require('./job-lifecycle.styles.scss');
export function JobLifecycleComponent({job, statuses, ...rest}) { export function JobLifecycleComponent({job, statuses, ...rest}) {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [lifecycleData, setLifecycleData] = useState(null); const [lifecycleData, setLifecycleData] = useState(null);
const { t } = useTranslation(); // Used for tracking external state changes.
// Used for tracking external state changes.
const {data} = useQuery(gql` const {data} = useQuery(gql`
query get_job_test($id: uuid!){ query get_job_test($id: uuid!){
jobs_by_pk(id:$id){ jobs_by_pk(id:$id){
@@ -43,7 +44,7 @@ export function JobLifecycleComponent({job, statuses, ...rest}) {
const data = response.data.transition[job.id]; const data = response.data.transition[job.id];
setLifecycleData(data); setLifecycleData(data);
} catch (err) { } catch (err) {
console.error(`Error getting Job Lifecycle Data: ${err.message}`); console.error(`${t('job_lifecycle.errors.fetch')}: ${err.message}`);
} finally { } finally {
setLoading(false); setLoading(false);
} }
@@ -53,30 +54,30 @@ export function JobLifecycleComponent({job, statuses, ...rest}) {
useEffect(() => { useEffect(() => {
if (!data) return; if (!data) return;
setTimeout(() => { setTimeout(() => {
getLifecycleData().catch(err => console.error(`Error getting Job Lifecycle Data: ${err.message}`)); getLifecycleData().catch(err => console.error(`${t('job_lifecycle.errors.fetch')}: ${err.message}`));
}, 1000); }, 500);
}, [data, getLifecycleData]); }, [data, getLifecycleData]);
const columns = [ const columns = [
{ {
title: 'Value', title: t('job_lifecycle.columns.value'),
dataIndex: 'value', dataIndex: 'value',
key: 'value', key: 'value',
}, },
{ {
title: 'Start', title: t('job_lifecycle.columns.start'),
dataIndex: 'start', dataIndex: 'start',
key: 'start', key: 'start',
render: (text) => DateTimeFormatterFunction(text), render: (text) => DateTimeFormatterFunction(text),
sorter: (a, b) => moment(a.start).unix() - moment(b.start).unix(), sorter: (a, b) => moment(a.start).unix() - moment(b.start).unix(),
}, },
{ {
title: 'Relative Start', title: t('job_lifecycle.columns.relative_start'),
dataIndex: 'start_readable', dataIndex: 'start_readable',
key: 'start_readable', key: 'start_readable',
}, },
{ {
title: 'End', title: t('job_lifecycle.columns.end'),
dataIndex: 'end', dataIndex: 'end',
key: 'end', key: 'end',
sorter: (a, b) => { sorter: (a, b) => {
@@ -88,33 +89,23 @@ export function JobLifecycleComponent({job, statuses, ...rest}) {
} }
return moment(a.end).unix() - moment(b.end).unix(); return moment(a.end).unix() - moment(b.end).unix();
}, },
render: (text) => isEmpty(text) ? 'N/A' : DateTimeFormatterFunction(text) render: (text) => isEmpty(text) ? t('job_lifecycle.content.not_available') : DateTimeFormatterFunction(text)
}, },
{ {
title: 'Relative End', title: t('job_lifecycle.columns.relative_end'),
dataIndex: 'end_readable', dataIndex: 'end_readable',
key: 'end_readable', key: 'end_readable',
}, },
{ {
title: 'Duration', title: t('job_lifecycle.columns.duration'),
dataIndex: 'duration_readable', dataIndex: 'duration_readable',
key: 'duration_readable', key: 'duration_readable',
sorter: (a, b) => a.duration - b.duration, sorter: (a, b) => a.duration - b.duration,
}, },
]; ];
useEffect(() => {
console.log('Statuses');
console.dir(statuses, {depth: null});
}, [statuses]);
// useEffect(() => {
// console.log('LifeCycle Data');
// console.dir(lifecycleData, {depth: null})
// }, [lifecycleData]);
return ( return (
<Card loading={loading} title='Job Lifecycle Component'> <Card loading={loading} title={t('job_lifecycle.content.title')}>
{!loading ? ( {!loading ? (
lifecycleData && lifecycleData.lifecycle && lifecycleData.durations ? ( lifecycleData && lifecycleData.lifecycle && lifecycleData.durations ? (
<Space direction='vertical' style={{width: '100%'}}> <Space direction='vertical' style={{width: '100%'}}>
@@ -123,7 +114,7 @@ export function JobLifecycleComponent({job, statuses, ...rest}) {
title={( title={(
<Space direction='horizontal' size='small'> <Space direction='horizontal' size='small'>
<Badge status='processing' count={lifecycleData.durations.totalStatuses}/> <Badge status='processing' count={lifecycleData.durations.totalStatuses}/>
Historical Status Durations {t('job_lifecycle.content.title_durations')}
</Space> </Space>
)} )}
@@ -165,22 +156,26 @@ export function JobLifecycleComponent({job, statuses, ...rest}) {
aria-label={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`} aria-label={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
title={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`} title={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
> >
<div>{key.roundedPercentage}</div>
{key.percentage > 5 ? {key.percentage > 5 ?
<div style={{ <>
backgroundColor: '#f0f2f5', <div>{key.roundedPercentage}</div>
borderRadius: '5px', <div style={{
paddingRight: '2px', backgroundColor: '#f0f2f5',
paddingLeft: '2px', borderRadius: '5px',
fontSize: '0.8rem', paddingRight: '2px',
}}> paddingLeft: '2px',
{key.status} fontSize: '0.8rem',
</div> : null} }}>
{key.status}
</div>
</>
: null}
</div> </div>
); );
})} })}
</div> </div>
<Card type='inner' title='Legend' style={{marginTop: '10px'}}> <Card type='inner' title={t('job_lifecycle.content.legend_title')} style={{marginTop: '10px'}}>
<div> <div>
{lifecycleData.durations.summations.map((key) => ( {lifecycleData.durations.summations.map((key) => (
<Tag color={key.color} style={{width: '13vh', padding: '4px', margin: '4px'}}> <Tag color={key.color} style={{width: '13vh', padding: '4px', margin: '4px'}}>
@@ -200,15 +195,21 @@ export function JobLifecycleComponent({job, statuses, ...rest}) {
</div> </div>
</Card> </Card>
<Card style={{marginTop: '10px'}}> <Card style={{marginTop: '10px'}}>
<span <ul>
style={{fontWeight: 'bold'}}>Previous Status Accumulated Time:</span> {lifecycleData.durations.humanReadableTotal} <li>
<span style={{fontWeight: 'bold'}}>{t('job_lifecycle.content.previous_status_accumulated_time')}:</span> {lifecycleData.durations.humanReadableTotal}
</li>
<li>
<span style={{fontWeight: 'bold'}}>{t('job_lifecycle.content.current_status_accumulated_time')} ({lifecycleData.lifecycle[0].value}):</span> {lifecycleData.durations.totalCurrentStatusDuration.humanReadable}
</li>
</ul>
</Card> </Card>
</Card> </Card>
<Card type='inner' title={( <Card type='inner' title={(
<> <>
<Space direction="horizontal" size="small"> <Space direction="horizontal" size="small">
<Badge status='processing' count={lifecycleData.lifecycle.length}/> <Badge status='processing' count={lifecycleData.lifecycle.length}/>
Transitions {t('job_lifecycle.content.title_transitions')}
</Space> </Space>
</> </>
)}> )}>
@@ -217,12 +218,12 @@ export function JobLifecycleComponent({job, statuses, ...rest}) {
</Space> </Space>
) : ( ) : (
<Card type='inner' style={{textAlign: 'center'}}> <Card type='inner' style={{textAlign: 'center'}}>
There is currently no lifecycle data for this job. {t('job_lifecycle.content.data_unavailable')}
</Card> </Card>
) )
) : ( ) : (
<Card type='inner' title='Loading'> <Card type='inner' title={t('job_lifecycle.content.title_loading')}>
Loading Job Timelines.... {t('job_lifecycle.content.loading')}
</Card> </Card>
)} )}
</Card> </Card>

View File

@@ -336,7 +336,7 @@ export function JobsDetailPage({
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane <Tabs.TabPane
forceRender forceRender
tab={<span><BarsOutlined />Lifecycle</span>} tab={<span><BarsOutlined />{t('menus.jobsdetail.lifecycle')}</span>}
key="lifecycle" key="lifecycle"
> >
<JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses}/> <JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses}/>

View File

@@ -113,11 +113,11 @@
"jobassignmentchange": "Employee {{name}} assigned to {{operation}}", "jobassignmentchange": "Employee {{name}} assigned to {{operation}}",
"jobassignmentremoved": "Employee assignment removed for {{operation}}", "jobassignmentremoved": "Employee assignment removed for {{operation}}",
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.", "jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
"jobinvoiced": "Job has been invoiced.",
"jobconverted": "Job converted and assigned number {{ro_number}}.", "jobconverted": "Job converted and assigned number {{ro_number}}.",
"jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.", "jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.",
"jobimported": "Job imported.", "jobimported": "Job imported.",
"jobinproductionchange": "Job production status set to {{inproduction}}", "jobinproductionchange": "Job production status set to {{inproduction}}",
"jobinvoiced": "Job has been invoiced.",
"jobioucreated": "IOU Created.", "jobioucreated": "IOU Created.",
"jobmodifylbradj": "Labor adjustments modified {{mod_lbr_ty}} / {{hours}}.", "jobmodifylbradj": "Labor adjustments modified {{mod_lbr_ty}} / {{hours}}.",
"jobnoteadded": "Note added to Job.", "jobnoteadded": "Note added to Job.",
@@ -255,7 +255,6 @@
"saving": "Error encountered while saving. {{message}}" "saving": "Error encountered while saving. {{message}}"
}, },
"fields": { "fields": {
"ReceivableCustomField": "QBO Receivable Custom Field {{number}}",
"address1": "Address 1", "address1": "Address 1",
"address2": "Address 2", "address2": "Address 2",
"appt_alt_transport": "Appointment Alternative Transportation Options", "appt_alt_transport": "Appointment Alternative Transportation Options",
@@ -332,6 +331,9 @@
"md_ded_notes": "Deductible Notes", "md_ded_notes": "Deductible Notes",
"md_email_cc": "Auto Email CC: $t(printcenter.subjects.jobs.{{template}})", "md_email_cc": "Auto Email CC: $t(printcenter.subjects.jobs.{{template}})",
"md_from_emails": "Additional From Emails", "md_from_emails": "Additional From Emails",
"md_functionality_toggles": {
"parts_queue_toggle": "Auto Add Imported/Supplemented Jobs to Parts Queue"
},
"md_hour_split": { "md_hour_split": {
"paint": "Paint Hour Split", "paint": "Paint Hour Split",
"prep": "Prep Hour Split" "prep": "Prep Hour Split"
@@ -354,9 +356,6 @@
}, },
"md_payment_types": "Payment Types", "md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources", "md_referral_sources": "Referral Sources",
"md_functionality_toggles": {
"parts_queue_toggle": "Auto Add Imported/Supplemented Jobs to Parts Queue"
},
"md_tasks_presets": { "md_tasks_presets": {
"hourstype": "", "hourstype": "",
"memo": "", "memo": "",
@@ -474,6 +473,7 @@
"editaccess": "Users -> Edit access" "editaccess": "Users -> Edit access"
} }
}, },
"ReceivableCustomField": "QBO Receivable Custom Field {{number}}",
"responsibilitycenter": "Responsibility Center", "responsibilitycenter": "Responsibility Center",
"responsibilitycenter_accountdesc": "Account Description", "responsibilitycenter_accountdesc": "Account Description",
"responsibilitycenter_accountitem": "Item", "responsibilitycenter_accountitem": "Item",
@@ -815,6 +815,10 @@
"usage": "Usage", "usage": "Usage",
"vehicle": "Vehicle Description" "vehicle": "Vehicle Description"
}, },
"readiness": {
"notready": "Not Ready",
"ready": "Ready"
},
"status": { "status": {
"in": "Available", "in": "Available",
"inservice": "In Service", "inservice": "In Service",
@@ -824,10 +828,6 @@
}, },
"successes": { "successes": {
"saved": "Courtesy Car saved successfully." "saved": "Courtesy Car saved successfully."
},
"readiness": {
"notready": "Not Ready",
"ready": "Ready"
} }
}, },
"csi": { "csi": {
@@ -1214,6 +1214,31 @@
"updated": "Inventory line updated." "updated": "Inventory line updated."
} }
}, },
"job_lifecycle": {
"columns": {
"duration": "Duration",
"end": "End",
"relative_end": "Relative End",
"relative_start": "Relative Start",
"start": "Start",
"value": "Value"
},
"content": {
"current_status_accumulated_time": "Current Status Accumulated Time",
"data_unavailable": " There is currently no Lifecycle data for this Job.",
"legend_title": "Legend",
"loading": "Loading Job Timelines....",
"not_available": "N/A",
"previous_status_accumulated_time": "Previous Status Accumulated Time",
"title": "Job Lifecycle Component",
"title_durations": "Historical Status Duration's",
"title_loading": "Loading",
"title_transitions": "Transitions"
},
"errors": {
"fetch": "Error getting Job Lifecycle Data"
}
},
"job_payments": { "job_payments": {
"buttons": { "buttons": {
"goback": "Go Back", "goback": "Go Back",
@@ -2014,6 +2039,7 @@
"general": "General", "general": "General",
"insurance": "Insurance Information", "insurance": "Insurance Information",
"labor": "Labor", "labor": "Labor",
"lifecycle": "Lifecycle",
"partssublet": "Parts & Bills", "partssublet": "Parts & Bills",
"rates": "Rates", "rates": "Rates",
"repairdata": "Repair Data", "repairdata": "Repair Data",
@@ -2922,8 +2948,8 @@
"shop-templates": "Shop Templates | $t(titles.app)", "shop-templates": "Shop Templates | $t(titles.app)",
"shop_vendors": "Vendors | $t(titles.app)", "shop_vendors": "Vendors | $t(titles.app)",
"techconsole": "Technician Console | $t(titles.app)", "techconsole": "Technician Console | $t(titles.app)",
"techjoblookup": "Technician Job Lookup | $t(titles.app)",
"techjobclock": "Technician Job Clock | $t(titles.app)", "techjobclock": "Technician Job Clock | $t(titles.app)",
"techjoblookup": "Technician Job Lookup | $t(titles.app)",
"techshiftclock": "Technician Shift Clock | $t(titles.app)", "techshiftclock": "Technician Shift Clock | $t(titles.app)",
"temporarydocs": "Temporary Documents | $t(titles.app)", "temporarydocs": "Temporary Documents | $t(titles.app)",
"timetickets": "Time Tickets | $t(titles.app)", "timetickets": "Time Tickets | $t(titles.app)",

View File

@@ -113,11 +113,11 @@
"jobassignmentchange": "", "jobassignmentchange": "",
"jobassignmentremoved": "", "jobassignmentremoved": "",
"jobchecklist": "", "jobchecklist": "",
"jobinvoiced": "",
"jobconverted": "", "jobconverted": "",
"jobfieldchanged": "", "jobfieldchanged": "",
"jobimported": "", "jobimported": "",
"jobinproductionchange": "", "jobinproductionchange": "",
"jobinvoiced": "",
"jobioucreated": "", "jobioucreated": "",
"jobmodifylbradj": "", "jobmodifylbradj": "",
"jobnoteadded": "", "jobnoteadded": "",
@@ -255,13 +255,9 @@
"saving": "" "saving": ""
}, },
"fields": { "fields": {
"ReceivableCustomField": "",
"address1": "", "address1": "",
"address2": "", "address2": "",
"appt_alt_transport": "", "appt_alt_transport": "",
"md_functionality_toggles": {
"parts_queue_toggle": ""
},
"appt_colors": { "appt_colors": {
"color": "", "color": "",
"label": "" "label": ""
@@ -335,6 +331,9 @@
"md_ded_notes": "", "md_ded_notes": "",
"md_email_cc": "", "md_email_cc": "",
"md_from_emails": "", "md_from_emails": "",
"md_functionality_toggles": {
"parts_queue_toggle": ""
},
"md_hour_split": { "md_hour_split": {
"paint": "", "paint": "",
"prep": "" "prep": ""
@@ -474,6 +473,7 @@
"editaccess": "" "editaccess": ""
} }
}, },
"ReceivableCustomField": "",
"responsibilitycenter": "", "responsibilitycenter": "",
"responsibilitycenter_accountdesc": "", "responsibilitycenter_accountdesc": "",
"responsibilitycenter_accountitem": "", "responsibilitycenter_accountitem": "",
@@ -815,6 +815,10 @@
"usage": "", "usage": "",
"vehicle": "" "vehicle": ""
}, },
"readiness": {
"notready": "",
"ready": ""
},
"status": { "status": {
"in": "", "in": "",
"inservice": "", "inservice": "",
@@ -824,10 +828,6 @@
}, },
"successes": { "successes": {
"saved": "" "saved": ""
},
"readiness": {
"notready": "",
"ready": ""
} }
}, },
"csi": { "csi": {
@@ -1214,6 +1214,31 @@
"updated": "" "updated": ""
} }
}, },
"job_lifecycle": {
"columns": {
"duration": "",
"end": "",
"relative_end": "",
"relative_start": "",
"start": "",
"value": ""
},
"content": {
"current_status_accumulated_time": "",
"data_unavailable": "",
"legend_title": "",
"loading": "",
"not_available": "",
"previous_status_accumulated_time": "",
"title": "",
"title_durations": "",
"title_loading": "",
"title_transitions": ""
},
"errors": {
"fetch": "Error al obtener los datos del ciclo de vida del trabajo"
}
},
"job_payments": { "job_payments": {
"buttons": { "buttons": {
"goback": "", "goback": "",
@@ -2014,6 +2039,7 @@
"general": "", "general": "",
"insurance": "", "insurance": "",
"labor": "Labor", "labor": "Labor",
"lifecycle": "",
"partssublet": "Piezas / Subarrendamiento", "partssublet": "Piezas / Subarrendamiento",
"rates": "", "rates": "",
"repairdata": "Datos de reparación", "repairdata": "Datos de reparación",
@@ -2922,8 +2948,8 @@
"shop-templates": "", "shop-templates": "",
"shop_vendors": "Vendedores | $t(titles.app)", "shop_vendors": "Vendedores | $t(titles.app)",
"techconsole": "$t(titles.app)", "techconsole": "$t(titles.app)",
"techjoblookup": "$t(titles.app)",
"techjobclock": "$t(titles.app)", "techjobclock": "$t(titles.app)",
"techjoblookup": "$t(titles.app)",
"techshiftclock": "$t(titles.app)", "techshiftclock": "$t(titles.app)",
"temporarydocs": "", "temporarydocs": "",
"timetickets": "", "timetickets": "",

View File

@@ -113,11 +113,11 @@
"jobassignmentchange": "", "jobassignmentchange": "",
"jobassignmentremoved": "", "jobassignmentremoved": "",
"jobchecklist": "", "jobchecklist": "",
"jobinvoiced": "",
"jobconverted": "", "jobconverted": "",
"jobfieldchanged": "", "jobfieldchanged": "",
"jobimported": "", "jobimported": "",
"jobinproductionchange": "", "jobinproductionchange": "",
"jobinvoiced": "",
"jobioucreated": "", "jobioucreated": "",
"jobmodifylbradj": "", "jobmodifylbradj": "",
"jobnoteadded": "", "jobnoteadded": "",
@@ -255,7 +255,6 @@
"saving": "" "saving": ""
}, },
"fields": { "fields": {
"ReceivableCustomField": "",
"address1": "", "address1": "",
"address2": "", "address2": "",
"appt_alt_transport": "", "appt_alt_transport": "",
@@ -332,13 +331,13 @@
"md_ded_notes": "", "md_ded_notes": "",
"md_email_cc": "", "md_email_cc": "",
"md_from_emails": "", "md_from_emails": "",
"md_functionality_toggles": {
"parts_queue_toggle": ""
},
"md_hour_split": { "md_hour_split": {
"paint": "", "paint": "",
"prep": "" "prep": ""
}, },
"md_functionality_toggles": {
"parts_queue_toggle": ""
},
"md_ins_co": { "md_ins_co": {
"city": "", "city": "",
"name": "", "name": "",
@@ -474,6 +473,7 @@
"editaccess": "" "editaccess": ""
} }
}, },
"ReceivableCustomField": "",
"responsibilitycenter": "", "responsibilitycenter": "",
"responsibilitycenter_accountdesc": "", "responsibilitycenter_accountdesc": "",
"responsibilitycenter_accountitem": "", "responsibilitycenter_accountitem": "",
@@ -815,6 +815,10 @@
"usage": "", "usage": "",
"vehicle": "" "vehicle": ""
}, },
"readiness": {
"notready": "",
"ready": ""
},
"status": { "status": {
"in": "", "in": "",
"inservice": "", "inservice": "",
@@ -824,10 +828,6 @@
}, },
"successes": { "successes": {
"saved": "" "saved": ""
},
"readiness": {
"notready": "",
"ready": ""
} }
}, },
"csi": { "csi": {
@@ -1214,6 +1214,31 @@
"updated": "" "updated": ""
} }
}, },
"job_lifecycle": {
"columns": {
"duration": "",
"end": "",
"relative_end": "",
"relative_start": "",
"start": "",
"value": ""
},
"content": {
"current_status_accumulated_time": "",
"data_unavailable": "",
"legend_title": "",
"loading": "",
"not_available": "",
"previous_status_accumulated_time": "",
"title": "",
"title_durations": "",
"title_loading": "",
"title_transitions": ""
},
"errors": {
"fetch": "Erreur lors de l'obtention des données du cycle de vie des tâches"
}
},
"job_payments": { "job_payments": {
"buttons": { "buttons": {
"goback": "", "goback": "",
@@ -2014,6 +2039,7 @@
"general": "", "general": "",
"insurance": "", "insurance": "",
"labor": "La main d'oeuvre", "labor": "La main d'oeuvre",
"lifecycle": "",
"partssublet": "Pièces / Sous-location", "partssublet": "Pièces / Sous-location",
"rates": "", "rates": "",
"repairdata": "Données de réparation", "repairdata": "Données de réparation",
@@ -2922,8 +2948,8 @@
"shop-templates": "", "shop-templates": "",
"shop_vendors": "Vendeurs | $t(titles.app)", "shop_vendors": "Vendeurs | $t(titles.app)",
"techconsole": "$t(titles.app)", "techconsole": "$t(titles.app)",
"techjoblookup": "$t(titles.app)",
"techjobclock": "$t(titles.app)", "techjobclock": "$t(titles.app)",
"techjoblookup": "$t(titles.app)",
"techshiftclock": "$t(titles.app)", "techshiftclock": "$t(titles.app)",
"temporarydocs": "", "temporarydocs": "",
"timetickets": "", "timetickets": "",

File diff suppressed because it is too large Load Diff

View File

@@ -14,11 +14,21 @@ const getColor = (key) => {
const calculateStatusDuration = (transitions, statuses) => { const calculateStatusDuration = (transitions, statuses) => {
let statusDuration = {}; let statusDuration = {};
let totalDuration = 0; let totalDuration = 0;
let totalCurrentStatusDuration = null;
let summations = []; let summations = [];
transitions.forEach((transition, index) => { transitions.forEach((transition, index) => {
let duration = transition.duration; let duration = transition.duration;
totalDuration += duration; totalDuration += duration;
if (transition.start && !transition.end) {
const startMoment = moment(transition.start);
const nowMoment = moment();
const duration = moment.duration(nowMoment.diff(startMoment));
totalCurrentStatusDuration = {
value: duration.asMilliseconds(),
humanReadable: durationToHumanReadable(duration)
};
}
if (!transition.prev_value) { if (!transition.prev_value) {
statusDuration[transition.value] = { statusDuration[transition.value] = {
@@ -84,6 +94,7 @@ const calculateStatusDuration = (transitions, statuses) => {
}) : summations, }) : summations,
totalStatuses: summations.length, totalStatuses: summations.length,
total: totalDuration, total: totalDuration,
totalCurrentStatusDuration,
humanReadableTotal humanReadableTotal
}; };
} }