feat: full appointment feature (CRUD + Appointments tab)
Builds the complete appointment feature end-to-end, mirroring the medication feature structure. The model existed but was orphaned dead code (no handlers, routes, repo, or frontend) — this builds the whole stack. Backend: - models/appointment.rs: AppointmentData (deserializes the data blob, camelCase keys), AppointmentResponse (flat snake_case + From<Appointment>), Create/Update request structs, AppointmentRepository (create, find_by_user_filtered with optional status filter, find/update/delete by appointment_id). Mirrors the medication serialization pattern. Module added to models/mod.rs. - handlers/appointments.rs: full CRUD (create/list/get/update/delete) returning AppointmentResponse. Routes wired in app.rs (POST/GET /api/appointments, GET/POST /:id, POST /:id/delete). - 3 unit tests (AppointmentData deser, default status, response flatten). Frontend: - Appointment/Create/Update types; getAppointments/getAppointment/create/ update/deleteAppointment in api.ts; useAppointmentStore. - AppointmentsManager component (list with type+status chips, create/edit dialogs, delete confirm, empty state) as a 5th Dashboard tab. Verified: backend fmt/clippy 0 warnings, 26 tests pass; frontend build clean, 20 tests pass.
This commit is contained in:
parent
0921d73a6d
commit
4c4c29f72e
10 changed files with 1019 additions and 4 deletions
|
|
@ -18,6 +18,9 @@ import {
|
|||
LogDoseRequest,
|
||||
AdherenceStats,
|
||||
Profile,
|
||||
Appointment,
|
||||
CreateAppointmentRequest,
|
||||
UpdateAppointmentRequest,
|
||||
} from '../types/api';
|
||||
|
||||
// API base URL. In dev this is "/api", proxied by the Vite dev server to the
|
||||
|
|
@ -262,6 +265,34 @@ class ApiService {
|
|||
return response.data;
|
||||
}
|
||||
|
||||
// ---- Appointments ----
|
||||
|
||||
async getAppointments(status?: string): Promise<Appointment[]> {
|
||||
const response = await this.client.get<Appointment[]>('/appointments', {
|
||||
params: status ? { status } : undefined,
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getAppointment(id: string): Promise<Appointment> {
|
||||
const response = await this.client.get<Appointment>(`/appointments/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async createAppointment(data: CreateAppointmentRequest): Promise<Appointment> {
|
||||
const response = await this.client.post<Appointment>('/appointments', data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async updateAppointment(id: string, data: UpdateAppointmentRequest): Promise<Appointment> {
|
||||
const response = await this.client.post<Appointment>(`/appointments/${id}`, data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async deleteAppointment(id: string): Promise<void> {
|
||||
await this.client.post(`/appointments/${id}/delete`);
|
||||
}
|
||||
|
||||
// ---- Drug Interactions (Phase 2.8) ----
|
||||
|
||||
async checkInteractions(medications: string[]): Promise<DrugInteraction[]> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue