import { type Order, type OrderAction, type OrderBasketItem } from '@openmrs/esm-patient-common-lib'; import { type ObservationValue } from '../../types/encounter'; /** * Enables a comparison of arbitrary values with support for undefined/null. * Requires the `<` and `>` operators to return something reasonable for the provided values. */ export function compare(x?: T, y?: T) { if (x == undefined && y == undefined) { return 0; } else if (x == undefined) { return -1; } else if (y == undefined) { return 1; } else if (x < y) { return -1; } else if (x > y) { return 1; } else { return 0; } } /** * Builds medication order object from the given order object */ export function buildMedicationOrder(order: Order, action?: OrderAction) { return { display: order.drug?.display, previousOrder: action !== 'NEW' ? order.uuid : null, action: action, drug: order.drug, dosage: order.dose, unit: { value: order.doseUnits?.display, valueCoded: order.doseUnits?.uuid, }, frequency: { valueCoded: order.frequency?.uuid, value: order.frequency?.display, }, route: { valueCoded: order.route?.uuid, value: order.route?.display, }, commonMedicationName: order.drug?.display, isFreeTextDosage: order.dosingType === 'org.openmrs.FreeTextDosingInstructions', freeTextDosage: order.dosingType === 'org.openmrs.FreeTextDosingInstructions' ? order.dosingInstructions : '', patientInstructions: order.dosingType !== 'org.openmrs.FreeTextDosingInstructions' ? order.dosingInstructions : '', asNeeded: order.asNeeded, asNeededCondition: order.asNeededCondition, startDate: action === 'DISCONTINUE' ? order.dateActivated : new Date(), duration: order.duration, durationUnit: { valueCoded: order.durationUnits?.uuid, value: order.durationUnits?.display, }, pillsDispensed: order.quantity, numRefills: order.numRefills, indication: order.orderReasonNonCoded, orderer: order.orderer.uuid, careSetting: order.careSetting.uuid, quantityUnits: { value: order.quantityUnits?.display, valueCoded: order.quantityUnits?.uuid, }, }; } /** * Builds lab order object from the given order object */ export function buildLabOrder(order: Order, action?: OrderAction) { return { action: action, display: order.display, previousOrder: action !== 'NEW' ? order.uuid : null, orderer: order.orderer.uuid, careSetting: order.careSetting.uuid, instructions: order.instructions, urgency: order.urgency, accessionNumber: order.accessionNumber, testType: { label: order.concept.display, conceptUuid: order.concept.uuid, }, orderNumber: order.orderNumber, concept: order.concept, orderType: order.orderType.uuid, specimenSource: null, scheduledDate: order.scheduledDate ? new Date(order.scheduledDate) : null, }; } /** * Builds general order object from the given order object */ export function buildGeneralOrder(order: Order, action?: OrderAction): OrderBasketItem { return { action: action, display: order.display, previousOrder: action !== 'NEW' ? order.uuid : null, orderer: order.orderer.uuid, careSetting: order.careSetting.uuid, instructions: order.instructions, urgency: order.urgency, accessionNumber: order.accessionNumber, concept: order.concept, orderNumber: order.orderNumber, orderType: order.orderType.uuid, scheduledDate: order.scheduledDate ? new Date(order.scheduledDate) : null, }; } /** * Utility function to extract display value from ObservationValue */ export const getObservationDisplayValue = (value: ObservationValue): string => { if (!value) { return '--'; } if (typeof value === 'string') { return value; } if (typeof value === 'number') { return value.toString(); } if (value && typeof value === 'object' && 'display' in value) { return value.display; } return '--'; }; /** * Removes the '+' prefix from a phone number if present * @param phoneNumber - The phone number to sanitize * @returns The phone number without the '+' prefix */ export function sanitizePhoneNumber(phoneNumber: string): string { if (!phoneNumber) { return phoneNumber; } return phoneNumber.startsWith('+') ? phoneNumber.substring(1) : phoneNumber; } /** * Masks a phone number by replacing all digits except the first two and the last two with asterisks (*) * @example * maskPhoneNumber('254712345678') // returns '25471******78' * @param phoneNumber - The phone number to be masked * @returns The masked phone number */ export const maskPhoneNumber = (phoneNumber: string): string => { const digits = phoneNumber.replace(/\D/g, ''); if (digits.length < 8) { return phoneNumber; } const firstPart = digits.slice(0, -6); const maskedPart = '*'.repeat(4); const lastPart = digits.slice(-2); return `${firstPart}${maskedPart}${lastPart}`; };