Fix email system and implement OTP confirmation flow
Email System Fixes: - Fix email sending after payment: handle-order-paid now calls send-notification instead of send-email-v2 directly, properly processing template variables - Fix order_created email timing: sent immediately after order creation, before payment QR code generation - Update email templates to use short order ID (8 chars) instead of full UUID - Add working "Akses Sekarang" buttons to payment_success and access_granted emails - Add platform_url column to platform_settings for email links OTP Verification Flow: - Create dedicated /confirm-otp page for users who close registration modal - Add link in checkout modal and email to dedicated OTP page - Update OTP email template with better copywriting and dedicated page link - Fix send-auth-otp to fetch platform settings for dynamic brand_name and platform_url - Auto-login users after OTP verification in checkout flow Admin Features: - Add delete user functionality with cascade deletion of all related data - Update IntegrasiTab to read/write email settings from platform_settings only - Add test email template for email configuration testing Cleanup: - Remove obsolete send-consultation-reminder and send-test-email functions - Update send-email-v2 to read email config from platform_settings - Remove footer links (Ubah Preferensi/Unsubscribe) from email templates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
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";
|
||||
import QRCode from 'https://esm.sh/qrcode@1.5.3';
|
||||
|
||||
const corsHeaders = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
@@ -259,44 +258,29 @@ serve(async (req: Request): Promise<Response> => {
|
||||
);
|
||||
}
|
||||
|
||||
// Get platform settings
|
||||
const { data: settings } = await supabase
|
||||
// Get platform settings (includes email configuration)
|
||||
const { data: platformSettings, error: platformError } = await supabase
|
||||
.from("platform_settings")
|
||||
.select("*")
|
||||
.single();
|
||||
|
||||
if (!settings) {
|
||||
if (platformError || !platformSettings) {
|
||||
console.error('Error fetching platform settings:', platformError);
|
||||
return new Response(
|
||||
JSON.stringify({ success: false, message: "Platform settings not configured" }),
|
||||
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
const brandName = platformSettings.brand_name || "ACCESS HUB";
|
||||
|
||||
// Build email payload
|
||||
const allVariables = {
|
||||
recipient_name: recipient_name || "Pelanggan",
|
||||
platform_name: settings.brand_name || "Platform",
|
||||
platform_name: brandName,
|
||||
...variables,
|
||||
};
|
||||
|
||||
// Special handling for order_created: generate QR code image
|
||||
if (template_key === 'order_created' && allVariables.qr_string) {
|
||||
console.log('[SEND-NOTIFICATION] Generating QR code for order_created email');
|
||||
try {
|
||||
const qrDataUrl = await QRCode.toDataURL(allVariables.qr_string, {
|
||||
width: 300,
|
||||
margin: 2,
|
||||
color: { dark: '#000000', light: '#FFFFFF' }
|
||||
});
|
||||
allVariables.qr_code_image = qrDataUrl;
|
||||
console.log('[SEND-NOTIFICATION] QR code generated successfully');
|
||||
} catch (qrError) {
|
||||
console.error('[SEND-NOTIFICATION] Failed to generate QR code:', qrError);
|
||||
// Continue without QR code - don't fail the email
|
||||
allVariables.qr_code_image = '';
|
||||
}
|
||||
}
|
||||
|
||||
const subject = replaceVariables(template.email_subject || template.subject || "", allVariables);
|
||||
const htmlContent = replaceVariables(template.email_body_html || template.body_html || template.body_text || "", allVariables);
|
||||
|
||||
@@ -304,67 +288,30 @@ serve(async (req: Request): Promise<Response> => {
|
||||
const htmlBody = EmailTemplateRenderer.render({
|
||||
subject: subject,
|
||||
content: htmlContent,
|
||||
brandName: settings.brand_name || "ACCESS HUB",
|
||||
brandName: brandName,
|
||||
});
|
||||
|
||||
const emailPayload: EmailPayload = {
|
||||
to: recipient_email,
|
||||
subject,
|
||||
html: htmlBody,
|
||||
from_name: settings.brand_email_from_name || settings.brand_name || "Notifikasi",
|
||||
from_email: settings.smtp_from_email || "noreply@example.com",
|
||||
from_name: platformSettings.integration_email_from_name || brandName || "Notifikasi",
|
||||
from_email: platformSettings.integration_email_from_email || "noreply@example.com",
|
||||
};
|
||||
|
||||
// Determine provider and send
|
||||
const provider = settings.integration_email_provider || "mailketing";
|
||||
const provider = platformSettings.integration_email_provider || "mailketing";
|
||||
console.log(`Sending email via ${provider} to ${recipient_email}`);
|
||||
|
||||
switch (provider) {
|
||||
case "mailketing":
|
||||
const mailketingToken = settings.mailketing_api_token || settings.api_token;
|
||||
const mailketingToken = platformSettings.integration_email_api_token;
|
||||
if (!mailketingToken) throw new Error("Mailketing API token not configured");
|
||||
await sendViaMailketing(emailPayload, mailketingToken);
|
||||
break;
|
||||
|
||||
case "smtp":
|
||||
await sendViaSMTP(emailPayload, {
|
||||
host: settings.smtp_host,
|
||||
port: settings.smtp_port || 587,
|
||||
username: settings.smtp_username,
|
||||
password: settings.smtp_password,
|
||||
from_name: emailPayload.from_name,
|
||||
from_email: emailPayload.from_email,
|
||||
use_tls: settings.smtp_use_tls ?? true,
|
||||
});
|
||||
break;
|
||||
|
||||
case "resend":
|
||||
const resendKey = Deno.env.get("RESEND_API_KEY");
|
||||
if (!resendKey) throw new Error("RESEND_API_KEY not configured");
|
||||
await sendViaResend(emailPayload, resendKey);
|
||||
break;
|
||||
|
||||
case "elasticemail":
|
||||
const elasticKey = Deno.env.get("ELASTICEMAIL_API_KEY");
|
||||
if (!elasticKey) throw new Error("ELASTICEMAIL_API_KEY not configured");
|
||||
await sendViaElasticEmail(emailPayload, elasticKey);
|
||||
break;
|
||||
|
||||
case "sendgrid":
|
||||
const sendgridKey = Deno.env.get("SENDGRID_API_KEY");
|
||||
if (!sendgridKey) throw new Error("SENDGRID_API_KEY not configured");
|
||||
await sendViaSendGrid(emailPayload, sendgridKey);
|
||||
break;
|
||||
|
||||
case "mailgun":
|
||||
const mailgunKey = Deno.env.get("MAILGUN_API_KEY");
|
||||
const mailgunDomain = Deno.env.get("MAILGUN_DOMAIN");
|
||||
if (!mailgunKey || !mailgunDomain) throw new Error("MAILGUN credentials not configured");
|
||||
await sendViaMailgun(emailPayload, mailgunKey, mailgunDomain);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown email provider: ${provider}`);
|
||||
throw new Error(`Unknown email provider: ${provider}. Only 'mailketing' is supported.`);
|
||||
}
|
||||
|
||||
// Log notification
|
||||
|
||||
Reference in New Issue
Block a user