Changes
This commit is contained in:
@@ -15,7 +15,15 @@ import { QRCodeSVG } from "qrcode.react";
|
|||||||
|
|
||||||
// Pakasir configuration
|
// Pakasir configuration
|
||||||
const PAKASIR_PROJECT_SLUG = "dewengoding";
|
const PAKASIR_PROJECT_SLUG = "dewengoding";
|
||||||
const PAKASIR_API_KEY = "iP13osgh7lAzWWIPsj7TbW5M3iGEAQMo";
|
const SANDBOX_API_KEY = "iP13osgh7lAzWWIPsj7TbW5M3iGEAQMo";
|
||||||
|
|
||||||
|
// Centralized API key retrieval - uses env var with sandbox fallback
|
||||||
|
const getPakasirApiKey = (): string => {
|
||||||
|
return import.meta.env.VITE_PAKASIR_API_KEY || SANDBOX_API_KEY;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Replace with actual Supabase Edge Function URL after creation
|
||||||
|
const PAKASIR_CALLBACK_URL = "https://lovable.backoffice.biz.id/functions/v1/pakasir-webhook";
|
||||||
|
|
||||||
type PaymentMethod = "qris" | "paypal";
|
type PaymentMethod = "qris" | "paypal";
|
||||||
type CheckoutStep = "cart" | "payment" | "waiting";
|
type CheckoutStep = "cart" | "payment" | "waiting";
|
||||||
@@ -117,7 +125,10 @@ export default function Checkout() {
|
|||||||
|
|
||||||
setOrderId(order.id);
|
setOrderId(order.id);
|
||||||
|
|
||||||
if (paymentMethod === "qris") {
|
// Build description from product titles
|
||||||
|
const productTitles = items.map(item => item.title).join(", ");
|
||||||
|
|
||||||
|
if (paymentMethod === "qris") {
|
||||||
// Call Pakasir API for QRIS
|
// Call Pakasir API for QRIS
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`https://app.pakasir.com/api/transactioncreate/qris`, {
|
const response = await fetch(`https://app.pakasir.com/api/transactioncreate/qris`, {
|
||||||
@@ -127,7 +138,9 @@ export default function Checkout() {
|
|||||||
project: PAKASIR_PROJECT_SLUG,
|
project: PAKASIR_PROJECT_SLUG,
|
||||||
order_id: order.id,
|
order_id: order.id,
|
||||||
amount: amountInRupiah,
|
amount: amountInRupiah,
|
||||||
api_key: PAKASIR_API_KEY,
|
api_key: getPakasirApiKey(),
|
||||||
|
description: productTitles,
|
||||||
|
callback_url: PAKASIR_CALLBACK_URL,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -222,7 +235,7 @@ export default function Checkout() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground text-center">
|
<p className="text-xs text-muted-foreground text-center">
|
||||||
Pembayaran akan otomatis terkonfirmasi setelah Anda scan dan bayar QR code di atas
|
Pembayaran diproses melalui Pakasir dan akan dikonfirmasi otomatis setelah berhasil.
|
||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -121,13 +121,35 @@ export default function ProductDetail() {
|
|||||||
|
|
||||||
const checkUserAccess = async () => {
|
const checkUserAccess = async () => {
|
||||||
if (!product || !user) return;
|
if (!product || !user) return;
|
||||||
const { data } = await supabase
|
|
||||||
|
// Check user_access table first
|
||||||
|
const { data: accessData } = await supabase
|
||||||
.from('user_access')
|
.from('user_access')
|
||||||
.select('id')
|
.select('id')
|
||||||
.eq('user_id', user.id)
|
.eq('user_id', user.id)
|
||||||
.eq('product_id', product.id)
|
.eq('product_id', product.id)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
setHasAccess(!!data);
|
|
||||||
|
if (accessData) {
|
||||||
|
setHasAccess(true);
|
||||||
|
setCheckingAccess(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check for paid orders containing this product
|
||||||
|
const { data: paidOrders } = await supabase
|
||||||
|
.from('orders')
|
||||||
|
.select(`
|
||||||
|
id,
|
||||||
|
order_items!inner (product_id)
|
||||||
|
`)
|
||||||
|
.eq('user_id', user.id)
|
||||||
|
.eq('payment_status', 'paid')
|
||||||
|
.eq('payment_provider', 'pakasir')
|
||||||
|
.eq('order_items.product_id', product.id)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
setHasAccess(!!(paidOrders && paidOrders.length > 0));
|
||||||
setCheckingAccess(false);
|
setCheckingAccess(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,11 +42,38 @@ export default function MemberDashboard() {
|
|||||||
}, [user, authLoading]);
|
}, [user, authLoading]);
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const [accessRes, ordersRes] = await Promise.all([
|
const [accessRes, ordersRes, paidOrdersRes] = await Promise.all([
|
||||||
supabase.from('user_access').select(`id, product:products (id, title, slug, type, meeting_link, recording_url)`).eq('user_id', user!.id),
|
supabase.from('user_access').select(`id, product:products (id, title, slug, type, meeting_link, recording_url)`).eq('user_id', user!.id),
|
||||||
supabase.from('orders').select('*').eq('user_id', user!.id).order('created_at', { ascending: false }).limit(3)
|
supabase.from('orders').select('*').eq('user_id', user!.id).order('created_at', { ascending: false }).limit(3),
|
||||||
|
// Also get products from paid orders (via order_items)
|
||||||
|
supabase.from('orders')
|
||||||
|
.select(`
|
||||||
|
order_items (
|
||||||
|
product:products (id, title, slug, type, meeting_link, recording_url)
|
||||||
|
)
|
||||||
|
`)
|
||||||
|
.eq('user_id', user!.id)
|
||||||
|
.eq('payment_status', 'paid')
|
||||||
|
.eq('payment_provider', 'pakasir')
|
||||||
]);
|
]);
|
||||||
if (accessRes.data) setAccess(accessRes.data as unknown as UserAccess[]);
|
|
||||||
|
// Combine access from user_access and paid orders
|
||||||
|
const directAccess = accessRes.data as unknown as UserAccess[] || [];
|
||||||
|
const paidProductAccess: UserAccess[] = [];
|
||||||
|
|
||||||
|
if (paidOrdersRes.data) {
|
||||||
|
const existingIds = new Set(directAccess.map(a => a.product.id));
|
||||||
|
paidOrdersRes.data.forEach((order: any) => {
|
||||||
|
order.order_items?.forEach((item: any) => {
|
||||||
|
if (item.product && !existingIds.has(item.product.id)) {
|
||||||
|
existingIds.add(item.product.id);
|
||||||
|
paidProductAccess.push({ id: `paid-${item.product.id}`, product: item.product });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setAccess([...directAccess, ...paidProductAccess]);
|
||||||
if (ordersRes.data) setRecentOrders(ordersRes.data);
|
if (ordersRes.data) setRecentOrders(ordersRes.data);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user