feat: implement Cash on Delivery (COD) payment method
This commit adds comprehensive COD support using Saleor's native Transaction system:
**Architecture:**
- Uses Saleor's native Transaction objects (not metadata)
- Modular payment method configuration
- Extensible design for future payment types (cards, bank transfer, etc.)
**New Components:**
- PaymentMethodSelector: Reusable payment method selection UI
- PaymentMethodCard: Individual payment method card
- CODInstructions: COD-specific instructions and guidance
- PaymentSection: Checkout integration wrapper
**Core Features:**
- COD selected by default for Serbia (default-channel)
- Transaction created automatically on order completion
- Transaction visible in Saleor Dashboard
- Multi-language support (EN, SR, DE, FR)
- No additional fees
- Instructions shown to customer (prepare cash, inspect order, no fee)
**Files Added:**
- docs/COD-IMPLEMENTATION-PLAN.md
- src/lib/config/paymentMethods.ts
- src/lib/saleor/payments/types.ts
- src/lib/saleor/payments/cod.ts
- src/components/payment/PaymentMethodSelector.tsx
- src/components/payment/PaymentMethodCard.tsx
- src/components/payment/CODInstructions.tsx
- src/components/payment/index.ts
- src/app/[locale]/checkout/components/PaymentSection.tsx
**Files Modified:**
- src/app/[locale]/checkout/page.tsx (added payment section, transaction creation)
- src/i18n/messages/{en,sr,de,fr}.json (payment translations)
**Technical Details:**
- Transaction status: NOT_CHARGED
- Available actions: [CHARGE]
- PSP Reference format: COD-{orderNumber}-{timestamp}
- Staff collects cash and fulfills order via Dashboard
Closes: Cash on Delivery payment implementation
This commit is contained in:
55
src/components/payment/CODInstructions.tsx
Normal file
55
src/components/payment/CODInstructions.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Banknote, Package, CheckCircle } from "lucide-react";
|
||||
|
||||
interface CODInstructionsProps {
|
||||
locale: string;
|
||||
}
|
||||
|
||||
export function CODInstructions({ locale }: CODInstructionsProps) {
|
||||
const t = useTranslations("Payment.COD");
|
||||
|
||||
const instructions = [
|
||||
{
|
||||
icon: Banknote,
|
||||
title: t("instructions.prepareCash"),
|
||||
description: t("instructions.prepareCashDesc"),
|
||||
},
|
||||
{
|
||||
icon: Package,
|
||||
title: t("instructions.inspectOrder"),
|
||||
description: t("instructions.inspectOrderDesc"),
|
||||
},
|
||||
{
|
||||
icon: CheckCircle,
|
||||
title: t("instructions.noFee"),
|
||||
description: t("instructions.noFeeDesc"),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="mt-4 rounded-lg bg-blue-50 p-4">
|
||||
<h4 className="mb-3 font-medium text-blue-900">
|
||||
{t("instructions.title")}
|
||||
</h4>
|
||||
|
||||
<div className="space-y-3">
|
||||
{instructions.map((instruction, index) => {
|
||||
const Icon = instruction.icon;
|
||||
return (
|
||||
<div key={index} className="flex items-start gap-3">
|
||||
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-100">
|
||||
<Icon className="h-4 w-4 text-blue-600" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-blue-900">{instruction.title}</p>
|
||||
<p className="text-sm text-blue-700">{instruction.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user