Files
simrsx-fe/app/handlers/encounter-process.handler.ts
2025-11-20 14:16:21 +07:00

312 lines
9.1 KiB
TypeScript

import { isValidDate } from '~/lib/date'
import { medicalPositions } from '~/lib/roles'
export interface EncounterItem {
id: string
title: string
classCode?: string[]
unit?: string
afterId?: string
component?: any
props?: Record<string, any>
}
export interface EncounterProps {
classCode: 'ambulatory' | 'emergency' | 'inpatient' | 'outpatient'
subClassCode: 'reg' | 'rehab' | 'chemo' | 'emg' | 'eon' | 'op' | 'icu' | 'hcu' | 'vk'
}
export const defaultItems: EncounterItem[] = [
{
id: 'status',
title: 'Status Masuk/Keluar',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'early-medical-assessment',
title: 'Pengkajian Awal Medis',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'rehab-medical-assessment',
title: 'Pengkajian Awal Medis Rehabilitasi Medis',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'rehab',
afterId: 'early-medical-assessment',
},
{
id: 'function-assessment',
title: 'Asesmen Fungsi',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'rehab',
afterId: 'rehab-medical-assessment',
},
{
id: 'therapy-protocol',
classCode: ['ambulatory'],
title: 'Protokol Terapi',
unit: 'rehab',
afterId: 'function-assessment',
},
{
id: 'chemotherapy-protocol',
title: 'Protokol Kemoterapi',
classCode: ['ambulatory'],
unit: 'chemo',
afterId: 'early-medical-assessment',
},
{
id: 'chemotherapy-medicine',
title: 'Protokol Obat Kemoterapi',
classCode: ['ambulatory'],
unit: 'chemo',
afterId: 'chemotherapy-protocol',
},
{
id: 'report',
title: 'Laporan Tindakan',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'patient-note',
title: 'CPRJ',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'education-assessment',
title: 'Asesmen Kebutuhan Edukasi',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'consent',
title: 'General Consent',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'prescription',
title: 'Order Obat',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'device',
title: 'Order Alkes',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'mcu-radiology',
title: 'Order Radiologi',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'mcu-lab-pc',
title: 'Order Lab PK',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'mcu-lab-micro',
title: 'Order Lab Mikro',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'mcu-lab-pa',
title: 'Order Lab PA',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'medical-action',
title: 'Order Ruang Tindakan',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'mcu-result',
title: 'Hasil Penunjang',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'consultation',
title: 'Konsultasi',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'resume',
title: 'Resume',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'control',
title: 'Surat Kontrol',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'screening',
title: 'Skrinning MPP',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
{
id: 'supporting-document',
title: 'Upload Dokumen Pendukung',
classCode: ['ambulatory'],
unit: 'rehab',
},
{
id: 'price-list',
title: 'Tarif Tindakan',
classCode: ['ambulatory', 'emergency', 'inpatient'],
unit: 'all',
},
]
const getItemsByClassCode = (classCode: string, items: EncounterItem[]) => {
return items.filter((item) => item.classCode?.includes(classCode))
}
const getItemsByUnit = (unit: string, items: EncounterItem[]) => {
return items.filter((item) => item.unit === unit)
}
export const getItemsByIds = (ids: string[], items: EncounterItem[]) => {
return items.filter((item) => ids.includes(item.id))
}
export const getIndexById = (id: string, items: EncounterItem[]) => {
return items.findIndex((item) => item.id === id)
}
export function insertItemByAfterId(id: string, items: EncounterItem[], newItem: EncounterItem) {
const index = getIndexById(id, items)
if (index > -1) {
items.splice(index + 1, 0, newItem)
}
}
export function mergeArrayAt<T>(arraysOne: T[], arraysTwo: T[] | T, deleteCount = 0): T[] {
const prevItems = arraysOne.slice()
if (!prevItems) return prevItems
const nextItems = Array.isArray(arraysTwo) ? arraysTwo : [arraysTwo]
if (nextItems.length === 0) return prevItems
// determine insertion position using the first item's `id` if available
const firstId = (nextItems[0] as any)?.afterId || (prevItems[0] as any)?.id
let pos = prevItems.length
if (typeof firstId === 'string') {
const index = prevItems.findIndex((item: any) => item.id === firstId)
pos = index < 0 ? Math.max(prevItems.length + index, 0) : Math.min(index, prevItems.length)
}
prevItems.splice(pos, deleteCount, ...nextItems)
return prevItems
}
export const getItemsAll = (classCode: string, unit: string, items: EncounterItem[]) => {
const prevItems = [...items]
let updateItems = getItemsByClassCode(classCode, prevItems)
updateItems = getItemsByUnit(unit, updateItems)
return updateItems
}
// Function to map API response to Encounter structure
export function mapResponseToEncounter(result: any): any {
if (!result) return null
// Check if patient and patient.person exist (minimal validation)
if (!result.patient || !result.patient.person) {
return null
}
const mapped: any = {
id: result.id || 0,
patient_id: result.patient_id || result.patient?.id || 0,
patient: {
id: result.patient?.id || 0,
number: result.patient?.number || '',
person: {
id: result.patient?.person?.id || 0,
name: result.patient?.person?.name || '',
birthDate: result.patient?.person?.birthDate || null,
gender_code: result.patient?.person?.gender_code || '',
residentIdentityNumber: result.patient?.person?.residentIdentityNumber || null,
frontTitle: result.patient?.person?.frontTitle || '',
endTitle: result.patient?.person?.endTitle || '',
addresses: result.patient?.person?.addresses || [],
},
},
registeredAt: result.registeredAt || result.patient?.registeredAt || null,
class_code: result.class_code || '',
unit_id: result.unit_id || 0,
unit: result.unit || null,
specialist_id: result.specialist_id || null,
subspecialist_id: result.subspecialist_id || null,
visitDate: isValidDate(result.visitDate)
? result.visitDate
: result.registeredAt || result.patient?.registeredAt || null,
adm_employee_id: result.adm_employee_id || 0,
appointment_doctor_id: result.appointment_doctor_id || null,
responsible_doctor_id: result.responsible_doctor_id || null,
appointment_doctor: result.appointment_doctor || null,
responsible_doctor: result.responsible_doctor || null,
refSource_name: result.refSource_name || null,
appointment_id: result.appointment_id || null,
earlyEducation: result.earlyEducation || null,
medicalDischargeEducation: result.medicalDischargeEducation || '',
admDischargeEducation: result.admDischargeEducation || null,
discharge_method_code: result.discharge_method_code || null,
discharge_reason: result.dischargeReason || result.discharge_reason || null,
discharge_date: result.discharge_date || null,
status_code: result.status_code || '',
// Payment related fields
paymentMethod_code:
result.paymentMethod_code && result.paymentMethod_code.trim() !== '' ? result.paymentMethod_code : null,
trx_number: result.trx_number || null,
member_number: result.member_number || null,
ref_number: result.ref_number || null,
}
return mapped
}
const listItemsForOutpatientRehab = mergeArrayAt(
getItemsAll('ambulatory', 'all', defaultItems),
getItemsAll('ambulatory', 'rehab', defaultItems),
)
const listItemsForOutpatientChemo = mergeArrayAt(
getItemsAll('ambulatory', 'all', defaultItems),
getItemsAll('ambulatory', 'chemo', defaultItems),
)
export const listItems: Record<string, Record<string, Record<string, any>>> = {
'installation|outpatient': {
'unit|rehab': {
items: listItemsForOutpatientRehab,
roles: medicalPositions,
},
'unit|chemo': {
items: listItemsForOutpatientChemo,
roles: medicalPositions,
},
all: getItemsAll('ambulatory', 'all', defaultItems),
},
'installation|emergency': {
all: getItemsAll('emergency', 'all', defaultItems),
},
'installation|inpatient': {
all: getItemsAll('inpatient', 'all', defaultItems),
},
}