From 66e52e079aaeea125e5485904161182e3fba553c Mon Sep 17 00:00:00 2001 From: Alihaghighattalab Date: Thu, 8 Aug 2024 18:13:57 +0330 Subject: [PATCH] complete add new card --- package-lock.json | 7 + package.json | 1 + src/components/common/dialog.tsx | 40 +++ src/components/common/input.tsx | 16 +- .../add-new-cart-dialog.tsx | 69 ++++ .../management-bank-accounts/bank-cart.tsx | 7 +- .../create-new-cart.tsx | 9 +- .../management-bank-accounts/index.tsx | 17 +- src/index.tsx | 1 + src/schema/index.ts | 15 + src/types/index.ts | 17 +- src/utility/cart.ts | 32 -- src/utility/cart.tsx | 335 ++++++++++++++++++ tailwind.config.js | 3 +- 14 files changed, 519 insertions(+), 50 deletions(-) create mode 100644 src/components/common/dialog.tsx create mode 100644 src/components/management-bank-accounts/add-new-cart-dialog.tsx delete mode 100644 src/utility/cart.ts create mode 100644 src/utility/cart.tsx diff --git a/package-lock.json b/package-lock.json index 16a1b7a..8308c7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@types/react-dom": "^18.3.0", "clsx": "^2.1.1", "iconsax-react": "^0.0.8", + "iranianbanklogos": "^3.1.2", "jalaali-js": "^1.2.7", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -10278,6 +10279,12 @@ "node": ">= 10" } }, + "node_modules/iranianbanklogos": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/iranianbanklogos/-/iranianbanklogos-3.1.2.tgz", + "integrity": "sha512-F6GnrhrC9UO1c4CW8uJloXAkg7pgx/Y8ok6qixb6L0knwIanG6Idudi8/Ebuu3c9PVd59wDTtTZQvtszr+Yyvw==", + "license": "ISC" + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", diff --git a/package.json b/package.json index a7bcc85..52db07a 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@types/react-dom": "^18.3.0", "clsx": "^2.1.1", "iconsax-react": "^0.0.8", + "iranianbanklogos": "^3.1.2", "jalaali-js": "^1.2.7", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/src/components/common/dialog.tsx b/src/components/common/dialog.tsx new file mode 100644 index 0000000..003b547 --- /dev/null +++ b/src/components/common/dialog.tsx @@ -0,0 +1,40 @@ +import { Dialog, DialogBackdrop, DialogPanel, DialogTitle } from '@headlessui/react' +import React, { FC } from 'react' + +type Props = { + isOpen: boolean, + close: () => void, + children: React.ReactNode, + title: string, + subTitle: string, + icon: React.ReactNode +} + +export const DialogComponent: FC = ({ isOpen, children, close, title, subTitle, icon }) => { + return ( + <> + + +
+
+ + +
+ {icon} +
+
+

{title}

+

{subTitle}

+
+
+ {children} +
+
+
+
+ + ) +} diff --git a/src/components/common/input.tsx b/src/components/common/input.tsx index 7a7ce86..98f600d 100644 --- a/src/components/common/input.tsx +++ b/src/components/common/input.tsx @@ -1,26 +1,32 @@ import { Eye, EyeSlash } from "iconsax-react" import React, { FC, useState } from "react" import { Input as InputComponent } from '@headlessui/react' +import { findBankByPAN } from "../../utility/cart" +import clsx from "clsx" type Props = { type?: React.HTMLInputTypeAttribute, placeholder: string, icon?: React.ReactNode, - field?: any - ref?: any + field?: any, + ref?: any, + className?: string } -export const Input: FC = ({ placeholder, type = "text", icon, field, ref }) => { +export const Input: FC = ({ placeholder, type = "text", icon, field, ref, className }) => { const [hidden, setHidden] = useState(false) const handleHidden = () => setHidden(prev => !prev) return (
-
+
{type === "password" ? !hidden ? : : icon} + {placeholder === "شماره کارت" && field.value && findBankByPAN(field.value).icon}
-
) } \ No newline at end of file diff --git a/src/components/management-bank-accounts/add-new-cart-dialog.tsx b/src/components/management-bank-accounts/add-new-cart-dialog.tsx new file mode 100644 index 0000000..4236e82 --- /dev/null +++ b/src/components/management-bank-accounts/add-new-cart-dialog.tsx @@ -0,0 +1,69 @@ +import { CardAdd } from "iconsax-react" +import { DialogComponent } from "../common/dialog" +import { FC } from "react" +import { Input } from "../common/input" +import { Button } from "@headlessui/react" +import { bankCarts, findBankByPAN } from "../../utility/cart" +import { Controller, SubmitHandler, useForm } from "react-hook-form" +import { AddNewCartInterface } from "../../types" +import { yupResolver } from "@hookform/resolvers/yup" +import { AddNewCardSchema } from "../../schema" +import { ErrorComponent } from "../common/error" + +type Props = { + isOpen: boolean, + close: () => void +} +export const AddNewCardDialog: FC = ({ isOpen, close }) => { + const { handleSubmit, formState: { errors }, control } = useForm({ + resolver: yupResolver(AddNewCardSchema) + }) + const createNewCard: SubmitHandler = async (data) => { + const finalData: any = { + id: bankCarts?.length + 1, + bankName: findBankByPAN(data.cartNumber).name, + bankPersianName: findBankByPAN(data.cartNumber).name_farsi, + cartNumber: data?.cartNumber.toString(), + cartOwner: `${data.name} ${data?.family}`, + shabaNumber: data?.shabaNumber, + } + bankCarts.push(finalData) + close() + } + return ( + }> +
+
+ ( +
+ + +
+ )} /> + ( +
+ + +
+ )} /> + ( +
+ + +
+ )} /> + ( +
+ + +
+ )} /> +
+
+ + +
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/management-bank-accounts/bank-cart.tsx b/src/components/management-bank-accounts/bank-cart.tsx index 9980bd4..a9341bc 100644 --- a/src/components/management-bank-accounts/bank-cart.tsx +++ b/src/components/management-bank-accounts/bank-cart.tsx @@ -1,18 +1,19 @@ import { Edit, Trash } from "iconsax-react" -import { formatCartNumber } from "../../utility/cart" import { BankCartInterface } from "../../types" import { FC } from "react" +import { findBankByPAN, formatCartNumber } from "../../utility/cart" type Props = { item: BankCartInterface } export const BankCart: FC = ({ item }) => { + console.log("item=>", item) return (
- {item?.bankName} + {findBankByPAN(item.cartNumber).icon}

بانک {item?.bankPersianName}

@@ -20,7 +21,7 @@ export const BankCart: FC = ({ item }) => {
-

{formatCartNumber(1234567891011121)}

+

{formatCartNumber(item?.cartNumber)}

{item?.cartOwner}

IR {item?.shabaNumber}

diff --git a/src/components/management-bank-accounts/create-new-cart.tsx b/src/components/management-bank-accounts/create-new-cart.tsx index bb24fc3..3815ebc 100644 --- a/src/components/management-bank-accounts/create-new-cart.tsx +++ b/src/components/management-bank-accounts/create-new-cart.tsx @@ -1,8 +1,11 @@ import { Add } from "iconsax-react" - -export const CreateNewCart = () => { +import { FC } from "react" +type Props = { + handleOpenDialog: () => void +} +export const CreateNewCart: FC = ({ handleOpenDialog }) => { return ( -
+
diff --git a/src/components/management-bank-accounts/index.tsx b/src/components/management-bank-accounts/index.tsx index 7b2090d..92fd57b 100644 --- a/src/components/management-bank-accounts/index.tsx +++ b/src/components/management-bank-accounts/index.tsx @@ -1,14 +1,21 @@ +import { useState } from "react" import { BankCartInterface } from "../../types" import { bankCarts } from "../../utility/cart" import { BankCart } from "./bank-cart" import { CreateNewCart } from "./create-new-cart" +import { AddNewCardDialog } from "./add-new-cart-dialog" export const ManagementBankAccounts = () => { - + const [showDialog, setShowDialog] = useState(false) + const handleCloseDialog = () => setShowDialog(false) + const handleOpenDialog = () => setShowDialog(true) return ( -
- - {bankCarts?.map((item: BankCartInterface) => )} -
+ <> +
+ + {bankCarts?.map((item: BankCartInterface) => )} +
+ + ) } \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index 70cbb61..8b59159 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,6 +3,7 @@ import ReactDOM from 'react-dom/client'; import { RouterProvider } from 'react-router-dom'; import { router } from './router'; import './index.css' +import "iranianbanklogos/dist/ibl.css"; const root = ReactDOM.createRoot( diff --git a/src/schema/index.ts b/src/schema/index.ts index 3a15c68..056c7f0 100644 --- a/src/schema/index.ts +++ b/src/schema/index.ts @@ -95,4 +95,19 @@ export const MyAccountSchema = yup.object({ repeatPassword: yup.string() .oneOf([yup.ref('newPassword')], "رمز عبور و تکرار آن باید یکسان باشند") .required("تکرار رمز عبور الزامی میاشد"), +}) + +export const AddNewCardSchema = yup.object({ + name: yup.string().required("وارد کردن نام الزامی میباشد").min(3, "نام نمیتواند کمتر از 3 کاراکتر باشد").max(20, "نام نمیتواند بیشتر از 20 کاراکتر باشد"), + family: yup.string().required("وارد کردن نام خانوادگی الزامی میباشد").min(3, "نام خانوادگی نمیتواند کمتر از 3 کاراکتر باشد").max(25, "نام خانوادگی نمیتواند بیشتر از 25 کاراکتر باشد"), + cartNumber: yup.string() + .required("وارد کردن شماره کارت الزامی میباشد") + .min(16, "شماره کارت نمیتوند کمتر از 16 رقم باشد") + .max(16, " شماره کارت نمیتواند بیشتر از 16 رقم باشد") + .matches(/^[0-9]{16}$/, "شماره کارت نامعتبر"), + shabaNumber: yup.string() + .required("وارد کردن شماره شبا الزامی میباشد") + .min(24, "شماره شبا نمیتوند کمتر از 24 رقم باشد") + .max(24, " شماره شبا نمیتواند بیشتر از 24 رقم باشد") + .matches(/^[0-9]{24}$/, "شماره شبا نامعتبر"), }) \ No newline at end of file diff --git a/src/types/index.ts b/src/types/index.ts index e6ec166..8a81137 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -80,7 +80,22 @@ export interface BankCartInterface { id: number, bankName: BankName, bankPersianName: PersianBankName, - cartNumber: number | string, + cartNumber: string, cartOwner: string, shabaNumber: string, +} + +export interface BanksInterface { + name: string, + name_farsi: string, + icon: React.ReactNode, + iban_nbc: string, + pan_iin: string[] | [] +} + +export interface AddNewCartInterface { + name: string + family: string + cartNumber: string + shabaNumber: string } \ No newline at end of file diff --git a/src/utility/cart.ts b/src/utility/cart.ts deleted file mode 100644 index b4e10e2..0000000 --- a/src/utility/cart.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { BankCartInterface } from "../types"; - -export const formatCartNumber = (num: number | string) => { - return num.toString().replace(/\B(?=(\d{4})+(?!\d))/g, `          `); -} - -export const bankCarts: BankCartInterface[] | [] = [ - { - id: 0, - bankName: 'mehr', - bankPersianName: "مهر", - cartNumber: 4682563898563372, - cartOwner: "علی مصلحی", - shabaNumber: "270700001000116102861001" - }, - { - id: 1, - bankName: 'saderat', - bankPersianName: "صادرات", - cartNumber: 4682563898563372, - cartOwner: "علی مصلحی", - shabaNumber: "270700001000116102861001" - }, - { - id: 2, - bankName: 'pasargad', - bankPersianName: "پاسارگاد", - cartNumber: 4682563898563372, - cartOwner: "علی مصلحی", - shabaNumber: "270700001000116102861001" - }, -] \ No newline at end of file diff --git a/src/utility/cart.tsx b/src/utility/cart.tsx new file mode 100644 index 0000000..1d45675 --- /dev/null +++ b/src/utility/cart.tsx @@ -0,0 +1,335 @@ +import { BankCartInterface, BanksInterface } from "../types"; + +export const formatCartNumber = (num: string) => { + return num?.toString().replace(/\B(?=(\d{4})+(?!\d))/g, `    `); +} + +export let bankCarts: BankCartInterface[] | [] | any = [] + +const banks: BanksInterface[] | [] = [ + { + name: "ansar", + name_farsi: "انصار", + icon: , + iban_nbc: "063", + pan_iin: [ + "627381" + ] + }, + { + name: "ayandeh", + name_farsi: "آینده", + icon: , + iban_nbc: "062", + pan_iin: [ + "636214" + ] + }, + { + name: "bank_markazi", + name_farsi: "بانک مرکزی", + icon: "Bank_Markazi.svg", + iban_nbc: "010", + pan_iin: [ + "636795" + ] + }, + { + name: "dey", + name_farsi: "دی", + icon: , + iban_nbc: "066", + pan_iin: [ + "502938" + ] + }, + { + name: "eghtesad_novin", + name_farsi: "اقتصاد نوین", + icon: , + iban_nbc: "055", + pan_iin: [ + "627412", + "627884" + ] + }, + { + name: "gardeshgari", + name_farsi: "گردشگری", + icon: , + iban_nbc: "064", + pan_iin: [ + "505416" + ] + }, + { + name: "ghavamin", + name_farsi: "قوامین", + icon: , + iban_nbc: "052", + pan_iin: [ + "639599" + ] + }, + { + name: "hekmat", + name_farsi: "حکمت", + icon: , + iban_nbc: "065", + pan_iin: [ + "636949" + ] + }, + { + name: "iran_zamin", + name_farsi: "ایران‌زمین", + icon: , + iban_nbc: "069", + pan_iin: [ + "505785", + ] + }, + { + name: "karafarin", + name_farsi: "کارآفرین", + icon: , + iban_nbc: "053", + pan_iin: [ + "502910", + "627488" + ] + }, + { + name: "keshavarzi", + name_farsi: "کشاورزی", + icon: , + iban_nbc: "016", + pan_iin: [ + "603770", + "639217" + ] + }, + { + name: "khavar_mianeh", + name_farsi: "خاورمیانه", + icon: , + iban_nbc: "078", + pan_iin: [ + "505809" + ] + }, + { + name: "maskan", + name_farsi: "مسکن", + icon: , + iban_nbc: "014", + pan_iin: [ + "628023" + ] + }, + { + name: "mehr_iran", + name_farsi: "مهر ایران", + icon: , + iban_nbc: "060", + pan_iin: [ + "606373" + ] + }, + { + name: "melall", + name_farsi: "ملل", + icon: , + iban_nbc: "075", + pan_iin: [ + "606256" + ] + }, + { + name: "mellat", + name_farsi: "ملت", + icon: , + iban_nbc: "012", + pan_iin: [ + "610433", + "991975" + ] + }, + { + name: "melli", + name_farsi: "ملی", + icon: , + iban_nbc: "017", + pan_iin: [ + "603799", + "589905", + "170019" + ] + }, + { + name: "noor", + name_farsi: "نور", + icon: "Noor.svg", + iban_nbc: "080", + pan_iin: [ + "507677" + ] + }, + { + name: "parsian", + name_farsi: "پارسیان", + icon: , + iban_nbc: "054", + pan_iin: [ + "622106", + "639194" + ] + }, + { + name: "pasargad", + name_farsi: "پاسارگاد", + icon: , + iban_nbc: "057", + pan_iin: [ + "502229", + "639347" + ] + }, + { + name: "postbank", + name_farsi: "پست‌بانک", + icon: , + iban_nbc: "021", + pan_iin: [ + "627760" + ] + }, + { + name: "refah", + name_farsi: "رفاه", + icon: , + iban_nbc: "013", + pan_iin: [ + "589463" + ] + }, + { + name: "resalat", + name_farsi: "رسالت", + icon: , + iban_nbc: "070", + pan_iin: [ + "504172" + ] + }, + { + name: "saderat", + name_farsi: "صادرات", + icon: , + iban_nbc: "019", + pan_iin: [ + "603769" + ] + }, + { + name: "saman", + name_farsi: "سامان", + icon: , + iban_nbc: "056", + pan_iin: [ + "621986" + ] + }, + { + name: "sanat_madan", + name_farsi: "صنعت و معدن", + icon: , + iban_nbc: "011", + pan_iin: [ + "627961" + ] + }, + { + name: "sarmayeh", + name_farsi: "سرمایه", + icon: , + iban_nbc: "058", + pan_iin: [ + "639607" + ] + }, + { + name: "sepah", + name_farsi: "سپه", + icon: , + iban_nbc: "015", + pan_iin: [ + "589210" + ] + }, + { + name: "shahr", + name_farsi: "شهر", + icon: , + iban_nbc: "061", + pan_iin: [ + "502806", + "504706" + ] + }, + { + name: "sina", + name_farsi: "سینا", + icon: , + iban_nbc: "059", + pan_iin: [ + "639346" + ] + }, + { + name: "tejarat", + name_farsi: "تجارت", + icon: , + iban_nbc: "018", + pan_iin: [ + "585983", + "627353" + ] + }, + { + name: "tosee_saderat", + name_farsi: "توسعه صادرات", + icon: , + iban_nbc: "020", + pan_iin: [ + "207177", + "627648" + ] + }, + { + name: "tosee_taavon", + name_farsi: "توسعه تعاون", + icon: , + iban_nbc: "022", + pan_iin: [ + "502908" + ] + } +] + +let cache: any = {}; + +export const findBankByPAN = (cardNumber: string | number) => { + cardNumber = String(cardNumber); + if (!/^[\d*]+$/.test(cardNumber) || cardNumber.length < 6) return {}; + const iin: string = cardNumber.slice(0, 6); + + if (cache[iin]) { + return cache[iin]; + } else { + const bank: any = banks?.find((bank: any) => bank?.pan_iin.includes(iin)) + if (!bank) return {}; + cache[iin] = { ...bank }; + return bank; + }; +}; \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js index d29de98..4e71aa8 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -10,7 +10,8 @@ module.exports = { "primary-text-color": "#11212D", "secondary-text-color": "#777577", "primary-color": "#015699", - "secondary-color": "#E6E8EA" + "secondary-color": "#E6E8EA", + "border-color": "#D9D9D9" }, backgroundImage: { 'bank-mehr': "url('/public/svgs/banks/mehr.svg')",