Files
meet-hub/supabase/functions/daily-reminders/index.ts

212 lines
6.9 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";
import { EmailTemplateRenderer } from "../shared/email-template-renderer.ts";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};
interface ConsultingSlot {
id: string;
date: string;
start_time: string;
end_time: string;
topic_category: string;
meet_link: string | null;
user_id: string;
profiles: {
full_name: string;
email: string;
};
}
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 supabaseKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
const supabase = createClient(supabaseUrl, supabaseKey);
// Get tomorrow's date
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
const tomorrowStr = tomorrow.toISOString().split('T')[0];
console.log(`Checking consultations for: ${tomorrowStr}`);
// Get confirmed consulting slots for tomorrow
const { data: slots, error } = await supabase
.from("consulting_slots")
.select(`
id,
date,
start_time,
end_time,
topic_category,
meet_link,
user_id,
profiles:user_id (full_name, email)
`)
.eq("date", tomorrowStr)
.eq("status", "confirmed");
if (error) {
console.error("Error fetching slots:", error);
throw error;
}
console.log(`Found ${slots?.length || 0} consultations for tomorrow`);
const results: { email: string; success: boolean; error?: string }[] = [];
// Send reminder to each client
for (const slot of (slots || []) as any[]) {
try {
const profile = slot.profiles;
if (!profile?.email) continue;
// Call send-notification function
// Get notification template and settings to send via send-email-v2
const { data: template } = await supabase
.from("notification_templates")
.select("*")
.eq("key", "consulting_reminder")
.eq("is_active", true)
.single();
const { data: emailSettings } = await supabase
.from("notification_settings")
.select("*")
.single();
// Get platform settings for brand_name
const { data: platformSettings } = await supabase
.from("platform_settings")
.select("brand_name")
.single();
const brandName = platformSettings?.brand_name || "ACCESS HUB";
let notifyError = null;
if (template && emailSettings?.api_token) {
// Build payload with proper shortcode mapping
const payload = {
nama: profile.full_name,
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",
jenis_konsultasi: slot.topic_category,
platform_name: brandName,
};
// Process shortcodes in template
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));
});
// Wrap with master template
const fullHtml = EmailTemplateRenderer.render({
subject: emailSubject,
content: emailBody,
brandName: brandName,
});
// Send via send-email-v2 (Mailketing API)
const { error: emailError } = await supabase.functions.invoke("send-email-v2", {
body: {
recipient: profile.email,
api_token: emailSettings.api_token,
from_name: emailSettings.from_name || brandName,
from_email: emailSettings.from_email || "noreply@with.dwindi.com",
subject: emailSubject,
content: fullHtml,
},
});
notifyError = emailError;
} else {
notifyError = { message: "Template not active or email not configured" };
}
body: {
template_key: "consultation_reminder",
recipient_email: profile.email,
recipient_name: profile.full_name,
variables: {
consultation_date: new Date(slot.date).toLocaleDateString('id-ID', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
}),
consultation_time: `${slot.start_time.substring(0, 5)} - ${slot.end_time.substring(0, 5)}`,
topic_category: slot.topic_category,
meet_link: slot.meet_link || "Link akan dikirim segera",
},
},
});
results.push({
email: profile.email,
success: !notifyError,
error: notifyError?.message,
});
console.log(`Reminder sent to ${profile.email}: ${notifyError ? 'FAILED' : 'SUCCESS'}`);
} catch (err: any) {
results.push({
email: slot.profiles?.email || "unknown",
success: false,
error: err.message,
});
}
}
// Get platform settings for admin digest
const { data: settings } = await supabase
.from("platform_settings")
.select("smtp_from_email")
.single();
// Send digest to admin if there are consultations
if (slots && slots.length > 0 && settings?.smtp_from_email) {
const slotsList = (slots as any[])
.map(s => `- ${s.start_time?.substring(0, 5)}: ${s.profiles?.full_name || 'N/A'} (${s.topic_category})`)
.join('\n');
console.log(`Admin digest: ${slots.length} consultations tomorrow`);
// Could send admin digest here
}
return new Response(
JSON.stringify({
success: true,
message: `Processed ${results.length} reminders`,
results
}),
{ status: 200, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
} catch (error: any) {
console.error("Error in daily reminders:", error);
return new Response(
JSON.stringify({ success: false, message: error.message }),
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
});