108 lines
3.2 KiB
TypeScript
108 lines
3.2 KiB
TypeScript
// MÓDULO 2.1: APPOINTMENTS - /appointments/cancel
|
|
import { validateExternalAuth } from "../_shared/auth.ts";
|
|
|
|
const corsHeaders = {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Headers":
|
|
"authorization, x-client-info, apikey, content-type",
|
|
};
|
|
|
|
function externalRest(path: string, method: string, body?: any): Promise<any> {
|
|
const url = `${Deno.env.get("EXTERNAL_SUPABASE_URL")}/rest/v1/${path}`;
|
|
return fetch(url, {
|
|
method,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
apikey: Deno.env.get("EXTERNAL_SUPABASE_KEY")!,
|
|
Authorization: `Bearer ${Deno.env.get("EXTERNAL_SUPABASE_KEY")}`,
|
|
Prefer: "return=representation",
|
|
},
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
}).then((r) => r.json());
|
|
}
|
|
|
|
Deno.serve(async (req) => {
|
|
if (req.method === "OPTIONS")
|
|
return new Response("ok", { headers: corsHeaders });
|
|
|
|
try {
|
|
const authHeader = req.headers.get("Authorization");
|
|
const supabase = createClient(
|
|
Deno.env.get("SUPABASE_URL")!,
|
|
Deno.env.get("SUPABASE_ANON_KEY")!,
|
|
{ global: { headers: { Authorization: authHeader! } } }
|
|
);
|
|
|
|
const {
|
|
data: { user },
|
|
} = await supabase.auth.getUser();
|
|
if (!user) throw new Error("Unauthorized");
|
|
|
|
const { appointment_id, reason } = await req.json();
|
|
|
|
// Buscar appointment para pegar doctor_id e date
|
|
const appointment = await externalRest(
|
|
`appointments?id=eq.${appointment_id}`,
|
|
"GET"
|
|
);
|
|
const apt = appointment[0];
|
|
|
|
// Cancelar no Supabase externo
|
|
await externalRest(`appointments?id=eq.${appointment_id}`, "PATCH", {
|
|
status: "cancelled",
|
|
cancellation_reason: reason,
|
|
});
|
|
|
|
// Log
|
|
await supabase.from("user_actions").insert({
|
|
user_id: user.id,
|
|
external_user_id: apt.patient_id,
|
|
action_category: "appointment",
|
|
action_type: "cancel",
|
|
action_description: `Cancelled appointment ${appointment_id}`,
|
|
resource_type: "appointment",
|
|
resource_id: appointment_id,
|
|
});
|
|
|
|
// Adicionar próximo da waitlist se existir
|
|
const { data: waitlistMatch } = await supabase
|
|
.from("waitlist")
|
|
.select("*")
|
|
.eq("doctor_id", apt.doctor_id)
|
|
.eq("status", "waiting")
|
|
.order("priority", { ascending: false })
|
|
.order("created_at", { ascending: true })
|
|
.limit(1);
|
|
|
|
if (waitlistMatch && waitlistMatch.length > 0) {
|
|
// Notificar paciente da waitlist
|
|
await supabase.from("notifications_queue").insert({
|
|
recipient_id: waitlistMatch[0].patient_id,
|
|
type: "sms",
|
|
template: "waitlist_slot_available",
|
|
data: {
|
|
appointment_date: apt.appointment_date,
|
|
appointment_time: apt.appointment_time,
|
|
},
|
|
});
|
|
}
|
|
|
|
return new Response(
|
|
JSON.stringify({
|
|
success: true,
|
|
message: "Appointment cancelled",
|
|
waitlist_notified: !!waitlistMatch,
|
|
}),
|
|
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
|
);
|
|
} catch (error: any) {
|
|
return new Response(
|
|
JSON.stringify({ success: false, error: error.message }),
|
|
{
|
|
status: 400,
|
|
headers: { ...corsHeaders, "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
}
|
|
});
|