feat(emails): implement transactional email system with Resend
Some checks failed
Build and Deploy / build (push) Has been cancelled
Some checks failed
Build and Deploy / build (push) Has been cancelled
- Add Resend email integration with @react-email/render - Create email templates: OrderConfirmation, OrderShipped, OrderCancelled, OrderPaid - Implement webhook handler for ORDER_CREATED and other events - Add multi-language support for customer emails - Admin emails in English with order details - Update checkout page with auto-scroll on order completion - Configure DASHBOARD_URL environment variable
This commit is contained in:
@@ -7,6 +7,7 @@ import { OrderCancelled } from "@/emails/OrderCancelled";
|
||||
import { OrderPaid } from "@/emails/OrderPaid";
|
||||
|
||||
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || "https://dev.manoonoils.com";
|
||||
const DASHBOARD_URL = process.env.DASHBOARD_URL || "https://dashboard.manoonoils.com";
|
||||
|
||||
interface SaleorWebhookHeaders {
|
||||
"saleor-event": string;
|
||||
@@ -69,6 +70,7 @@ interface SaleorOrder {
|
||||
}
|
||||
|
||||
const SUPPORTED_EVENTS = [
|
||||
"ORDER_CREATED",
|
||||
"ORDER_CONFIRMED",
|
||||
"ORDER_FULLY_PAID",
|
||||
"ORDER_CANCELLED",
|
||||
@@ -141,6 +143,7 @@ async function handleOrderConfirmed(order: SaleorOrder) {
|
||||
const customerName = getCustomerName(order);
|
||||
|
||||
const customerEmail = order.userEmail;
|
||||
const phone = order.shippingAddress?.phone || order.billingAddress?.phone;
|
||||
|
||||
await sendEmailToCustomer({
|
||||
to: customerEmail,
|
||||
@@ -168,7 +171,7 @@ async function handleOrderConfirmed(order: SaleorOrder) {
|
||||
});
|
||||
|
||||
await sendEmailToAdmin({
|
||||
subject: `New Order #${order.number} - ${customerName}`,
|
||||
subject: `🎉 New Order #${order.number} - ${formatPrice(order.total.gross.amount, currency)}`,
|
||||
react: OrderConfirmation({
|
||||
language: "en",
|
||||
orderId: order.id,
|
||||
@@ -178,7 +181,11 @@ async function handleOrderConfirmed(order: SaleorOrder) {
|
||||
items: parseOrderItems(order.lines, currency),
|
||||
total: formatPrice(order.total.gross.amount, currency),
|
||||
shippingAddress: formatAddress(order.shippingAddress),
|
||||
billingAddress: formatAddress(order.billingAddress),
|
||||
phone,
|
||||
siteUrl: SITE_URL,
|
||||
dashboardUrl: DASHBOARD_URL,
|
||||
isAdmin: true,
|
||||
}),
|
||||
eventType: "ORDER_CONFIRMED",
|
||||
orderId: order.id,
|
||||
@@ -360,6 +367,7 @@ async function handleSaleorWebhook(
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case "ORDER_CREATED":
|
||||
case "ORDER_CONFIRMED":
|
||||
await handleOrderConfirmed(order);
|
||||
break;
|
||||
@@ -379,6 +387,9 @@ async function handleSaleorWebhook(
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
console.log("=== WEBHOOK RECEIVED ===");
|
||||
console.log("Timestamp:", new Date().toISOString());
|
||||
|
||||
const body = await request.json();
|
||||
const headers = request.headers;
|
||||
|
||||
@@ -388,6 +399,14 @@ export async function POST(request: NextRequest) {
|
||||
const apiUrl = headers.get("saleor-api-url");
|
||||
|
||||
console.log(`Received webhook: ${event} from ${domain}`);
|
||||
console.log("Headers:", { event, domain, apiUrl, hasSignature: !!signature });
|
||||
console.log("Payload keys:", Object.keys(body));
|
||||
|
||||
if (body.order) {
|
||||
console.log("Order ID:", body.order.id);
|
||||
console.log("Order number:", body.order.number);
|
||||
console.log("User email:", body.order.userEmail);
|
||||
}
|
||||
|
||||
if (!event) {
|
||||
return NextResponse.json({ error: "Missing saleor-event header" }, { status: 400 });
|
||||
|
||||
Reference in New Issue
Block a user