Implement collaboration wallets, withdrawals, and app UI flows
This commit is contained in:
172
supabase/functions/send-collaboration-notification/index.ts
Normal file
172
supabase/functions/send-collaboration-notification/index.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
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" } },
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user