feat(payment): enhance payment configuration to include active gateways and update CORS settings
This commit is contained in:
@@ -2,11 +2,25 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { api } from '../lib/api';
|
||||
import type { ApiResponse } from '../lib/api';
|
||||
|
||||
export interface PaymentGatewayInfo {
|
||||
name: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface PaymentConfig {
|
||||
test_mode: boolean;
|
||||
appointment_fee_rials: number;
|
||||
gateways: PaymentGatewayInfo[];
|
||||
}
|
||||
|
||||
export function usePaymentConfig() {
|
||||
const { data } = useQuery<ApiResponse<{ test_mode: boolean }>>({
|
||||
const { data } = useQuery<ApiResponse<PaymentConfig>>({
|
||||
queryKey: ['payment-config'],
|
||||
queryFn: () => api.get('/api/v1/payment/config'),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
return { isTestMode: data?.data?.test_mode ?? false };
|
||||
return {
|
||||
isTestMode: data?.data?.test_mode ?? false,
|
||||
gateways: data?.data?.gateways ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import {
|
||||
CheckIcon, XMarkIcon, SparklesIcon, RocketLaunchIcon,
|
||||
@@ -42,14 +42,12 @@ const PLAN_META: Record<string, {
|
||||
},
|
||||
};
|
||||
|
||||
const GATEWAY_LABELS: Record<string, string> = { mellat: 'بانک ملت', sep: 'سپ (صادرات)' };
|
||||
|
||||
// ── Main Page ─────────────────────────────────────────────────────────────
|
||||
|
||||
export default function SubscriptionPage() {
|
||||
const qc = useQueryClient();
|
||||
const [purchaseTarget, setPurchaseTarget] = useState<{ period: SubscriptionPeriod; planName: string } | null>(null);
|
||||
const [selectedGateway, setSelectedGateway] = useState<'mellat' | 'sep'>('mellat');
|
||||
const [selectedGateway, setSelectedGateway] = useState<string>('');
|
||||
|
||||
const { data: plansData, isLoading: plansLoading } = useQuery<ApiResponse<SubscriptionPlan[]>>({
|
||||
queryKey: ['subscription-plans'],
|
||||
@@ -61,7 +59,13 @@ export default function SubscriptionPage() {
|
||||
queryFn: () => api.get('/api/v1/subscription/my'),
|
||||
});
|
||||
|
||||
const { isTestMode } = usePaymentConfig();
|
||||
const { isTestMode, gateways } = usePaymentConfig();
|
||||
|
||||
useEffect(() => {
|
||||
if (gateways.length > 0 && !gateways.some((g) => g.name === selectedGateway)) {
|
||||
setSelectedGateway(gateways[0].name);
|
||||
}
|
||||
}, [gateways, selectedGateway]);
|
||||
|
||||
const plans = plansData?.data ?? [];
|
||||
const myRaw = myData?.data;
|
||||
@@ -320,31 +324,40 @@ export default function SubscriptionPage() {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--text-2)', marginBottom: 10 }}>
|
||||
انتخاب درگاه پرداخت
|
||||
gateways.length === 0 ? (
|
||||
<div style={{
|
||||
background: 'var(--danger-bg)', border: '1px solid var(--danger)',
|
||||
borderRadius: 10, padding: '12px 16px', fontSize: 13, color: 'var(--danger)',
|
||||
}}>
|
||||
در حال حاضر هیچ درگاه پرداخت فعالی وجود ندارد. لطفاً با پشتیبانی تماس بگیرید.
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
|
||||
{(['mellat', 'sep'] as const).map((gw) => (
|
||||
<button
|
||||
key={gw}
|
||||
onClick={() => setSelectedGateway(gw)}
|
||||
style={{
|
||||
padding: '12px 16px', borderRadius: 'var(--r-sm)', cursor: 'pointer',
|
||||
border: `2px solid ${selectedGateway === gw ? 'var(--primary)' : 'var(--border)'}`,
|
||||
background: selectedGateway === gw ? 'var(--primary-soft)' : 'var(--surface)',
|
||||
color: selectedGateway === gw ? 'var(--primary-700)' : 'var(--text-2)',
|
||||
fontWeight: selectedGateway === gw ? 700 : 500,
|
||||
fontSize: 13, transition: '.14s', fontFamily: 'inherit',
|
||||
display: 'flex', alignItems: 'center', gap: 8,
|
||||
}}
|
||||
>
|
||||
<CreditCardIcon style={{ width: 17, flexShrink: 0 }} />
|
||||
{GATEWAY_LABELS[gw]}
|
||||
</button>
|
||||
))}
|
||||
) : (
|
||||
<div>
|
||||
<div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--text-2)', marginBottom: 10 }}>
|
||||
انتخاب درگاه پرداخت
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
|
||||
{gateways.map((gw) => (
|
||||
<button
|
||||
key={gw.name}
|
||||
onClick={() => setSelectedGateway(gw.name)}
|
||||
style={{
|
||||
padding: '12px 16px', borderRadius: 'var(--r-sm)', cursor: 'pointer',
|
||||
border: `2px solid ${selectedGateway === gw.name ? 'var(--primary)' : 'var(--border)'}`,
|
||||
background: selectedGateway === gw.name ? 'var(--primary-soft)' : 'var(--surface)',
|
||||
color: selectedGateway === gw.name ? 'var(--primary-700)' : 'var(--text-2)',
|
||||
fontWeight: selectedGateway === gw.name ? 700 : 500,
|
||||
fontSize: 13, transition: '.14s', fontFamily: 'inherit',
|
||||
display: 'flex', alignItems: 'center', gap: 8,
|
||||
}}
|
||||
>
|
||||
<CreditCardIcon style={{ width: 17, flexShrink: 0 }} />
|
||||
{gw.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* دکمهها */}
|
||||
@@ -352,7 +365,7 @@ export default function SubscriptionPage() {
|
||||
<button
|
||||
className="btn primary"
|
||||
style={{ flex: 1, height: 44 }}
|
||||
disabled={purchaseMutation.isPending}
|
||||
disabled={purchaseMutation.isPending || (!isTestMode && (gateways.length === 0 || selectedGateway === ''))}
|
||||
onClick={() =>
|
||||
purchaseMutation.mutate({ period_uuid: purchaseTarget.period.uuid, gateway: selectedGateway, amount_rials: purchaseTarget.period.price_rials })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user