import { ChevronLeft, ChevronRight, Loader, Loader2, Plus, Trash2, TriangleAlert, X, } from "lucide-react"; import HeaderWithSupport from "../components/HeaderWithSupport"; import { Carousel, CarouselApi, CarouselContent, CarouselItem, } from "../components/ui/carousel"; import { useCallback, useState, useRef, useEffect } from "react"; import { useNavigate, useParams } from "@remix-run/react"; import { useCarousel } from "../hooks/useCarousel"; import { useRequireOwner } from "../hooks/useStoreOwnership"; import { Drawer, DrawerTitle, DrawerContent, DrawerHeader, } from "../components/ui/drawer"; import { useServiceCreateCashRequest, useServiceGetSellerBalance, useServiceGetBankAccounts, useServiceRegisterBankAccount, useServiceDeleteBankAccount, } from "../requestHandler/use-wallet-hooks"; import { formatAccountNumber, formatPrice, getPersianTextOfPrice, safeGoBack, } from "../utils/helpers"; import { Button } from "../components/ui/button"; import AppInput from "../components/AppInput"; import { Dialog, DialogContent, DialogOverlay } from "../components/ui/dialog"; import { Input } from "../components/ui/input"; import { MetaFunction } from "@remix-run/node"; import { detectIranianBank, validateIranianBankCard, } from "~/utils/iranian-banks"; import { BankLogo } from "~/components/BankLogo"; export default function CashingFunds() { const navigate = useNavigate(); const { storeId } = useParams(); useRequireOwner(storeId); // financial is owner-only const handleBack = () => { safeGoBack(navigate); }; const [currentIndex, setCurrentIndex] = useState(0); const { api, setApi } = useCarousel({ onSelect: useCallback( (carouselApi: CarouselApi) => { if (!carouselApi) return; setCurrentIndex(carouselApi.selectedScrollSnap()); }, [setCurrentIndex] ), }); const [addCartDrawerOpen, setAddCartDrawerOpen] = useState(false); const [deleteCardModalOpen, setDeleteCardModalOpen] = useState(false); const [cardToDelete, setCardToDelete] = useState(); const { data: balance, isLoading: isBalanceLoading } = useServiceGetSellerBalance(); const { data: bankAccounts, isLoading: isBankAccountsLoading } = useServiceGetBankAccounts(); const [cashDrawerIsOpen, setCashDrawerIsOpen] = useState(false); return (

کارت‌های بانکی شما:

{isBankAccountsLoading ? (
) : bankAccounts && bankAccounts.length > 0 ? ( <> {bankAccounts.map((account, index) => ( {(() => { const detectedBank = detectIranianBank( account.cardNumber || "" ); return (
{/* Delete button */}

{detectedBank ? detectedBank.name : "بانک"}

{detectedBank ? ( ) : (
؟
)}

{formatAccountNumber(account.cardNumber || "")}

{account.iban}

); })()}
))}
{bankAccounts.length > 1 && (
{ api?.scrollPrev(); }} className="font-bold text-GRAY ml-1 cursor-pointer" size={20} /> {bankAccounts.map((_, index) => (
)} ) : (

هیچ کارت بانکی ثبت نشده است

لطفا ابتدا کارت بانکی خود را اضافه کنید

)}

موجودی کیف پول (تومان):

{isBalanceLoading ? ( ) : (

{formatPrice(balance?.availableFunds || "0")}

)}
{/* Floating action buttons */}
{/* Withdraw button */}
{/* Modals and Drawers */} {bankAccounts && bankAccounts.length > 0 && ( )}
); } const DeleteCardModal = ({ isOpen, onOpenChange, bankAccountId, }: { isOpen: boolean; onOpenChange: (open: boolean) => void; bankAccountId?: string; }) => { const { mutate: deleteBankAccount, isPending } = useServiceDeleteBankAccount(); const onRemove = () => { if (!bankAccountId) return; deleteBankAccount(bankAccountId, { onSuccess: () => { onOpenChange(false); }, onError: (error) => { console.error("Failed to delete bank account:", error); }, }); }; return (

حذف کارت

از حذف این کارت مطمئن هستید؟

); }; const AddCartDrawer = ({ isOpen, onOpenChange, }: { isOpen: boolean; onOpenChange: (open: boolean) => void; }) => { const [cardPart1, setCardPart1] = useState(""); const [cardPart2, setCardPart2] = useState(""); const [cardPart3, setCardPart3] = useState(""); const [cardPart4, setCardPart4] = useState(""); const [shabaNumber, setShabaNumber] = useState(""); const [cardError, setCardError] = useState(""); const { mutate: registerBankAccount, isPending: isSubmitting } = useServiceRegisterBankAccount(); const cardRef1 = useRef(null); const cardRef2 = useRef(null); const cardRef3 = useRef(null); const cardRef4 = useRef(null); // Detect bank from current card input const fullCardNumber = cardPart1 + cardPart2 + cardPart3 + cardPart4; const detectedBank = detectIranianBank(fullCardNumber); const handleCardInputChange = ( value: string, part: number, setter: (value: string) => void ) => { // فقط عدد قبول کند const numericValue = value.replace(/\D/g, ""); if (numericValue.length <= 4) { setter(numericValue); // اگر 4 رقم پر شد، به بعدی برو if (numericValue.length === 4) { if (part === 1) cardRef2.current?.focus(); else if (part === 2) cardRef3.current?.focus(); else if (part === 3) cardRef4.current?.focus(); } } }; const handleSubmit = () => { const formattedIban = `IR${shabaNumber}`; // Validate Iranian bank card if (!validateIranianBankCard(fullCardNumber)) { setCardError("شماره کارت وارد شده متعلق به بانک‌های ایران نیست"); return; } registerBankAccount( { iban: formattedIban, cardNumber: fullCardNumber, }, { onSuccess: () => { // Reset form setCardPart1(""); setCardPart2(""); setCardPart3(""); setCardPart4(""); setShabaNumber(""); setCardError(""); onOpenChange(false); }, onError: (error) => { console.error("Failed to register bank account:", error); setCardError("خطا در ثبت کارت بانکی"); }, } ); }; const isFormValid = cardPart1.length === 4 && cardPart2.length === 4 && cardPart3.length === 4 && cardPart4.length === 4 && shabaNumber.length === 24 && validateIranianBankCard(fullCardNumber); return ( onOpenChange(false)} /> افزودن کارت جدید

شماره کارت را وارد کنید:

{ handleCardInputChange(e.target.value, 1, setCardPart1); setCardError(""); }} /> { handleCardInputChange(e.target.value, 2, setCardPart2); setCardError(""); }} /> { handleCardInputChange(e.target.value, 3, setCardPart3); setCardError(""); }} /> { handleCardInputChange(e.target.value, 4, setCardPart4); setCardError(""); }} />
{/* Show detected bank */} {detectedBank && fullCardNumber.length >= 6 && (

بانک {detectedBank.name}

کارت شناسایی شد

)} {/* Show error if card is complete but invalid */} {fullCardNumber.length === 16 && !detectedBank && (

شماره کارت متعلق به بانک‌های ایران نیست

)} {/* Show custom error */} {cardError && (

{cardError}

)}

شماره شبا حساب خود را وارد کنید:

setShabaNumber(e.target.value)} dir={!shabaNumber ? "rtl" : "ltr"} className="pl-14" />
IR
); }; const CashDrawer = ({ isOpen, onOpenChange, currentAccount, availableFunds, }: { isOpen: boolean; onOpenChange: (open: boolean) => void; currentAccount: { id?: string; iban: string; cardNumber: string; isVerified: boolean; createdAt: string; }; availableFunds: number; }) => { const [amount, setAmount] = useState(null); const [withdrawAll, setWithdrawAll] = useState(false); const { mutate: createCashRequest, isPending: submitLoading } = useServiceCreateCashRequest(); const [successModalIsOpen, setSuccessModalIsOpen] = useState(false); const [errorModalIsOpen, setErrorModalIsOpen] = useState(false); // Reset state when drawer closes useEffect(() => { if (!isOpen) { setAmount(null); setWithdrawAll(false); } }, [isOpen]); return ( onOpenChange(false)} /> مبلغ برداشت را تعیین کنید:
) => { setAmount(parseInt(e.target.value) || null); setWithdrawAll(false); }} /> {/* Show Persian text of entered amount */} {amount !== null && amount > 0 && (

{getPersianTextOfPrice(amount.toString())}

)} {/* Show maximum withdrawal amount */}

حداکثر قابل برداشت:

{formatPrice(availableFunds.toString())} تومان

{/* Toggle switch for withdraw all */}

مبلغ تعیین شده بعد از بررسی، به حساب{" "} {formatAccountNumber(currentAccount.cardNumber) .split("-") .reverse() .join("-")} {" "} با شماره شبا{" "} {currentAccount.iban} منتقل خواهد شد

); }; const SuccessModal = ({ isOpen, onOpenChange, }: { isOpen: boolean; onOpenChange: (open: boolean) => void; }) => { return (

در انتظار تایید مبلغ

پس از تایید، مبلغ مورد نظر به حساب شما واریز می‌شود. این فرآیند کمتر از یک ساعت زمان می‌برد.

); }; const ErrorModal = ({ isOpen, onOpenChange, }: { isOpen: boolean; onOpenChange: (open: boolean) => void; }) => { return (

درخواست برداشت مبلغ با خطا مواجه شد

لطفا مجددا درخواست برداشت را انجام دهید. یا با پشتیبانی تماس بگیرید.

); }; export const meta: MetaFunction = () => { return [ { title: "کیف پول - ویترون" }, { name: "description", content: "مدیریت و مشاهده تمام کیف پول در فروشگاه شما. فیلتر بر اساس وضعیت و جستجو در کیف پول.", }, { name: "keywords", content: "کیف پول، مدیریت کیف پول، فروشگاه، مشتری، ویترون", }, { name: "robots", content: "noindex, follow" }, { property: "og:title", content: "کیف پول - ویترون" }, { property: "og:description", content: "مدیریت و مشاهده تمام کیف پول در فروشگاه شما. فیلتر بر اساس وضعیت و جستجو در کیف پول.", }, { property: "og:type", content: "website" }, { name: "twitter:card", content: "summary" }, { name: "twitter:title", content: "کیف پول - ویترون" }, { name: "twitter:description", content: "مدیریت و مشاهده تمام کیف پول در فروشگاه شما. فیلتر بر اساس وضعیت و جستجو در کیف پول.", }, ]; };