feat: migrate clients module to patients + add docs
This commit is contained in:
@@ -7,9 +7,49 @@
|
||||
*/
|
||||
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { headers, cookies } from 'next/headers';
|
||||
import type { FHIRPatient, FHIRBundle } from '@/lib/fhir';
|
||||
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000';
|
||||
/**
|
||||
* Get the base URL for API calls in server actions
|
||||
* Uses headers() to get the host from the request
|
||||
*/
|
||||
function getBaseUrl(): string {
|
||||
// Try environment variable first
|
||||
if (process.env.NEXT_PUBLIC_APP_URL) {
|
||||
return process.env.NEXT_PUBLIC_APP_URL;
|
||||
}
|
||||
|
||||
// Try to get from headers (works in server components/actions)
|
||||
try {
|
||||
const headersList = headers();
|
||||
const host = headersList.get('host');
|
||||
const protocol = headersList.get('x-forwarded-proto') || 'http';
|
||||
if (host) {
|
||||
return `${protocol}://${host}`;
|
||||
}
|
||||
} catch {
|
||||
// Headers not available, fallback to localhost
|
||||
}
|
||||
|
||||
// Fallback to localhost
|
||||
return 'http://localhost:3000';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cookies as a string for fetch headers
|
||||
*/
|
||||
async function getCookieHeader(): Promise<string> {
|
||||
try {
|
||||
const cookieStore = await cookies();
|
||||
return cookieStore
|
||||
.getAll()
|
||||
.map((cookie) => `${cookie.name}=${cookie.value}`)
|
||||
.join('; ');
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all patients via FHIR API
|
||||
@@ -17,31 +57,102 @@ const API_BASE_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000';
|
||||
export async function getPatients(filters?: {
|
||||
search?: string;
|
||||
status?: string;
|
||||
gender?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
sortBy?: string;
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
}) {
|
||||
try {
|
||||
const url = new URL(`${API_BASE_URL}/api/fhir/Patient`);
|
||||
const baseUrl = getBaseUrl();
|
||||
const url = new URL('/api/fhir/Patient', baseUrl);
|
||||
|
||||
// Search filter
|
||||
if (filters?.search) {
|
||||
url.searchParams.set('name', filters.search);
|
||||
}
|
||||
|
||||
// Status filter
|
||||
if (filters?.status) {
|
||||
url.searchParams.set('status', filters.status);
|
||||
}
|
||||
|
||||
// Gender filter
|
||||
if (filters?.gender) {
|
||||
url.searchParams.set('gender', filters.gender);
|
||||
}
|
||||
|
||||
// Pagination (default: 50 per page)
|
||||
const page = filters?.page || 1;
|
||||
const pageSize = filters?.pageSize || 50;
|
||||
url.searchParams.set('_count', pageSize.toString());
|
||||
url.searchParams.set('_offset', ((page - 1) * pageSize).toString());
|
||||
|
||||
// Sorting
|
||||
if (filters?.sortBy) {
|
||||
const sortOrder = filters?.sortOrder === 'desc' ? '-' : '';
|
||||
url.searchParams.set('_sort', `${sortOrder}${filters.sortBy}`);
|
||||
}
|
||||
|
||||
// Get cookies to pass authentication
|
||||
const cookieHeader = await getCookieHeader();
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
cache: 'no-store',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(cookieHeader && { Cookie: cookieHeader }),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch patients: ${response.statusText}`);
|
||||
const errorText = await response.text();
|
||||
let errorMessage = `Failed to fetch patients: ${response.status} ${response.statusText}`;
|
||||
|
||||
// Check if we got HTML (likely a redirect to login)
|
||||
if (errorText.trim().startsWith('<!DOCTYPE') || errorText.trim().startsWith('<html')) {
|
||||
throw new Error('Niet geautoriseerd. Log opnieuw in.');
|
||||
}
|
||||
|
||||
try {
|
||||
const errorJson = JSON.parse(errorText);
|
||||
if (errorJson.issue?.[0]?.diagnostics) {
|
||||
errorMessage = errorJson.issue[0].diagnostics;
|
||||
}
|
||||
} catch {
|
||||
// If not JSON, use the text (but truncate if HTML)
|
||||
if (errorText && !errorText.trim().startsWith('<!')) {
|
||||
errorMessage = errorText.substring(0, 200);
|
||||
}
|
||||
}
|
||||
|
||||
console.error('Error fetching patients:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
url: url.toString(),
|
||||
error: errorMessage.substring(0, 100),
|
||||
});
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const bundle: FHIRBundle<FHIRPatient> = await response.json();
|
||||
return bundle.entry?.map((entry) => entry.resource).filter(Boolean) as FHIRPatient[] || [];
|
||||
|
||||
return {
|
||||
patients: bundle.entry?.map((entry) => entry.resource).filter(Boolean) as FHIRPatient[] || [],
|
||||
total: bundle.total || 0,
|
||||
page,
|
||||
pageSize,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching patients:', error);
|
||||
throw new Error('Failed to fetch patients');
|
||||
|
||||
// Provide more context in error message
|
||||
if (error instanceof TypeError && error.message.includes('fetch')) {
|
||||
throw new Error('Kon geen verbinding maken met de server. Controleer of de applicatie draait.');
|
||||
}
|
||||
|
||||
throw error instanceof Error ? error : new Error('Failed to fetch patients');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,11 +161,22 @@ export async function getPatients(filters?: {
|
||||
*/
|
||||
export async function getPatient(id: string) {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/fhir/Patient/${id}`, {
|
||||
const baseUrl = getBaseUrl();
|
||||
const cookieHeader = await getCookieHeader();
|
||||
|
||||
const response = await fetch(`${baseUrl}/api/fhir/Patient/${id}`, {
|
||||
cache: 'no-store',
|
||||
headers: {
|
||||
...(cookieHeader && { Cookie: cookieHeader }),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
// Check if we got HTML (likely a redirect to login)
|
||||
if (errorText.trim().startsWith('<!DOCTYPE') || errorText.trim().startsWith('<html')) {
|
||||
throw new Error('Niet geautoriseerd. Log opnieuw in.');
|
||||
}
|
||||
throw new Error(`Failed to fetch patient: ${response.statusText}`);
|
||||
}
|
||||
|
||||
@@ -62,7 +184,7 @@ export async function getPatient(id: string) {
|
||||
return patient;
|
||||
} catch (error) {
|
||||
console.error('Error fetching patient:', error);
|
||||
throw new Error('Failed to fetch patient');
|
||||
throw error instanceof Error ? error : new Error('Failed to fetch patient');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +193,14 @@ export async function getPatient(id: string) {
|
||||
*/
|
||||
export async function createPatient(fhirPatient: FHIRPatient) {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/fhir/Patient`, {
|
||||
const baseUrl = getBaseUrl();
|
||||
const cookieHeader = await getCookieHeader();
|
||||
|
||||
const response = await fetch(`${baseUrl}/api/fhir/Patient`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(cookieHeader && { Cookie: cookieHeader }),
|
||||
},
|
||||
body: JSON.stringify(fhirPatient),
|
||||
});
|
||||
@@ -98,10 +224,14 @@ export async function createPatient(fhirPatient: FHIRPatient) {
|
||||
*/
|
||||
export async function updatePatient(id: string, fhirPatient: FHIRPatient) {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/fhir/Patient/${id}`, {
|
||||
const baseUrl = getBaseUrl();
|
||||
const cookieHeader = await getCookieHeader();
|
||||
|
||||
const response = await fetch(`${baseUrl}/api/fhir/Patient/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(cookieHeader && { Cookie: cookieHeader }),
|
||||
},
|
||||
body: JSON.stringify({ ...fhirPatient, id }),
|
||||
});
|
||||
@@ -120,3 +250,31 @@ export async function updatePatient(id: string, fhirPatient: FHIRPatient) {
|
||||
throw error instanceof Error ? error : new Error('Failed to update patient');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete patient via FHIR API
|
||||
*/
|
||||
export async function deletePatient(id: string) {
|
||||
try {
|
||||
const baseUrl = getBaseUrl();
|
||||
const cookieHeader = await getCookieHeader();
|
||||
|
||||
const response = await fetch(`${baseUrl}/api/fhir/Patient/${id}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
...(cookieHeader && { Cookie: cookieHeader }),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.issue?.[0]?.diagnostics || 'Failed to delete patient');
|
||||
}
|
||||
|
||||
revalidatePath('/epd/patients');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error deleting patient:', error);
|
||||
throw error instanceof Error ? error : new Error('Failed to delete patient');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user