verify payment
This commit is contained in:
@@ -2,70 +2,157 @@
|
|||||||
|
|
||||||
import Button from '@/components/button/PrimaryButton';
|
import Button from '@/components/button/PrimaryButton';
|
||||||
import { ef } from '@/lib/helpers/utfNumbers';
|
import { ef } from '@/lib/helpers/utfNumbers';
|
||||||
import { CardTick } from 'iconsax-react';
|
import { CardTick, CloseCircle } from 'iconsax-react';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
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
|
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) {
|
export default function VerifyIndex({ }: Props) {
|
||||||
// const { t } = useTranslation('notifications')
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const name = params.name as string;
|
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 (
|
return (
|
||||||
<div className='h-full bg-inherit relative flex flex-col lg:gap-4'>
|
<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='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='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'>
|
<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' />
|
<CardTick className='size-10 stroke-primary' variant='TwoTone' />
|
||||||
<h5 className='font-bold text-sm'>پرداخت موفق</h5>
|
)}
|
||||||
|
<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'>
|
<p className='text-sm mt-1 leading-5 text-disabled-text'>
|
||||||
{ef('مبلغ: 560,000 تومان')}
|
{ef(`مبلغ: ${formatPrice(amount)} تومان`)}
|
||||||
</p>
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{!isError && (
|
||||||
<div className='mt-5 w-full text-sm2'>
|
<div className='mt-5 w-full text-sm2'>
|
||||||
|
{paidAt && (
|
||||||
|
<>
|
||||||
<div className='flex justify-between items-center'>
|
<div className='flex justify-between items-center'>
|
||||||
<div className='font-medium text-disabled-text'>تاریخ:</div>
|
<div className='font-medium text-disabled-text'>تاریخ:</div>
|
||||||
<div className='font-medium'>{ef('1401/05/08')}</div>
|
<div className='font-medium'>{ef(formatDate(paidAt))}</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className='border border-border my-3' />
|
<hr className='border border-border my-3' />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{paidAt && (
|
||||||
|
<>
|
||||||
<div className='flex justify-between items-center'>
|
<div className='flex justify-between items-center'>
|
||||||
<div className='text-disabled-text'>ساعت:</div>
|
<div className='text-disabled-text'>ساعت:</div>
|
||||||
<div className=''>{ef('21:45')}</div>
|
<div className=''>{ef(formatTime(paidAt))}</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className='border border-border my-3' />
|
<hr className='border border-border my-3' />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{cardPan && (
|
||||||
|
<>
|
||||||
<div className='flex justify-between items-center'>
|
<div className='flex justify-between items-center'>
|
||||||
<div className='text-disabled-text'>از کارت:</div>
|
<div className='text-disabled-text'>از کارت:</div>
|
||||||
<div className=''>{ef('6104 6647 **** 1147')}</div>
|
<div className=''>{ef(formattedCardPan)}</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className='border border-border my-3' />
|
<hr className='border border-border my-3' />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{gateway && (
|
||||||
|
<>
|
||||||
<div className='flex justify-between items-center'>
|
<div className='flex justify-between items-center'>
|
||||||
<div className='text-disabled-text'>درگاه پرداخت:</div>
|
<div className='text-disabled-text'>درگاه پرداخت:</div>
|
||||||
<div className=''>{ef('درگاه پرداخت')}</div>
|
<div className=''>{gateway}</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className='border border-border my-3' />
|
<hr className='border border-border my-3' />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{referenceId && (
|
||||||
|
<>
|
||||||
<div className='flex justify-between items-center'>
|
<div className='flex justify-between items-center'>
|
||||||
<div className='text-disabled-text'>شماره پیگیری:</div>
|
<div className='text-disabled-text'>شماره پیگیری:</div>
|
||||||
<div className=''>{ef('556284526')}</div>
|
<div className=''>{ef(referenceId)}</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className='border border-border my-3' />
|
<hr className='border border-border my-3' />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className='mt-12'
|
className='mt-12'
|
||||||
onClick={() => router.push(`/${name}`)} // TODO: redirect to order
|
onClick={() => router.push(`/${name}`)}
|
||||||
>
|
>
|
||||||
بازگشت
|
بازگشت
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</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