Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion projects/ngx-formentry/src/form-entry/form-entry.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { CustomControlWrapperModule } from '../components/custom-control-wrapper
import { CustomComponentWrapperModule } from '../components/custom-component-wrapper/custom-component-wrapper..module';
import { TranslateModule } from '@ngx-translate/core';
import { PatientIdentifierAdapter } from './value-adapters/patient-identifier.adapter';
import { AppointmentAdapter } from './value-adapters/appointment.adapter';

@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
Expand Down Expand Up @@ -102,7 +103,8 @@ import { PatientIdentifierAdapter } from './value-adapters/patient-identifier.ad
OrderValueAdapter,
DiagnosisValueAdapter,
DebugModeService,
PatientIdentifierAdapter
PatientIdentifierAdapter,
AppointmentAdapter
],
exports: [
FormRendererComponent,
Expand Down
8 changes: 8 additions & 0 deletions projects/ngx-formentry/src/form-entry/form-factory/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ export class Form {
}
}

get value() {
return this.rootNode.control.value;
}

get isDirty() {
return this.rootNode.control.dirty;
}

get valid() {
return this.rootNode.control.valid;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ export class QuestionFactory {
const mappings: any = {
label: 'label',
required: 'required',
id: 'key'
id: 'key',
type: ''
};
question.datePickerFormat = schemaQuestion.datePickerFormat ?? 'calendar';

this.copyProperties(mappings, schemaQuestion, question);
this.addDisableOrHideProperty(schemaQuestion, question);
this.addAlertProperty(schemaQuestion, question);
Expand Down Expand Up @@ -225,7 +225,8 @@ export class QuestionFactory {
const mappings = {
label: 'label',
required: 'required',
id: 'key'
id: 'key',
type: ''
};
question.componentConfigs = schemaQuestion.componentConfigs || [];
this.copyProperties(mappings, schemaQuestion, question);
Expand Down Expand Up @@ -681,6 +682,42 @@ export class QuestionFactory {
return question;
}

toRemoteSelect(schemaQuestion: any): UiSelectQuestion {
const question = new UiSelectQuestion({
options: [],
type: '',
key: '',
searchFunction: function () {},
resolveFunction: function () {}
});
question.questionIndex = this.quetionIndex;
question.label = schemaQuestion.label;
question.prefix = schemaQuestion.prefix;
question.key = schemaQuestion.id;
question.renderingType = schemaQuestion.type;
question.renderingType = 'remote-select';
question.validators = this.addValidators(schemaQuestion);
question.extras = schemaQuestion;
question.dataSource = schemaQuestion.questionOptions.dataSource;

if (question.dataSource === undefined) {
console.error(`No data source provided for question ${question.label}`);
}

const mappings: any = {
label: 'label',
required: 'required',
id: 'key'
};
question.componentConfigs = schemaQuestion.componentConfigs || [];
this.copyProperties(mappings, schemaQuestion, question);
this.addDisableOrHideProperty(schemaQuestion, question);
this.addAlertProperty(schemaQuestion, question);
this.addHistoricalExpressions(schemaQuestion, question);
this.addCalculatorProperty(schemaQuestion, question);
return question;
}

toTestOrderQuestion(schemaQuestion: any): TestOrderQuestion {
const question = new TestOrderQuestion({
type: '',
Expand Down Expand Up @@ -938,6 +975,8 @@ export class QuestionFactory {
return this.toFileUploadQuestion(schema);
case 'workspace-launcher':
return this.toWorkspaceLauncher(schema);
case 'remote-select':
return this.toRemoteSelect(schema);
default:
console.warn('New Schema Question Type found.........' + renderType);
return this.toTextQuestion(schema);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
export interface AppointmentResponsePayload {
uuid: string;
appointmentNumber: string;
dateCreated: number;
dateAppointmentScheduled: number;
patient: {
OpenMRSID: string;
identifier: string;
UniquePatientNumber: string;
gender: string;
name: string;
uuid: string;
age: number;
customAttributes: Record<string, unknown>;
};
service: {
appointmentServiceId: number;
name: string;
description: string | null;
speciality: Record<string, unknown>;
startTime: string;
endTime: string;
maxAppointmentsLimit: number | null;
durationMins: number | null;
location: Record<string, unknown>;
uuid: string;
color: string;
initialAppointmentStatus: string | null;
creatorName: string | null;
};
serviceType: unknown | null;
provider: unknown | null;
location: {
name: string;
uuid: string;
};
startDateTime: number;
endDateTime: number;
appointmentKind: string;
status: string;
comments: string;
additionalInfo: unknown | null;
teleconsultation: unknown | null;
providers: Array<{
uuid: string;
comments: string | null;
response: string;
name: string;
}>;
voided: boolean;
extensions: {
patientEmailDefined: boolean;
};
teleconsultationLink: string | null;
priority: unknown | null;
recurring: boolean;
}
/**
* Interface representing the structure of an appointment payload.
*/
export interface AppointmentPayload {
status: string;
appointmentKind: string;
locationUuid: string;
serviceUuid: string;
providers: { uuid: string }[];
startDateTime: string;
endDateTime: string;
dateAppointmentIssued?: string;
uuid?: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { Injectable } from '@angular/core';
import { ValueAdapter } from './value.adapter';
import { Form } from '../form-factory';
import { GroupNode, LeafNode } from '../form-factory/form-node';
import moment from 'moment';
import {
AppointmentPayload,
AppointmentResponsePayload
} from './appointment-helper';

@Injectable({
providedIn: 'root'
})
export class AppointmentAdapter implements ValueAdapter {
/**
* Generates the form payload for an appointment.
* @param {Form} form - The form object.
* @returns {AppointmentPayload} The generated appointment payload.
*/
public generateFormPayload(form: Form): AppointmentPayload {
const uuid = form?.valueProcessingInfo?.appointmentUuid;
const dateAppointmentIssued =
form?.valueProcessingInfo?.dateAppointmentIssued;

const questionNodes = this.findAppointmentQuestionNodes(form.rootNode);
const payload = this.generateFormPayloadForQuestion(questionNodes);

// If in edit mode, add the uuid to the payload
if (uuid) {
payload.uuid = uuid;
}

// Add dateAppointmentIssued to the payload if it exists
if (dateAppointmentIssued) {
payload.dateAppointmentIssued = dateAppointmentIssued;
}

return payload;
}

public populateForm(form: Form, payload: AppointmentResponsePayload): void {
const questionNodes = this.findAppointmentQuestionNodes(form.rootNode);
this.populateFormForQuestion(questionNodes, payload);
}

private populateFormForQuestion(
appointmentQuestionNodes: LeafNode[],
payload: AppointmentResponsePayload
): void {
appointmentQuestionNodes.forEach((node) => {
const appointmentKey =
node.question.extras.questionOptions.appointmentKey;
const value = payload[appointmentKey];

if (appointmentKey) {
if (appointmentKey === 'duration') {
node.control.setValue(this.calculateDuration(payload));
return;
}

if (value instanceof Object) {
if (Array.isArray(value)) {
node.control.setValue(value[0].uuid);
return;
}
node.control.setValue(value.uuid);
return;
}

node.control.setValue(value);
}
});
}

private calculateDuration(payload: AppointmentResponsePayload): string {
const duration = moment
.duration(moment(payload.endDateTime).diff(payload.startDateTime))
.asMinutes();
return duration.toString();
}

private findAppointmentQuestionNodes(formNode: GroupNode): LeafNode[] {
const appointmentNodes: LeafNode[] = [];

const traverseNode = (node: GroupNode | LeafNode): void => {
if (node instanceof GroupNode) {
Object.values(node.children).forEach(traverseNode);
} else if (
node instanceof LeafNode &&
node.question.extras?.type === 'appointment'
) {
appointmentNodes.push(node as LeafNode);
}
};

traverseNode(formNode);

return appointmentNodes;
}

/**
* Generates the form payload for appointment questions.
* @param {LeafNode[]} appointmentQuestionNodes - An array of leaf nodes representing appointment questions.
* @returns {AppointmentPayload} The generated appointment payload.
*/
private generateFormPayloadForQuestion(
appointmentQuestionNodes: LeafNode[]
): AppointmentPayload {
const formPayload = appointmentQuestionNodes.reduce<Record<string, string>>(
(payload, node) => {
const { appointmentKey } = node.question.extras.questionOptions;
payload[appointmentKey] = node.control.value;
return payload;
},
{}
);

const {
providers,
startDateTime,
duration,
service,
location,
status = 'Scheduled',
appointmentKind = 'Scheduled',
...restOfPayload
} = formPayload;

const endDateTime = duration
? this.calculateEndDateTime(startDateTime, parseInt(duration, 10))
: moment(startDateTime).endOf('day').toISOString();

return {
...restOfPayload,
status,
appointmentKind,
locationUuid: location,
serviceUuid: service,
providers: [{ uuid: providers }],
startDateTime: moment(startDateTime).toISOString(),
endDateTime
};
}

/**
* Calculates the end date and time based on the start date and time and duration.
* @param {string} startDateTime - The start date and time in ISO format.
* @param {number} durationMinutes - The duration in minutes.
* @returns {string} The calculated end date and time in ISO format.
*/
private calculateEndDateTime(
startDateTime: string,
durationMinutes: number
): string {
return moment(startDateTime).add(durationMinutes, 'minutes').toISOString();
}
}
1 change: 1 addition & 0 deletions projects/ngx-formentry/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ export { DatePickerComponent } from '../components/date-time-picker';
export { TimePickerComponent } from '../components/date-time-picker';
export { MomentPipe } from '../components/date-time-picker';
export { PatientIdentifierAdapter } from '../form-entry/value-adapters/patient-identifier.adapter';
export { AppointmentAdapter } from '../form-entry/value-adapters/appointment.adapter';
Loading