verify payment
This commit is contained in:
@@ -2,68 +2,155 @@
|
||||
|
||||
import Button from '@/components/button/PrimaryButton';
|
||||
import { ef } from '@/lib/helpers/utfNumbers';
|
||||
import { CardTick } from 'iconsax-react';
|
||||
import { CardTick, CloseCircle } from 'iconsax-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import React from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useVerify } from '../hooks/useVerifyData';
|
||||
import { toast } from '@/components/Toast';
|
||||
import { VerifyData } from '../types/Types';
|
||||
|
||||
type Props = object
|
||||
|
||||
const formatDate = (dateString: string): string => {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('fa-IR', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
const formatTime = (dateString: string): string => {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleTimeString('fa-IR', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
const formatPrice = (value: number): string => {
|
||||
return value.toLocaleString('fa-IR');
|
||||
};
|
||||
|
||||
export default function VerifyIndex({ }: Props) {
|
||||
// const { t } = useTranslation('notifications')
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const name = params.name as string;
|
||||
|
||||
const urlparams = new URLSearchParams(window.location.search);
|
||||
const authority = urlparams.get('Authority');
|
||||
const id = params.id
|
||||
|
||||
const [verifyData, setVerifyData] = useState<VerifyData | null>(null);
|
||||
const [isError, setIsError] = useState(false);
|
||||
|
||||
const { mutate: verify } = useVerify();
|
||||
|
||||
useEffect(() => {
|
||||
if (authority && id) {
|
||||
verify({ authority: authority as string, orderId: id as string }, {
|
||||
onSuccess: (data) => {
|
||||
toast('پرداخت موفقیت آمیز بود', 'success');
|
||||
setVerifyData(data.data);
|
||||
setIsError(false);
|
||||
},
|
||||
onError: () => {
|
||||
toast('پرداخت ناموفق بوده', 'error');
|
||||
setIsError(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [authority, id]);
|
||||
|
||||
const amount = verifyData?.amount || verifyData?.order?.total || 0;
|
||||
const paidAt = verifyData?.paidAt || '';
|
||||
const cardPan = verifyData?.verifyResponse?.data?.card_pan || '';
|
||||
const gateway = verifyData?.order?.paymentMethod?.description || verifyData?.gateway || '';
|
||||
const referenceId = verifyData?.referenceId || '';
|
||||
|
||||
const formattedCardPan = cardPan || '';
|
||||
|
||||
return (
|
||||
<div className='h-full bg-inherit relative flex flex-col lg:gap-4'>
|
||||
<div className='flex-1 flex flex-col items-center justify-center'>
|
||||
<div className='bg-container py-5 px-2 rounded-container shadow-lg w-full'>
|
||||
<div className='items-center gap-2 bg-gray-50 rounded-2xl h-35 flex flex-col justify-center'>
|
||||
<CardTick className='size-10 stroke-primary' variant='TwoTone' />
|
||||
<h5 className='font-bold text-sm'>پرداخت موفق</h5>
|
||||
<p className='text-sm mt-1 leading-5 text-disabled-text'>
|
||||
{ef('مبلغ: 560,000 تومان')}
|
||||
</p>
|
||||
<div className={`items-center gap-2 rounded-2xl h-35 flex flex-col justify-center ${isError ? 'bg-red-50' : 'bg-gray-50'}`}>
|
||||
{isError ? (
|
||||
<CloseCircle className='size-10 stroke-red-500' variant='TwoTone' />
|
||||
) : (
|
||||
<CardTick className='size-10 stroke-primary' variant='TwoTone' />
|
||||
)}
|
||||
<h5 className={`font-bold text-sm ${isError ? 'text-red-600' : ''}`}>
|
||||
{isError ? 'پرداخت ناموفق' : 'پرداخت موفق'}
|
||||
</h5>
|
||||
{!isError && verifyData && (
|
||||
<p className='text-sm mt-1 leading-5 text-disabled-text'>
|
||||
{ef(`مبلغ: ${formatPrice(amount)} تومان`)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='mt-5 w-full text-sm2'>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='font-medium text-disabled-text'>تاریخ:</div>
|
||||
<div className='font-medium'>{ef('1401/05/08')}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
{!isError && (
|
||||
<div className='mt-5 w-full text-sm2'>
|
||||
{paidAt && (
|
||||
<>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='font-medium text-disabled-text'>تاریخ:</div>
|
||||
<div className='font-medium'>{ef(formatDate(paidAt))}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-disabled-text'>ساعت:</div>
|
||||
<div className=''>{ef('21:45')}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
{paidAt && (
|
||||
<>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-disabled-text'>ساعت:</div>
|
||||
<div className=''>{ef(formatTime(paidAt))}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-disabled-text'>از کارت:</div>
|
||||
<div className=''>{ef('6104 6647 **** 1147')}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
{cardPan && (
|
||||
<>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-disabled-text'>از کارت:</div>
|
||||
<div className=''>{ef(formattedCardPan)}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-disabled-text'>درگاه پرداخت:</div>
|
||||
<div className=''>{ef('درگاه پرداخت')}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
{gateway && (
|
||||
<>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-disabled-text'>درگاه پرداخت:</div>
|
||||
<div className=''>{gateway}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-disabled-text'>شماره پیگیری:</div>
|
||||
<div className=''>{ef('556284526')}</div>
|
||||
{referenceId && (
|
||||
<>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-disabled-text'>شماره پیگیری:</div>
|
||||
<div className=''>{ef(referenceId)}</div>
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<hr className='border border-border my-3' />
|
||||
)}
|
||||
|
||||
<Button
|
||||
className='mt-12'
|
||||
onClick={() => router.push(`/${name}`)} // TODO: redirect to order
|
||||
>
|
||||
بازگشت
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
className='mt-12'
|
||||
onClick={() => router.push(`/${name}`)}
|
||||
>
|
||||
بازگشت
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import * as api from "../service/VerifyService";
|
||||
|
||||
export const useVerify = () => {
|
||||
return useMutation({
|
||||
mutationFn: api.verify,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import { api } from "@/config/axios";
|
||||
import { VerifyType, VerifyResponse } from "../types/Types";
|
||||
|
||||
export const verify = async (params: VerifyType): Promise<VerifyResponse> => {
|
||||
const { data } = await api.post<VerifyResponse>(
|
||||
"/public/payments/verify",
|
||||
params
|
||||
);
|
||||
return data;
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
import { BaseResponse } from "@/app/[name]/(Main)/types/Types";
|
||||
|
||||
export interface VerifyType {
|
||||
authority: string;
|
||||
orderId: string;
|
||||
}
|
||||
|
||||
export interface VerifyOrderHistory {
|
||||
status: string;
|
||||
changedAt: string;
|
||||
}
|
||||
|
||||
export interface VerifyPaymentMethod {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
restaurant: string;
|
||||
method: string;
|
||||
gateway: string;
|
||||
description: string;
|
||||
enabled: boolean;
|
||||
order: number;
|
||||
merchantId: string;
|
||||
}
|
||||
|
||||
export interface VerifyOrder {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
user: string;
|
||||
restaurant: string;
|
||||
deliveryMethod: string;
|
||||
userAddress: string | null;
|
||||
carAddress: string | null;
|
||||
paymentMethod: VerifyPaymentMethod;
|
||||
orderNumber: number;
|
||||
couponDiscount: number;
|
||||
couponDetail: unknown | null;
|
||||
itemsDiscount: number;
|
||||
totalDiscount: number;
|
||||
subTotal: number;
|
||||
tax: number;
|
||||
deliveryFee: number;
|
||||
total: number;
|
||||
totalItems: number;
|
||||
description: string;
|
||||
tableNumber: string;
|
||||
status: string;
|
||||
history: VerifyOrderHistory[];
|
||||
}
|
||||
|
||||
export interface VerifyResponseData {
|
||||
data: {
|
||||
fee: number;
|
||||
code: number;
|
||||
wages: unknown | null;
|
||||
ref_id: number;
|
||||
message: string;
|
||||
card_pan: string;
|
||||
fee_type: string;
|
||||
order_id: string;
|
||||
card_hash: string;
|
||||
shaparak_fee: number;
|
||||
};
|
||||
errors: unknown[];
|
||||
}
|
||||
|
||||
export interface VerifyData {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
order: VerifyOrder;
|
||||
amount: number;
|
||||
referenceId: string;
|
||||
method: string;
|
||||
gateway: string;
|
||||
transactionId: string;
|
||||
status: string;
|
||||
cardPan: string | null;
|
||||
verifyResponse: VerifyResponseData;
|
||||
paidAt: string;
|
||||
failedAt: string | null;
|
||||
description: string | null;
|
||||
}
|
||||
|
||||
export type VerifyResponse = BaseResponse<VerifyData>;
|
||||
Reference in New Issue
Block a user