173 lines
5.8 KiB
TypeScript
173 lines
5.8 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",
|
|
};
|
|
|
|
interface NotificationPayload {
|
|
type: "new_sale" | "withdrawal_requested" | "withdrawal_completed" | "withdrawal_rejected";
|
|
collaboratorUserId?: string;
|
|
userId?: string;
|
|
amount?: number;
|
|
productTitle?: string;
|
|
profitAmount?: number;
|
|
profitSharePercentage?: number;
|
|
saleDate?: string;
|
|
paymentReference?: string;
|
|
reason?: string;
|
|
bankInfo?: {
|
|
bankName: string;
|
|
accountNumber: string;
|
|
accountName: string;
|
|
};
|
|
}
|
|
|
|
async function sendEmail(recipient: string, subject: string, content: string): Promise<void> {
|
|
const response = await fetch(`${Deno.env.get("SUPABASE_URL")}/functions/v1/send-email-v2`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Authorization": `Bearer ${Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")}`,
|
|
},
|
|
body: JSON.stringify({
|
|
recipient,
|
|
subject,
|
|
content,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const text = await response.text();
|
|
throw new Error(`send-email-v2 failed: ${response.status} ${text}`);
|
|
}
|
|
}
|
|
|
|
serve(async (req: Request): Promise<Response> => {
|
|
if (req.method === "OPTIONS") {
|
|
return new Response(null, { headers: corsHeaders });
|
|
}
|
|
|
|
try {
|
|
const supabase = createClient(
|
|
Deno.env.get("SUPABASE_URL")!,
|
|
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!,
|
|
{
|
|
auth: {
|
|
autoRefreshToken: false,
|
|
persistSession: false,
|
|
},
|
|
},
|
|
);
|
|
|
|
const data = await req.json() as NotificationPayload;
|
|
const { type } = data;
|
|
|
|
let recipientEmail = "";
|
|
let subject = "";
|
|
let htmlContent = "";
|
|
|
|
if (type === "new_sale") {
|
|
const { data: collaborator } = await supabase
|
|
.from("profiles")
|
|
.select("email, name")
|
|
.eq("id", data.collaboratorUserId || "")
|
|
.maybeSingle();
|
|
|
|
recipientEmail = collaborator?.email || "";
|
|
subject = `🎉 You earned Rp ${(data.profitAmount || 0).toLocaleString("id-ID")} from ${data.productTitle || "your product"}!`;
|
|
htmlContent = `
|
|
<h2>Great news, ${collaborator?.name || "Partner"}!</h2>
|
|
<p>Your collaborative webinar <strong>${data.productTitle || "-"}</strong> just made a sale.</p>
|
|
<ul>
|
|
<li>Your Share: ${data.profitSharePercentage || 0}%</li>
|
|
<li>Profit Earned: <strong>Rp ${(data.profitAmount || 0).toLocaleString("id-ID")}</strong></li>
|
|
<li>Sale Date: ${data.saleDate ? new Date(data.saleDate).toLocaleDateString("id-ID") : "-"}</li>
|
|
</ul>
|
|
`;
|
|
} else if (type === "withdrawal_requested") {
|
|
const { data: adminRole } = await supabase
|
|
.from("user_roles")
|
|
.select("user_id")
|
|
.eq("role", "admin")
|
|
.limit(1)
|
|
.maybeSingle();
|
|
|
|
const { data: admin } = await supabase
|
|
.from("profiles")
|
|
.select("email")
|
|
.eq("id", adminRole?.user_id || "")
|
|
.maybeSingle();
|
|
|
|
recipientEmail = admin?.email || "";
|
|
subject = "💸 New Withdrawal Request";
|
|
htmlContent = `
|
|
<h2>New Withdrawal Request</h2>
|
|
<p>A collaborator has requested withdrawal:</p>
|
|
<ul>
|
|
<li>Amount: <strong>Rp ${(data.amount || 0).toLocaleString("id-ID")}</strong></li>
|
|
<li>Bank: ${data.bankInfo?.bankName || "-"}</li>
|
|
<li>Account: ${data.bankInfo?.accountNumber || "-"} (${data.bankInfo?.accountName || "-"})</li>
|
|
</ul>
|
|
`;
|
|
} else if (type === "withdrawal_completed") {
|
|
const { data: user } = await supabase
|
|
.from("profiles")
|
|
.select("email, name")
|
|
.eq("id", data.userId || "")
|
|
.maybeSingle();
|
|
|
|
recipientEmail = user?.email || "";
|
|
subject = `✅ Withdrawal Completed: Rp ${(data.amount || 0).toLocaleString("id-ID")}`;
|
|
htmlContent = `
|
|
<h2>Withdrawal Completed, ${user?.name || "Partner"}!</h2>
|
|
<ul>
|
|
<li>Amount: <strong>Rp ${(data.amount || 0).toLocaleString("id-ID")}</strong></li>
|
|
<li>Payment Reference: ${data.paymentReference || "-"}</li>
|
|
</ul>
|
|
`;
|
|
} else if (type === "withdrawal_rejected") {
|
|
const { data: user } = await supabase
|
|
.from("profiles")
|
|
.select("email, name")
|
|
.eq("id", data.userId || "")
|
|
.maybeSingle();
|
|
|
|
recipientEmail = user?.email || "";
|
|
subject = "❌ Withdrawal Request Returned";
|
|
htmlContent = `
|
|
<h2>Withdrawal Request Returned</h2>
|
|
<p>Hi ${user?.name || "Partner"},</p>
|
|
<p>Your withdrawal request of <strong>Rp ${(data.amount || 0).toLocaleString("id-ID")}</strong> has been returned to your wallet.</p>
|
|
<p>Reason: ${data.reason || "Contact admin for details"}</p>
|
|
`;
|
|
} else {
|
|
return new Response(
|
|
JSON.stringify({ error: "Unknown notification type" }),
|
|
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } },
|
|
);
|
|
}
|
|
|
|
if (!recipientEmail) {
|
|
return new Response(
|
|
JSON.stringify({ error: "Recipient email not found" }),
|
|
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } },
|
|
);
|
|
}
|
|
|
|
await sendEmail(recipientEmail, subject, htmlContent);
|
|
|
|
return new Response(
|
|
JSON.stringify({ success: true }),
|
|
{ status: 200, headers: { ...corsHeaders, "Content-Type": "application/json" } },
|
|
);
|
|
} catch (error: unknown) {
|
|
const message = error instanceof Error ? error.message : "Failed to send notification";
|
|
return new Response(
|
|
JSON.stringify({ error: message }),
|
|
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } },
|
|
);
|
|
}
|
|
});
|