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,4 +1,5 @@
|
||||
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": "*",
|
||||
@@ -7,22 +8,24 @@ const corsHeaders = {
|
||||
|
||||
interface EmailRequest {
|
||||
recipient: string;
|
||||
api_token: string;
|
||||
from_name: string;
|
||||
from_email: string;
|
||||
subject: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
// Send via Mailketing API
|
||||
async function sendViaMailketing(request: EmailRequest): Promise<{ success: boolean; message: string }> {
|
||||
const { recipient, api_token, from_name, from_email, subject, content } = request;
|
||||
async function sendViaMailketing(
|
||||
request: EmailRequest,
|
||||
apiToken: string,
|
||||
fromName: string,
|
||||
fromEmail: string
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
const { recipient, subject, content } = request;
|
||||
|
||||
// Build form-encoded body (http_build_query format)
|
||||
const params = new URLSearchParams();
|
||||
params.append('api_token', api_token);
|
||||
params.append('from_name', from_name);
|
||||
params.append('from_email', from_email);
|
||||
params.append('api_token', apiToken);
|
||||
params.append('from_name', fromName);
|
||||
params.append('from_email', fromEmail);
|
||||
params.append('recipient', recipient);
|
||||
params.append('subject', subject);
|
||||
params.append('content', content);
|
||||
@@ -58,19 +61,46 @@ serve(async (req: Request): Promise<Response> => {
|
||||
}
|
||||
|
||||
try {
|
||||
// Initialize Supabase client
|
||||
const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
|
||||
const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
|
||||
const supabase = createClient(supabaseUrl, supabaseServiceKey);
|
||||
|
||||
// Fetch email settings from platform_settings
|
||||
const { data: settings, error: settingsError } = await supabase
|
||||
.from('platform_settings')
|
||||
.select('*')
|
||||
.single();
|
||||
|
||||
if (settingsError || !settings) {
|
||||
console.error('Error fetching platform settings:', settingsError);
|
||||
throw new Error('Failed to fetch email configuration from platform_settings');
|
||||
}
|
||||
|
||||
const apiToken = settings.integration_email_api_token;
|
||||
const fromName = settings.integration_email_from_name || settings.brand_name;
|
||||
const fromEmail = settings.integration_email_from_email;
|
||||
|
||||
if (!apiToken || !fromEmail) {
|
||||
return new Response(
|
||||
JSON.stringify({ success: false, message: "Email not configured. Please set API token and from email in platform settings." }),
|
||||
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
const body: EmailRequest = await req.json();
|
||||
|
||||
// Validate required fields
|
||||
if (!body.recipient || !body.api_token || !body.from_name || !body.from_email || !body.subject || !body.content) {
|
||||
if (!body.recipient || !body.subject || !body.content) {
|
||||
return new Response(
|
||||
JSON.stringify({ success: false, message: "Missing required fields: recipient, api_token, from_name, from_email, subject, content" }),
|
||||
JSON.stringify({ success: false, message: "Missing required fields: recipient, subject, content" }),
|
||||
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
// Basic email validation
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(body.recipient) || !emailRegex.test(body.from_email)) {
|
||||
if (!emailRegex.test(body.recipient) || !emailRegex.test(fromEmail)) {
|
||||
return new Response(
|
||||
JSON.stringify({ success: false, message: "Invalid email format" }),
|
||||
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
||||
@@ -78,10 +108,10 @@ serve(async (req: Request): Promise<Response> => {
|
||||
}
|
||||
|
||||
console.log(`Attempting to send email to: ${body.recipient}`);
|
||||
console.log(`From: ${body.from_name} <${body.from_email}>`);
|
||||
console.log(`From: ${fromName} <${fromEmail}>`);
|
||||
console.log(`Subject: ${body.subject}`);
|
||||
|
||||
const result = await sendViaMailketing(body);
|
||||
const result = await sendViaMailketing(body, apiToken, fromName, fromEmail);
|
||||
|
||||
return new Response(
|
||||
JSON.stringify(result),
|
||||
|
||||
Reference in New Issue
Block a user