Files
meet-hub/supabase/functions/send-consultation-reminder/index.ts

191 lines
6.4 KiB
TypeScript

import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};
serve(async (req: Request): Promise<Response> => {
if (req.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders });
}
try {
const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
const supabase = createClient(supabaseUrl, supabaseServiceKey);
// Get current date/time in Jakarta timezone
const now = new Date();
const jakartaOffset = 7 * 60; // UTC+7
const jakartaTime = new Date(now.getTime() + jakartaOffset * 60 * 1000);
const today = jakartaTime.toISOString().split('T')[0];
// Find consultations happening in the next 24 hours that haven't been reminded
const tomorrow = new Date(jakartaTime);
tomorrow.setDate(tomorrow.getDate() + 1);
const tomorrowStr = tomorrow.toISOString().split('T')[0];
console.log("Checking consultations for dates:", today, "to", tomorrowStr);
// Get confirmed slots for today and tomorrow
const { data: upcomingSlots, error: slotsError } = await supabase
.from("consulting_slots")
.select(`
*,
profiles:user_id (full_name, email)
`)
.eq("status", "confirmed")
.gte("date", today)
.lte("date", tomorrowStr)
.order("date")
.order("start_time");
if (slotsError) {
console.error("Error fetching slots:", slotsError);
throw slotsError;
}
console.log("Found upcoming slots:", upcomingSlots?.length || 0);
if (!upcomingSlots || upcomingSlots.length === 0) {
return new Response(
JSON.stringify({ success: true, message: "No upcoming consultations to remind" }),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
// Get notification template for consultation reminder
const { data: template } = await supabase
.from("notification_templates")
.select("*")
.eq("key", "consulting_scheduled")
.single();
// Get SMTP settings
const { data: smtpSettings } = await supabase
.from("notification_settings")
.select("*")
.single();
// Get platform settings
const { data: platformSettings } = await supabase
.from("platform_settings")
.select("brand_name, brand_email_from_name, integration_whatsapp_number")
.single();
const results: any[] = [];
for (const slot of upcomingSlots) {
const profile = slot.profiles as any;
// Build payload for notification
const payload = {
nama: profile?.full_name || "Pelanggan",
email: profile?.email || "",
tanggal_konsultasi: new Date(slot.date).toLocaleDateString("id-ID", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
}),
jam_konsultasi: `${slot.start_time.substring(0, 5)} - ${slot.end_time.substring(0, 5)} WIB`,
link_meet: slot.meet_link || "Akan diinformasikan",
topik: slot.topic_category,
catatan: slot.notes || "-",
brand_name: platformSettings?.brand_name || "LearnHub",
whatsapp: platformSettings?.integration_whatsapp_number || "",
};
// Log the reminder payload
console.log("Reminder payload for slot:", slot.id, payload);
// Update last_payload_example in template
if (template) {
await supabase
.from("notification_templates")
.update({ last_payload_example: payload })
.eq("id", template.id);
}
// Send webhook if configured
if (template?.webhook_url) {
try {
await fetch(template.webhook_url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
event: "consulting_reminder",
slot_id: slot.id,
...payload,
}),
});
console.log("Webhook sent for slot:", slot.id);
} catch (webhookError) {
console.error("Webhook error:", webhookError);
}
}
// Send email if template is active and Mailketing is configured
if (template?.is_active && smtpSettings?.api_token && profile?.email) {
try {
// Replace shortcodes in email body using master template system
let emailBody = template.email_body_html || "";
let emailSubject = template.email_subject || "Reminder Konsultasi";
Object.entries(payload).forEach(([key, value]) => {
const regex = new RegExp(`\\{${key}\\}`, "g");
emailBody = emailBody.replace(regex, String(value));
emailSubject = emailSubject.replace(regex, String(value));
});
// Send via send-email-v2 (Mailketing API)
const { error: emailError } = await supabase.functions.invoke("send-email-v2", {
body: {
recipient: profile.email,
api_token: smtpSettings.api_token,
from_name: smtpSettings.from_name || platformSettings?.brand_name || "Access Hub",
from_email: smtpSettings.from_email || "noreply@with.dwindi.com",
subject: emailSubject,
content: emailBody,
},
});
if (emailError) {
console.error("Failed to send reminder email:", emailError);
} else {
console.log("Reminder email sent to:", profile.email);
}
} catch (emailError) {
console.error("Error sending reminder email:", emailError);
}
}
results.push({
slot_id: slot.id,
client: profile?.full_name,
date: slot.date,
time: slot.start_time,
reminded: true,
});
}
return new Response(
JSON.stringify({
success: true,
message: `Processed ${results.length} consultation reminders`,
results
}),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
} catch (error: any) {
console.error("Error sending reminders:", error);
return new Response(
JSON.stringify({ success: false, message: error.message }),
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
});