wallet
This commit is contained in:
@@ -4,4 +4,5 @@ VITE_REFRESH_TOKEN_NAME = 'dmnu-a-rt'
|
|||||||
# VITE_BASE_URL = 'https://dmenu-api.danakcorp.com'
|
# VITE_BASE_URL = 'https://dmenu-api.danakcorp.com'
|
||||||
VITE_BASE_URL = 'http://192.168.99.131:2000'
|
VITE_BASE_URL = 'http://192.168.99.131:2000'
|
||||||
|
|
||||||
VITE_SOCKET_URL = 'https://dmenu-api.danakcorp.com'
|
VITE_SOCKET_URL = 'https://dmenu-api.danakcorp.com'
|
||||||
|
VITE_INVOICE_URL = 'https://console.danakcorp.com/receipts/'
|
||||||
+9
-1
@@ -611,6 +611,15 @@
|
|||||||
"exsist_special_character": "شامل کاراکتر های خاص (نماد ها) باشد"
|
"exsist_special_character": "شامل کاراکتر های خاص (نماد ها) باشد"
|
||||||
},
|
},
|
||||||
"wallet": {
|
"wallet": {
|
||||||
|
"charge": "شارژ",
|
||||||
|
"charge_title": "شارژ کیف پول",
|
||||||
|
"amount": "مبلغ",
|
||||||
|
"amount_placeholder": "مبلغ را وارد کنید",
|
||||||
|
"amount_required": "مبلغ را وارد کنید",
|
||||||
|
"charge_success": "درخواست شارژ با موفقیت ثبت شد",
|
||||||
|
"invoice_issued": "صورتحساب صادر شد",
|
||||||
|
"cancel": "انصراف",
|
||||||
|
"balance": "موجودی کیف پول",
|
||||||
"increese_wallet": "افزایش موجودی حساب اعتباری",
|
"increese_wallet": "افزایش موجودی حساب اعتباری",
|
||||||
"online_pay": "پرداخت آنلاین",
|
"online_pay": "پرداخت آنلاین",
|
||||||
"card_to_card": "کارت به کارت",
|
"card_to_card": "کارت به کارت",
|
||||||
@@ -619,7 +628,6 @@
|
|||||||
"enter_your_price": "مبلغ دلخواه خودرا وارد کنید",
|
"enter_your_price": "مبلغ دلخواه خودرا وارد کنید",
|
||||||
"select_payment": "انتخاب درگاه پرداخت",
|
"select_payment": "انتخاب درگاه پرداخت",
|
||||||
"pay": "پرداخت",
|
"pay": "پرداخت",
|
||||||
"amount": "مبلغ",
|
|
||||||
"enter_amount_card": "مبلغ کارت به کارت شده را وارد کنید",
|
"enter_amount_card": "مبلغ کارت به کارت شده را وارد کنید",
|
||||||
"upload_deposit_slip": "آپلود فیش واریزی",
|
"upload_deposit_slip": "آپلود فیش واریزی",
|
||||||
"submit_slip": "ثبت فیش",
|
"submit_slip": "ثبت فیش",
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { type FC, useState } from "react";
|
||||||
|
import DefaulModal from "@/components/DefaulModal";
|
||||||
|
import Input from "@/components/Input";
|
||||||
|
import Button from "@/components/Button";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useCreateChargeRequest } from "../hooks/useWalletData";
|
||||||
|
import { extractErrorMessage } from "@/config/func";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ChargeModal: FC<Props> = ({ open, onClose }) => {
|
||||||
|
const { t } = useTranslation("global");
|
||||||
|
const [amount, setAmount] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const createChargeRequest = useCreateChargeRequest();
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAmount("");
|
||||||
|
setError("");
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
const numericAmount = Number(amount);
|
||||||
|
|
||||||
|
if (!numericAmount || numericAmount <= 0) {
|
||||||
|
setError(t("wallet.amount_required"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createChargeRequest.mutate(
|
||||||
|
{ amount: numericAmount },
|
||||||
|
{
|
||||||
|
onSuccess: (response) => {
|
||||||
|
const { invoiceId } = response.data;
|
||||||
|
const invoiceBaseUrl = import.meta.env.VITE_INVOICE_URL;
|
||||||
|
|
||||||
|
if (invoiceId && invoiceBaseUrl) {
|
||||||
|
window.open(`${invoiceBaseUrl}${invoiceId}`, "_blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success(t("wallet.invoice_issued"));
|
||||||
|
handleClose();
|
||||||
|
},
|
||||||
|
onError: (err) => {
|
||||||
|
toast.error(extractErrorMessage(err));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaulModal
|
||||||
|
open={open}
|
||||||
|
close={handleClose}
|
||||||
|
isHeader
|
||||||
|
title_header={t("wallet.charge_title")}
|
||||||
|
width={480}
|
||||||
|
>
|
||||||
|
<div className="mt-6">
|
||||||
|
<Input
|
||||||
|
name="amount"
|
||||||
|
label={t("wallet.amount")}
|
||||||
|
placeholder={t("wallet.amount_placeholder")}
|
||||||
|
type="number"
|
||||||
|
seprator
|
||||||
|
value={amount}
|
||||||
|
onChange={(e) => {
|
||||||
|
setAmount(e.target.value);
|
||||||
|
setError("");
|
||||||
|
}}
|
||||||
|
error_text={error}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex gap-3 mt-6">
|
||||||
|
<Button
|
||||||
|
label={t("wallet.cancel")}
|
||||||
|
type="button"
|
||||||
|
onClick={handleClose}
|
||||||
|
className="bg-gray-100 text-gray-700"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label={t("wallet.charge")}
|
||||||
|
type="button"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
isloading={createChargeRequest.isPending}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaulModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChargeModal;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { type FC, useState } from "react";
|
||||||
|
import { EmptyWallet } from "iconsax-react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { formatPrice } from "@/helpers/func";
|
||||||
|
import { useGetWalletBalance } from "../hooks/useWalletData";
|
||||||
|
import ChargeModal from "./ChargeModal";
|
||||||
|
import MoonLoader from "react-spinners/MoonLoader";
|
||||||
|
|
||||||
|
const WalletHeader: FC = () => {
|
||||||
|
const { t } = useTranslation("global");
|
||||||
|
const [showChargeModal, setShowChargeModal] = useState(false);
|
||||||
|
const { data, isLoading } = useGetWalletBalance();
|
||||||
|
|
||||||
|
const balance = data?.data?.balance ?? 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center gap-2 bg-[#F5F5F5] rounded-xl px-3 h-9">
|
||||||
|
<EmptyWallet size={18} color="black" />
|
||||||
|
<div className="text-xs whitespace-nowrap min-w-[80px]">
|
||||||
|
{isLoading ? (
|
||||||
|
<MoonLoader size={12} color="#000" />
|
||||||
|
) : (
|
||||||
|
formatPrice(balance)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowChargeModal(true)}
|
||||||
|
className="text-xs bg-primary text-white rounded-lg px-3 h-7 whitespace-nowrap hover:opacity-90 transition-opacity"
|
||||||
|
>
|
||||||
|
{t("wallet.charge")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ChargeModal
|
||||||
|
open={showChargeModal}
|
||||||
|
onClose={() => setShowChargeModal(false)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WalletHeader;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import * as api from "../service/WalletService";
|
||||||
|
|
||||||
|
export const useGetWalletBalance = () => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["wallet-balance"],
|
||||||
|
queryFn: () => api.getWalletBalance(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCreateChargeRequest = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.createChargeRequest,
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["wallet-balance"] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import axios from "@/config/axios";
|
||||||
|
import type {
|
||||||
|
ChargeRequestResponse,
|
||||||
|
ChargeRequestType,
|
||||||
|
WalletBalanceResponse,
|
||||||
|
} from "../types/Types";
|
||||||
|
|
||||||
|
export const getWalletBalance = async (): Promise<WalletBalanceResponse> => {
|
||||||
|
const { data } = await axios.get<WalletBalanceResponse>(
|
||||||
|
"/admin/restaurants/wallet/balance"
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createChargeRequest = async (
|
||||||
|
params: ChargeRequestType
|
||||||
|
): Promise<ChargeRequestResponse> => {
|
||||||
|
const { data } = await axios.post<ChargeRequestResponse>(
|
||||||
|
"/admin/restaurants/charge-request",
|
||||||
|
params
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import type { IResponse } from "@/types/response.types";
|
||||||
|
|
||||||
|
export type WalletBalance = {
|
||||||
|
balance: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WalletBalanceResponse = IResponse<WalletBalance>;
|
||||||
|
|
||||||
|
export type ChargeRequestType = {
|
||||||
|
amount: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChargeRequestResult = {
|
||||||
|
id: string;
|
||||||
|
amount: number;
|
||||||
|
invoiceId: string;
|
||||||
|
status: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChargeRequestResponse = IResponse<ChargeRequestResult>;
|
||||||
@@ -7,6 +7,7 @@ import { useSharedStore } from './store/sharedStore'
|
|||||||
import { HambergerMenu } from 'iconsax-react'
|
import { HambergerMenu } from 'iconsax-react'
|
||||||
import { clx } from '@/helpers/utils'
|
import { clx } from '@/helpers/utils'
|
||||||
import Notifications from '@/pages/notification/Notification'
|
import Notifications from '@/pages/notification/Notification'
|
||||||
|
import WalletHeader from '@/pages/wallet/components/WalletHeader'
|
||||||
|
|
||||||
const Header: FC = () => {
|
const Header: FC = () => {
|
||||||
|
|
||||||
@@ -43,9 +44,7 @@ const Header: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
{/* <img src={LogoImage} className='h-6 xl:hidden block absolute right-0 left-0 mx-auto' /> */}
|
{/* <img src={LogoImage} className='h-6 xl:hidden block absolute right-0 left-0 mx-auto' /> */}
|
||||||
<div className='flex xl:gap-6 gap-4 items-center'>
|
<div className='flex xl:gap-6 gap-4 items-center'>
|
||||||
{/* <Link className='xl:hidden' to={Pages.wallet}>
|
<WalletHeader />
|
||||||
<Wallet className='xl:size-[18px] size-[17px]' color='black' />
|
|
||||||
</Link> */}
|
|
||||||
<Notifications />
|
<Notifications />
|
||||||
{/* {
|
{/* {
|
||||||
data && (
|
data && (
|
||||||
|
|||||||
Vendored
+8
@@ -1,5 +1,13 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_INVOICE_URL: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
|
|
||||||
declare module "*.svg?raw" {
|
declare module "*.svg?raw" {
|
||||||
const content: string;
|
const content: string;
|
||||||
export default content;
|
export default content;
|
||||||
|
|||||||
Reference in New Issue
Block a user