79 lines
2.3 KiB
TypeScript
79 lines
2.3 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
|
|
export interface PolimedPatient {
|
|
id: string;
|
|
fullName: string;
|
|
birthDate: string;
|
|
phone: string;
|
|
cardNumber: string;
|
|
}
|
|
|
|
export interface PolimedAppointment {
|
|
id: string;
|
|
patientId: string;
|
|
patientFullName: string;
|
|
doctorFullName: string;
|
|
specialty: string;
|
|
scheduledFor: string;
|
|
status: 'scheduled' | 'completed' | 'cancelled' | 'no_show';
|
|
}
|
|
|
|
export type PolimedVisitEventType =
|
|
| 'arrived'
|
|
| 'service_started'
|
|
| 'service_ended'
|
|
| 'left_without_service';
|
|
|
|
@Injectable()
|
|
export class PolimedClient {
|
|
private readonly logger = new Logger(PolimedClient.name);
|
|
private readonly baseUrl: string;
|
|
|
|
constructor(config: ConfigService) {
|
|
this.baseUrl = config.getOrThrow<string>('POLIMED_BASE_URL');
|
|
}
|
|
|
|
async searchPatients(query: string, limit = 20): Promise<PolimedPatient[]> {
|
|
const url = new URL('/patients/search', this.baseUrl);
|
|
url.searchParams.set('q', query);
|
|
url.searchParams.set('limit', String(limit));
|
|
return this.fetchJson(url);
|
|
}
|
|
|
|
async getAppointments(date?: string): Promise<PolimedAppointment[]> {
|
|
const url = new URL('/appointments', this.baseUrl);
|
|
if (date) url.searchParams.set('date', date);
|
|
return this.fetchJson(url);
|
|
}
|
|
|
|
async getAppointment(id: string): Promise<PolimedAppointment> {
|
|
const url = new URL(`/appointments/${id}`, this.baseUrl);
|
|
return this.fetchJson(url);
|
|
}
|
|
|
|
async pushVisitEvent(
|
|
appointmentId: string,
|
|
event: { type: PolimedVisitEventType; occurredAt: string; source?: string },
|
|
): Promise<void> {
|
|
const url = new URL(`/visits/${appointmentId}/events`, this.baseUrl);
|
|
const res = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ ...event, source: event.source ?? 'reception-video' }),
|
|
});
|
|
if (!res.ok) {
|
|
this.logger.warn(`pushVisitEvent failed: ${res.status} ${url}`);
|
|
throw new Error(`Polimed event failed: ${res.status}`);
|
|
}
|
|
}
|
|
|
|
private async fetchJson<T>(url: URL): Promise<T> {
|
|
const res = await fetch(url);
|
|
if (!res.ok) {
|
|
throw new Error(`Polimed ${url.pathname} failed: ${res.status}`);
|
|
}
|
|
return (await res.json()) as T;
|
|
}
|
|
}
|