diff --git a/.gitignore b/.gitignore index cff2732..a93a63a 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ yarn.lock .env package-lock.json +package.json +yarn.lock +package-lock.json diff --git a/package-lock.json b/package-lock.json index 87756c1..3e4da0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "https": "^1.0.0", "leaflet": "^1.9.4", "lucide-react": "^0.456.0", + "metronic-tailwind-react": "file:", "mini-svg-data-uri": "^1.4.4", "moment": "^2.30.1", "next-themes": "^0.4.3", @@ -6454,6 +6455,10 @@ "node": ">= 8" } }, + "node_modules/metronic-tailwind-react": { + "resolved": "", + "link": true + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", diff --git a/package.json b/package.json index 2e30fa9..7745b80 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "https": "^1.0.0", "leaflet": "^1.9.4", "lucide-react": "^0.456.0", + "metronic-tailwind-react": "file:", "mini-svg-data-uri": "^1.4.4", "moment": "^2.30.1", "next-themes": "^0.4.3", diff --git a/src/pages/groups/Column.tsx b/src/pages/groups/Column.tsx index d796078..2f6fe7f 100644 --- a/src/pages/groups/Column.tsx +++ b/src/pages/groups/Column.tsx @@ -1,3 +1,4 @@ +import { KeenIcon } from '@/components'; import { ColumnDef } from '@tanstack/react-table'; export type Group = { @@ -8,7 +9,7 @@ export type Group = { description: string; }; -export const columns: ColumnDef[] = [ +export const getColumns = (handleUpdate: (data: any) => void): ColumnDef[] => [ { accessorKey: 'no', header: 'ID' @@ -30,8 +31,19 @@ export const columns: ColumnDef[] = [ accessorKey: 'description', header: 'Description' }, - // { - // id: 'actions', - // header: 'Actions' - // } + { + id: 'actions', + cell: ({ row }) => { + const dataMembers = row.original; + + return ( + + ); + } + } ]; diff --git a/src/pages/groups/ListToolbar.tsx b/src/pages/groups/ListToolbar.tsx new file mode 100644 index 0000000..793f4c9 --- /dev/null +++ b/src/pages/groups/ListToolbar.tsx @@ -0,0 +1,49 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { Button } from '@/components/ui/button'; + +const ListToolBar = ({ createGroup }: { createGroup: () => void }) => { + const { table, reload } = useDataGrid(); + + return ( +
+
+
+
+ + {/* + + */} +
+
+ + + + +
+
+
+
+ ); +}; + +export { ListToolBar }; diff --git a/src/pages/groups/ManageGroups.tsx b/src/pages/groups/ManageGroups.tsx index 55ae1eb..d03966f 100644 --- a/src/pages/groups/ManageGroups.tsx +++ b/src/pages/groups/ManageGroups.tsx @@ -1,5 +1,5 @@ import { DataTable } from '@/components/ui/DataTable'; -import { columns, Group } from './Column'; +import { getColumns, Group } from './Column'; import { apiConfig } from '@/config/api.config'; import axios, { AxiosResponse } from 'axios'; import { Helmet } from 'react-helmet'; @@ -24,6 +24,8 @@ import CloseIcon from '@mui/icons-material/Close'; import Divider from '@mui/material/Divider'; import ConfirmDialog from '@/components/confirm'; import { toast } from 'sonner'; +import { Container, DataGridProvider } from '@/components'; +import { ListToolBar } from './ListToolbar'; // import { DialogHeader } from '@/components/ui/dialog'; // import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; const BASE_URL = apiConfig.service_customer; @@ -66,7 +68,7 @@ const ManageGroups = () => { let resGroups = groups.data.data.list.map((el: any) => { el.no = temp++; return el; - }); + }) setDataGroup(resGroups); } catch (error: any) { alert(error.message); @@ -89,9 +91,9 @@ const ManageGroups = () => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!formData.groupName) return toast.warning(`Group name can not be empty!`) - if (!formData.status) return toast.warning(`Status can not be empty!`) - if (!formData.description) return toast.warning(`Description can not be empty!`) + if (!formData.groupName) return toast.warning(`Group name can not be empty!`); + if (!formData.status) return toast.warning(`Status can not be empty!`); + if (!formData.description) return toast.warning(`Description can not be empty!`); setIsDialogOpen(false); setDialogOpen(true); }; @@ -134,7 +136,7 @@ const ManageGroups = () => { description: formData.description, created_at: new Date() }); - toast.success(`Success create group`) + toast.success(`Success create group`); } else if (dialogType === 'update') { await axios.put(`${BASE_URL}/groups/update/${formData.id}`, { name: formData.groupName, @@ -142,14 +144,14 @@ const ManageGroups = () => { description: formData.description, updated_at: new Date() }); - toast.success(`Success update group`) + toast.success(`Success update group`); } else if (dialogType === 'delete') { await axios.delete(`${BASE_URL}/groups/delete/${formData.id}/true`); - toast.success(`Success delete group`) + toast.success(`Success delete group`); } } catch (error: any) { console.log(error); - toast.error(error.message) + toast.error(error.message); } finally { await fetchGroups(); setDialogOpen(false); @@ -162,19 +164,19 @@ const ManageGroups = () => { TPAY | Manage Group - setDialogOpen(false)} - title="Confirm Action" - content={ - `Are you sure you want to ` + - (dialogType === 'create' ? 'create?' : dialogType === 'update' ? 'update?' : 'delete?') - } - onYes={handleYes} - onNo={() => setDialogOpen(false)} - /> -

Groups

-
+ + setDialogOpen(false)} + title="Confirm Action" + content={ + `Are you sure you want to ` + + (dialogType === 'create' ? 'create?' : dialogType === 'update' ? 'update?' : 'delete?') + } + onYes={handleYes} + onNo={() => setDialogOpen(false)} + /> +

Groups

Dashboard @@ -188,84 +190,101 @@ const ManageGroups = () => { Manage Groups -
-
- */} +
+ {/* -
+ /> */} + } + layout={{ card: true }} + sorting={[{ id: 'created_at', desc: true }]} + serverSide={false} + onRowSelectionChange={(selected, table: any) => { + const selectedRow = table.getSelectedRowModel().rows[0]; + if (selectedRow) handleUpdate(selectedRow.original); + }} + /> +
+ {/* */} - - -
- {dialogType==='create'?"Create New Group":"Update Group"} - - - -
- -
-
-
- - -
-
- - - - } - label="Yes" - /> - } - label="No" - /> - - -
-
- - -
- -
-
-
-
+ + +
+ + {dialogType === 'create' ? 'Create New Group' : 'Update Group'} + + + + +
+ +
+
+
+ + +
+
+ + + + } + label="Yes" + /> + } + label="No" + /> + + +
+
+ + +
+ +
+
+
+
+ ); }; diff --git a/src/pages/master/postoadms/blocks/ListToolbar.tsx b/src/pages/master/postoadms/blocks/ListToolbar.tsx index 37b3976..9ffcb42 100644 --- a/src/pages/master/postoadms/blocks/ListToolbar.tsx +++ b/src/pages/master/postoadms/blocks/ListToolbar.tsx @@ -2,10 +2,23 @@ import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; import { Button } from '@/components/ui/button'; import { useManagePostoAdmsContext } from '../hooks/useManagePostoAdmsContext'; +import { useState } from 'react'; const ListToolbar = () => { const { table, reload } = useDataGrid(); const { handleAddDialog, handleSearchDialog } = useManagePostoAdmsContext(); + const [searchPosto, setSearchPosto] = useState(''); + const [searchMunicipio, setSearchMunicipio] = useState(''); + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + handleSearch(); + } + }; + + const handleSearch = () => { + table.getColumn('name')?.setFilterValue(searchPosto); + }; return (
@@ -16,11 +29,17 @@ const ListToolbar = () => { table.getColumn('name')?.setFilterValue(event.target.value)} + placeholder="Search" + value={searchPosto} + onChange={(event) => setSearchPosto(event.target.value)} + onKeyDown={handleKeyDown} /> + + + {/* ); + }, + cell: ({ row, table }) => { + const pageIndex = table.getState().pagination.pageIndex; + const pageSize = table.getState().pagination.pageSize; + const rowIndex = row.index; + + const number = pageIndex * pageSize + rowIndex + 1; + return number; } }, { @@ -136,61 +145,117 @@ export const columns: ColumnDef[] = [ id: 'actions', cell: ({ row }) => { const dataMembers = row.original; + return ( - - + ); } } ]; -export const initialMember = { - id: "", - fullname: "", - email: "", - username: "", - msisdn: "", - password: "", - pin: "", - try_pin: "", - mother_fullname: "", - agent_name: "", - bank_name: "", - bank_account: "", - ibank_number: "", - address: "", - longitude: "", - latitude: "", - nationality: "", - photouser: "", - photomerchant: "", - file_selfie: "", - file_document_id: "", - file_document_id_selfie: "", - file_commercial_license: "", - identity_type: "", - identity_number: "", - license_number: "", - date_birth: "", - gender: "", - status: "N", - isneedapproval: "", - isapproved: "", - approveddate: "", - approvedby: "", - created_by: "", - created_at: "", - updated_by: "", - updated_at: "", - deleted_by: "", - deleted_at: "", - group: "", - point_tier: "", - language: "", - municipio: "", - posto_adms: "", - suco: "", - aldeia: "", - profession: "", - description: "" -} +export type MembersProps = { + id: string; + fullname: string; + email: string; + username: string; + msisdn: string; + password: string; + pin: string; + try_pin: string; + mother_fullname: string; + agent_name: string; + bank_name: string; + bank_account: string; + ibank_number: string; + address: string; + longitude: string; + latitude: string; + nationality: string; + photouser: string; + photomerchant: string; + file_selfie: string; + file_document_id: string; + file_document_id_selfie: string; + file_commercial_license: string; + identity_type: string; + identity_number: string; + license_number: string; + date_birth: string; + gender: string; + status: string; + isneedapproval: string; + isapproved: string; + approveddate: string; + approvedby: string; + created_by: string; + created_at: string; + updated_by: string; + updated_at: string; + deleted_by: string; + deleted_at: string; + group: string; + point_tier: string; + language: string; + municipio: string; + posto_adms: string; + suco: string; + aldeia: string; + profession: string; + description: string; +}; + +export const initialMember: MembersProps = { + id: '', + fullname: '', + email: '', + username: '', + msisdn: '', + password: '', + pin: '', + try_pin: '', + mother_fullname: '', + agent_name: '', + bank_name: '', + bank_account: '', + ibank_number: '', + address: '', + longitude: '', + latitude: '', + nationality: '', + photouser: '', + photomerchant: '', + file_selfie: '', + file_document_id: '', + file_document_id_selfie: '', + file_commercial_license: '', + identity_type: '', + identity_number: '', + license_number: '', + date_birth: '', + gender: '', + status: 'N', + isneedapproval: '', + isapproved: '', + approveddate: '', + approvedby: '', + created_by: '', + created_at: '', + updated_by: '', + updated_at: '', + deleted_by: '', + deleted_at: '', + group: '', + point_tier: '', + language: '', + municipio: '', + posto_adms: '', + suco: '', + aldeia: '', + profession: '', + description: '' +}; diff --git a/src/pages/members/kyc/Kyc.tsx b/src/pages/members/kyc/Kyc.tsx index b3ecff9..969db5e 100644 --- a/src/pages/members/kyc/Kyc.tsx +++ b/src/pages/members/kyc/Kyc.tsx @@ -1,9 +1,9 @@ -import { DataGridInner, TDataGridProps } from '@/components'; +import { Container, DataGridInner, DataGridProvider, TDataGridProps } from '@/components'; import { DataTable } from '@/components/ui/DataTable'; import { Table } from '@tanstack/react-table'; import React, { createContext, useContext, useState, useEffect } from 'react'; import { ManageKycContextProvider } from './hooks'; -import { columns, initialMember } from './Columns'; +import { getColumns, initialMember } from './Columns'; import { useAuthContext } from '@/auth'; import { LoaderTransparant } from '@/components'; import { apiConfig } from '@/config/api.config'; @@ -16,25 +16,7 @@ const BASE_URL_MASTER_DATA = apiConfig.service_master_data; import DetailMember from '../manage-members/blocks/DetailMember'; import { Breadcrumbs, Link } from '@mui/material'; import { Helmet } from 'react-helmet'; - -export interface IDataGridContextProps { - props: TDataGridProps; - table: Table; - totalRows: number; - loading: (state: boolean) => void; - reload: () => void; - children?: React.ReactNode; -} - -const DataGridContext = createContext | undefined>(undefined); - -export const useDataGrid = () => { - const context = useContext(DataGridContext); - if (!context) { - throw new Error('useDataGrid must be used within a DataGridProvider'); - } - return context; -}; +import { ListToolBar } from './blocks/ListToolBar'; const Kyc = () => { const [loading, setLoading] = useState(false); @@ -58,8 +40,8 @@ const Kyc = () => { limit: 10, page: 1, with_deleted: false, - order_field: 'fullname', - order_direction: 'ASC', + order_field: 'created_at', + order_direction: 'DESC', type: 'kyc' } }); @@ -72,14 +54,14 @@ const Kyc = () => { setMembers(resMembers); let getProfession: any = await axios.get(`${BASE_URL_MASTER_DATA}/profession/list`, { params: { - limit: 50, - page: 1, - with_deleted: false, - order_field: 'name', - order_direction: 'ASC', + limit: 50, + page: 1, + with_deleted: false, + order_field: 'name', + order_direction: 'ASC' } }); - setProfession(getProfession.data.data.list) + setProfession(getProfession.data.data.list); } catch (error: any) { toast.error(error.message); console.log(error); @@ -103,8 +85,12 @@ const Kyc = () => { setDialogOpen(true); } + const resetForm = () => { + setMember(initialMember); + }; + const handleYes = async () => { - setLoading(true) + setLoading(true); const userLogin: any = await getUser(); const updateData: any = member; const customerId = member.id; @@ -151,100 +137,123 @@ const Kyc = () => { if (updateData[property]) form.append(property, updateData[property]); } if (dialogType === 'reject') { - if (destinationGroup === "Premium") await axios.post(`${BASE_URL}/customer/reject`, { customerid: customerId, description: updateData.approval_description_premium }); - if (destinationGroup === "Agent") await axios.post(`${BASE_URL}/customer/reject`, { customerid: customerId, description: updateData.approval_description_agent }); + if (destinationGroup === 'Premium') + await axios.post(`${BASE_URL}/customer/reject`, { + customerid: customerId, + description: updateData.approval_description_premium + }); + if (destinationGroup === 'Agent') + await axios.post(`${BASE_URL}/customer/reject`, { + customerid: customerId, + description: updateData.approval_description_agent + }); } if (dialogType === 'update') { await axios.put(`${BASE_URL}/customer/update/${customerId}`, form); - if (updateData.isneedapproval == 1&&destinationGroup === "Premium") await axios.post(`${BASE_URL}/customer/approve`, { customerid: customerId, description: updateData.approval_description_premium}); - if (updateData.isneedapproval == 1&&destinationGroup === "Agent") await axios.post(`${BASE_URL}/customer/approve`, { customerid: customerId, description: updateData.approval_description_agent}); + if (updateData.isneedapproval == 1 && destinationGroup === 'Premium') + await axios.post(`${BASE_URL}/customer/approve`, { + customerid: customerId, + description: updateData.approval_description_premium + }); + if (updateData.isneedapproval == 1 && destinationGroup === 'Agent') + await axios.post(`${BASE_URL}/customer/approve`, { + customerid: customerId, + description: updateData.approval_description_agent + }); } setDialogOpen(false); setIsDialogOpen(false); toast.success(`Success Update & ${dialogType} Kyc Member`); } catch (error: any) { - if (error?.response?.data?.error) error.message = error?.response?.data?.error + if (error?.response?.data?.error) error.message = error?.response?.data?.error; setDialogOpen(false); setIsDialogOpen(false); toast.error(error.message); } finally { await fetchCustomers(); - setLoading(false) + setLoading(false); } }; function setShowAddDialog(el: any) { - setIsDialogOpen(el) + setIsDialogOpen(el); } if (loading) return ; + useEffect(() => { + if (!isDialogOpen) resetForm(); + }, [isDialogOpen]); + return ( <> TPAY | KYC -
-
- setDialogOpen(false)} - title="Confirm Action" - content={`Are you sure you want to ${dialogType}?`} - onYes={handleYes} - onNo={() => setDialogOpen(false)} + + setDialogOpen(false)} + title="Confirm Action" + content={`Are you sure you want to ${dialogType}?`} + onYes={handleYes} + onNo={() => setDialogOpen(false)} + /> + {member.id ? ( + // + - { member.id ? ( - // - - ): ""} -

Manage Member KYC

-
- - - Dashboard - + ) : ( + '' + )} +

KYC Upgrade Members

+ + + Dashboard + - - Members - - - - Manage Member KYC - - -
-
-
- -
-
+ + Members + + + KYC Upgrade Members + + + {/*
*/} +
+ } + layout={{ card: true }} + sorting={[{ id: 'created_at', desc: true }]} + serverSide={false} + onRowSelectionChange={(selected, table: any) => { + const selectedRow = table.getSelectedRowModel().rows[0]; + if (selectedRow) handleUpdate(selectedRow.original); + }} + >
-
+ {/*
*/} + ); }; diff --git a/src/pages/members/kyc/blocks/AddDialog.tsx b/src/pages/members/kyc/blocks/AddDialog.tsx deleted file mode 100644 index 68b4d58..0000000 --- a/src/pages/members/kyc/blocks/AddDialog.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Dialog } from '@/components/ui/dialog'; -import { useRef } from 'react'; -import { useKycContext } from '../hooks'; -import { useDataGrid } from '@/components'; - -const AddDialog = () => { - const parentRef = useRef(null); - const { showAddDialog, handleAddDialog } = useKycContext(); - const { reload } = useDataGrid(); - - return ; -}; - -export default AddDialog; diff --git a/src/pages/members/kyc/blocks/ListToolBar.tsx b/src/pages/members/kyc/blocks/ListToolBar.tsx index 8d99350..180e68b 100644 --- a/src/pages/members/kyc/blocks/ListToolBar.tsx +++ b/src/pages/members/kyc/blocks/ListToolBar.tsx @@ -4,7 +4,6 @@ import { useKycContext } from '../hooks'; const ListToolBar = () => { const { table, reload } = useDataGrid(); - const { handleDetailDialog, handleAddDialog } = useKycContext(); return (
diff --git a/src/pages/members/manage-members/Columns.tsx b/src/pages/members/manage-members/Columns.tsx index 983178e..6039aba 100644 --- a/src/pages/members/manage-members/Columns.tsx +++ b/src/pages/members/manage-members/Columns.tsx @@ -1,3 +1,4 @@ +import { KeenIcon } from '@/components'; import { Button } from '@/components/ui/button'; import { DropdownMenu, @@ -18,7 +19,7 @@ export type Members = { created_at: Date; }; -export const columns: ColumnDef[] = [ +export const getColumns = (handleUpdate: (data: any) => void): ColumnDef[] => [ { accessorKey: 'no', header: ({ column }) => { @@ -110,22 +111,12 @@ export const columns: ColumnDef[] = [ const dataMembers = row.original; return ( - - {/* - - */} - {/* - Actions - navigator.clipboard.writeText(dataMembers.id.toString())} - > - Copy account ID - - */} - + ); } } diff --git a/src/pages/members/manage-members/ManageMembers.tsx b/src/pages/members/manage-members/ManageMembers.tsx index 6d9cdd2..8d27979 100644 --- a/src/pages/members/manage-members/ManageMembers.tsx +++ b/src/pages/members/manage-members/ManageMembers.tsx @@ -1,18 +1,20 @@ import { DataTable } from '@/components/ui/DataTable'; import { apiConfig } from '@/config/api.config'; -import { columns, Members, initialMember } from './Columns'; +import { getColumns, Members, initialMember } from './Columns'; import { useState, useEffect } from 'react'; import axios from 'axios'; // import CustomerDialog from './CustomerDetailModal'; import DetailMember from './blocks/DetailMember'; import ConfirmDialog from '@/components/confirm'; import { useAuthContext } from '@/auth'; -import { LoaderTransparant } from '@/components'; +import { Container, DataGridInner, LoaderTransparant } from '@/components'; +import { DataGridProvider } from '@/components'; import { toast } from 'sonner'; import { Breadcrumbs, Link } from '@mui/material'; const BASE_URL_MASTER_DATA = apiConfig.service_master_data; const BASE_URL = apiConfig.service_customer; import { Helmet } from 'react-helmet'; +import ListToolbar from './blocks/ListToolBar'; const ManageMembers = () => { const [loading, setLoading] = useState(false); const [members, setMembers] = useState([]); @@ -23,8 +25,8 @@ const ManageMembers = () => { const [dialogOpen, setDialogOpen] = useState(false); const [dialogType, setDialogType] = useState(''); const closeDialog = () => { - setIsDialogOpen(false) - setMember(initialMember) + setIsDialogOpen(false); + setMember(initialMember); }; const { getUser } = useAuthContext(); @@ -50,7 +52,7 @@ const ManageMembers = () => { el.no = temp++; if (el.date_birth) { const d = new Date(el.date_birth); - el.date_birth = d.toLocaleString("sv-SE"); + el.date_birth = d.toLocaleString('sv-SE'); } el.name = el.fullname; return el; @@ -58,14 +60,14 @@ const ManageMembers = () => { setMembers(resMembers); let getProfession: any = await axios.get(`${BASE_URL_MASTER_DATA}/profession/list`, { params: { - limit: 50, - page: 1, - with_deleted: false, - order_field: 'name', - order_direction: 'ASC', + limit: 50, + page: 1, + with_deleted: false, + order_field: 'name', + order_direction: 'ASC' } }); - setProfession(getProfession.data.data.list) + setProfession(getProfession.data.data.list); } catch (error: any) { toast.error(error.message); console.log(error); @@ -74,14 +76,14 @@ const ManageMembers = () => { const handleUpdate = (data: any) => { setDialogType('update'); - setSelectedMember(data.id) + setSelectedMember(data.id); setMember(data); setIsDialogOpen(true); }; function createMember() { setDialogType('create'); - setSelectedMember('') + setSelectedMember(''); setMember(initialMember); setIsDialogOpen(true); } @@ -92,7 +94,7 @@ const ManageMembers = () => { } const handleYes = async () => { - setLoading(true) + setLoading(true); const userLogin: any = await getUser(); const updateData: any = member; updateData.updated_by = userLogin.data ? userLogin.data.id : ''; @@ -135,7 +137,7 @@ const ManageMembers = () => { for (const property in updateData) { if (updateData[property]) form.append(property, updateData[property]); } - + if (dialogType === 'update') { await axios.put(`${BASE_URL}/customer/update/${selectedMember}`, form, { headers: { @@ -145,8 +147,8 @@ const ManageMembers = () => { toast.success('Success Edit Member'); } if (dialogType === 'create') { - const createMember:any = member - createMember.pin = "admin" + const createMember: any = member; + createMember.pin = 'admin'; delete createMember.password; delete createMember.try_pin; delete createMember.license_number; @@ -162,7 +164,7 @@ const ManageMembers = () => { delete createMember.approval_description_premium; delete createMember.approval_description_agent; delete createMember.language; - await axios.post(`${BASE_URL}/customers/create`, member) + await axios.post(`${BASE_URL}/customers/create`, member); toast.success('Success Create Member. PIN sent to email'); } } catch (error: any) { @@ -171,12 +173,12 @@ const ManageMembers = () => { setDialogOpen(false); closeDialog(); await fetchCustomers(); - setLoading(false) + setLoading(false); } }; function setShowAddDialog(el: any) { - setIsDialogOpen(el) + setIsDialogOpen(el); } if (loading) return ; @@ -186,56 +188,59 @@ const ManageMembers = () => { TPAY | Manage Members -
-
- setDialogOpen(false)} - title="Confirm Action" - content={`Are you sure you want to ${dialogType}?`} - onYes={handleYes} - onNo={() => setDialogOpen(false)} + + setDialogOpen(false)} + title="Confirm Action" + content={`Are you sure you want to ${dialogType}?`} + onYes={handleYes} + onNo={() => setDialogOpen(false)} + /> + {member.id !== '' || dialogType === 'create' ? ( + - { (member.id!=='' || dialogType==='create') ? ( - - ): ""} -

Manage Members

-
- - - Dashboard - - - Members - + ) : ( + '' + )} +

Manage Members

+ + + Dashboard + + + Members + - - Manage Members - - -
-
-
- -
-
+ + Manage Members + + + {/*
*/} +
+ } + onRowSelectionChange={(selected, table: any) => { + const selectedRow = table.getSelectedRowModel().rows[0]; + if (selectedRow) handleUpdate(selectedRow.original); + }} + >
-
+ {/*
*/} + ); }; diff --git a/src/pages/members/manage-members/blocks/DetailMember.tsx b/src/pages/members/manage-members/blocks/DetailMember.tsx index 4eac2e1..9852562 100644 --- a/src/pages/members/manage-members/blocks/DetailMember.tsx +++ b/src/pages/members/manage-members/blocks/DetailMember.tsx @@ -65,13 +65,13 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa setNationality(getNationality.data.data) setFormData({ ...formData, [name]: value }); } else { + if (name === 'municipio_id' || name === 'posto_adms_id' || name === 'suco_id') await getMasterAfter(name, value); setFormData({ ...formData, [name]: value }); - if (name === 'municipio' || name === 'posto_adms' || name === 'suco') await getMasterAfter(name, value); } }; async function getMasterAfter(name: string, id: any) { - if (name === 'municipio') { + if (name === 'municipio_id') { let getMunicipiosPosto = await axios.get(`${BASE_URL_MASTER_DATA}/municipios/postoadms/${id}`, { params: { limit: 50, @@ -83,7 +83,7 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa }); setPostoAdm(getMunicipiosPosto.data.data) } - if (name === 'posto_adms') { + if (name === 'posto_adms_id') { let getPostoSuco = await axios.get(`${BASE_URL_MASTER_DATA}/postoadms/sucos/${id}`, { params: { limit: 50, @@ -95,7 +95,7 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa }); setSucos(getPostoSuco.data.data) } - if (name === 'suco') { + if (name === 'suco_id') { let getSucoAldeias = await axios.get(`${BASE_URL_MASTER_DATA}/sucos/aldeias/${id}`, { params: { limit: 50, @@ -130,46 +130,21 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa } }); setGroups(getGroups.data.data.list); - // let getMunicipios = await axios.get(`${BASE_URL_MASTER_DATA}/municipios/list`, { - // params: { - // limit: 50, - // page: 1, - // with_deleted: false, - // order_field: 'name', - // order_direction: 'ASC', - // } - // }); - // setMunicipios(getMunicipios.data.data.list) - // let getPostoAdms = await axios.get(`${BASE_URL_MASTER_DATA}/postoadms/list`, { - // params: { - // limit: 50, - // page: 1, - // with_deleted: false, - // order_field: 'name', - // order_direction: 'ASC', - // } - // }); - // setPostoAdm(getPostoAdms.data.data.list) - // let getSucos = await axios.get(`${BASE_URL_MASTER_DATA}/sucos/list`, { - // params: { - // limit: 50, - // page: 1, - // with_deleted: false, - // order_field: 'name', - // order_direction: 'ASC', - // } - // }); - // setSucos(getSucos.data.data.list) - // let getAldeias = await axios.get(`${BASE_URL_MASTER_DATA}/aldeias/list`, { - // params: { - // limit: 50, - // page: 1, - // with_deleted: false, - // order_field: 'name', - // order_direction: 'ASC', - // } - // }); - // setAldeias(getAldeias.data.data.list) + + let getMunicipios = await axios.get(`${BASE_URL_MASTER_DATA}/municipios/list`, { + params: { + limit: 70, + page: 1, + with_deleted: false, + order_field: 'name', + order_direction: 'ASC', + } + }); + setMunicipios(getMunicipios.data.data.list) + if (formData.municipio_id) await handleChange({target: { name: "municipio_id",value: formData.municipio_id }}); + if (formData.posto_adms_id) await handleChange({target: { name: "posto_adms_id",value: formData.posto_adms_id }}); + if (formData.suco_id) await handleChange({target: { name: "suco_id",value: formData.suco_id }}); + if (formData.aldeia_id) await handleChange({target: { name: "aldeia_id",value: formData.aldeia_id }}); } catch (error:any) { console.log(error); toast.error(error.message) @@ -234,10 +209,10 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Email', 'email', 'text', true, viewOnly): ''} {/* {generateList(formData, handleChange, status, 'status', 'Status', null, true)} */} {(formData.id || dialogType === "create") ? generateList(formData, handleChange, profession, 'profession', 'Profession', false, false): ''} - {(formData.id || dialogType === "create") ? generateList(formData, handleChange, municipios, 'municipio', 'Municipio', false, false): ''} - {(formData.id || dialogType === "create") ? generateList(formData, handleChange, postoAdm, 'posto_adms', 'Posto', false, false): ''} - {(formData.id || dialogType === "create") ? generateList(formData, handleChange, sucos, 'suco', 'Suco', false, false): ''} - {(formData.id || dialogType === "create") ? generateList(formData, handleChange, aldeias, 'aldeia', 'Aldeia', false, false): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, municipios, 'municipio_id', 'Municipio', false, false): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, postoAdm, 'posto_adms_id', 'Posto', false, false): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, sucos, 'suco_id', 'Suco', false, false): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, aldeias, 'aldeia_id', 'Aldeia', false, false): ''} {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Nationality', 'nationality', 'text', true, viewOnly): ''}
diff --git a/src/pages/members/manage-members/blocks/ListToolBar.tsx b/src/pages/members/manage-members/blocks/ListToolBar.tsx new file mode 100644 index 0000000..77742b8 --- /dev/null +++ b/src/pages/members/manage-members/blocks/ListToolBar.tsx @@ -0,0 +1,53 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { Button } from '@/components/ui/button'; +import { useState } from 'react'; + +const ListToolbar = ({ createMember }: { createMember: () => void }) => { + const { table, reload } = useDataGrid(); + const [ usernameFilter, setUsernameFilter] = useState(''); + const [emailFilter, setEmailFilter] = useState(''); + + const handleUsernameChange = (e: React.ChangeEvent) => { + setUsernameFilter(e.target.value); + table.getColumn('username')?.setFilterValue(e.target.value); + }; + + const handleEmailChange = (e: React.ChangeEvent) => { + setEmailFilter(e.target.value); + table.getColumn('email')?.setFilterValue(e.target.value); + }; + + return ( +
+
+
+
+ +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/transaction/history-transaction/Transaction.tsx b/src/pages/transaction/history-transaction/Transaction.tsx index e0bc691..ca2dbf8 100644 --- a/src/pages/transaction/history-transaction/Transaction.tsx +++ b/src/pages/transaction/history-transaction/Transaction.tsx @@ -2,6 +2,7 @@ import { Container, DataGridInner } from '@/components'; import { TransactionProvider } from './hooks/TransactionContext'; import { Breadcrumbs, Link } from '@mui/material'; import { Helmet } from 'react-helmet'; +import ResendTransaction from './blocks/ResendTransaction'; const Transaction = () => { return ( @@ -28,6 +29,7 @@ const Transaction = () => {
+ diff --git a/src/pages/transaction/history-transaction/blocks/ResendTransaction.tsx b/src/pages/transaction/history-transaction/blocks/ResendTransaction.tsx new file mode 100644 index 0000000..2b4b13d --- /dev/null +++ b/src/pages/transaction/history-transaction/blocks/ResendTransaction.tsx @@ -0,0 +1,205 @@ +import { useTransactionContext } from '../hooks/useTransactionContext'; +import { useCallApi } from '@/hooks'; +import { apiConfig } from '@/config/api.config'; +import { useCallback, useEffect, useState } from 'react'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { Alert, useDataGrid } from '@/components'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { toast } from 'sonner'; +import { Input } from '@/components/ui/input'; + +const API_URL = apiConfig.transaction; + +const ResendTransaction = () => { + const { showResendDialog, handleResendDialog, selectedTransactionForResend } = useTransactionContext(); + const { GetData, PostData } = useCallApi(); + const { reload } = useDataGrid(); + const [transactionDetails, setTransactionDetails] = useState(null); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialStatePin = { + pin: '' + }; + const [formField, setFormField] = useState(initialStatePin); + + useEffect(() => { + if (showResendDialog) { + // Reset form fields when dialog opens + setFormField({ + pin: '' + }); + setAlert({ show: false, message: '' }); + setTransactionDetails(null); // Optional reset + } + }, [showResendDialog]); + + useEffect(() => { + const fetchTransactionDetails = async () => { + if (selectedTransactionForResend) { + try { + const response = await GetData( + `${API_URL}/transaction/history/detail/${selectedTransactionForResend}`, + { + id: selectedTransactionForResend, + } + ); + setTransactionDetails(response?.data); + } catch (error) { + console.error('Error fetching transaction', error); + } + } + + }; + + if (showResendDialog && selectedTransactionForResend) { + fetchTransactionDetails(); + } + }, [showResendDialog, selectedTransactionForResend, GetData]); + + const doResendTransaction = useCallback(async (data: any | null, pintransactiion: string) => { + + if (pintransactiion.trim() === '') { + setAlert({ show: true, message: 'Please fill pin.' }); + return; + } + + if (pintransactiion.length < 6) { + setAlert({ show: true, message: 'Pin length must be 6 characters long.' }); + return; + } + + if (!data) { + toast.error('No Transaction selected'); + return; + } + + if (!data.type) { + toast.error('No Transaction Type selected'); + return; + } + + let apiEndpoint: string | null | undefined = null; + let apiJsonData: any | null | undefined = null; + + switch (data.kind) { + case 'T': + apiEndpoint = `${API_URL}/transaction/transfer`; + apiJsonData = { + id_origin_customer: data.origin_customer.id, + msisdn_destination: data.transfer.destination_customer.msisdn, + id_transaction_type: data.type.id, + amount: String(data.transfer.amount), + pin: pintransactiion, + type: data.transfer.type + } + break; + case 'U': + apiEndpoint = `${API_URL}/transaction/topup`; + apiJsonData = { + id_origin_customer: data.origin_customer.id, + id_transaction_type: data.type.id, + pin_p24: data.transfer.pin_p24, + amount: String(data.transfer.amount), + pin: pintransactiion + } + break; + case 'W': + apiEndpoint = `${API_URL}/transaction/withdraw`; + apiJsonData = { + id_origin_customer: data.origin_customer.id, + id_transaction_type: data.type.id, + destination_iban: data.transfer.destination_iban, + amount: String(data.transfer.amount), + pin: pintransactiion + } + break; + case 'P': + apiEndpoint = `${API_URL}/transaction/purchase`; + apiJsonData = { + id_origin_customer: data.origin_customer.id, + code_product: "object purchase : masih null", + wallet: "emoney or point", + destination_number: "parameter number", + destination_amount: "parameter amount", + pin: pintransactiion + } + break; + } + + if (!apiEndpoint || !apiJsonData) { + toast.error('Invalid transaction'); + return; + } + + const response = await PostData(apiEndpoint, apiJsonData); + + if (response?.status) { + setAlert({ show: false, message: '' }); + handleResendDialog(false, null); + toast.success('Success Retry Transaction'); + reload(); + + const createActivity = { + module: 'History Transaction', + description: `Retry Transaction => ${selectedTransactionForResend}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); + } else { + setAlert({ show: true, message: response?.message }); + toast.error('Failed Retry Transaction'); + } + }, [selectedTransactionForResend, PostData, handleResendDialog, reload]); + + return ( + handleResendDialog(open, null)}> + + + + + +

Are you sure?

+ You will retry this transaction! +
+ {alert.show && ( + +

{alert.message}

+
+ )} +
+ + + setFormField({ ...formField, pin: e.target.value })} + /> + + + + +
+
+ ); +}; + +export default ResendTransaction; diff --git a/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx index 6a39771..00bbdf0 100644 --- a/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx +++ b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx @@ -9,6 +9,9 @@ import ListToolbar from '../blocks/ListToolbar'; import { Button } from '@/components/ui/button'; import { useNavigate } from 'react-router'; import DetailTransaction from '../blocks/DetailTransaction'; +import { log } from 'console'; +import ResendTransaction from '../blocks/ResendTransaction'; +import { comment } from 'stylis'; interface TransactionProps { id: number; @@ -28,6 +31,9 @@ interface ContextProps { setShowDetailDialog: React.Dispatch>; selectedTransactionId: number | null; setSelectedTransactionId: React.Dispatch>; + showResendDialog: boolean; + handleResendDialog: (show: boolean, selected_transaction: string | null) => void; + selectedTransactionForResend: string | null; } const initialProps: ContextProps = { @@ -35,7 +41,10 @@ const initialProps: ContextProps = { showDetailDialog: false, setShowDetailDialog: () => { }, selectedTransactionId: null, - setSelectedTransactionId: () => { } + setSelectedTransactionId: () => { }, + showResendDialog: false, + handleResendDialog: (show: boolean, selected_transaction: string | null) => { }, + selectedTransactionForResend: null }; const ManageTransactionContext = createContext(initialProps); @@ -50,6 +59,14 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { const handleNavigate = (path: string) => { const url = navigate(`${API_URL}/transaction/history/${path}`); }; + const [showResendDialog, setShowResendDialog] = useState(false); + const [selectedTransactionForResend, setSelectedTransactionForResend] = useState(null); + + const handleResendDialog = useCallback((show: boolean, selected_transaction: string | null) => { + setSelectedTransactionForResend(show ? selected_transaction : null); + setShowResendDialog(show); + }, []); + const columns = useMemo[]>( () => [ @@ -162,7 +179,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { ); }, - }, + }, { accessorKey: 'description', header: ({ column }) => , @@ -188,6 +205,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { enableHiding: false, cell: (data) => { const row = data.row.original; + const isVisible = row.status === 'F' ? true : false || row.status === 'P' ? true : false; return (
+ {/* add new button for resend transaction failed */} + {isVisible && + + }
); }, @@ -208,7 +238,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { } } ], - []); + [handleResendDialog]); const getTransactionLists = async (page: number, limit: number, sorting: any, filter: any) => { try { @@ -259,7 +289,10 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { showDetailDialog, setShowDetailDialog, selectedTransactionId, - setSelectedTransactionId + setSelectedTransactionId, + showResendDialog, + handleResendDialog, + selectedTransactionForResend }} > diff --git a/src/pages/transfer/transfertype/blocks/AddDialog.tsx b/src/pages/transfer/transfertype/blocks/AddDialog.tsx index 6e5f51f..fe6eff6 100644 --- a/src/pages/transfer/transfertype/blocks/AddDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/AddDialog.tsx @@ -467,6 +467,10 @@ const AddDialog = () => { Return Agent Merchant Return Agent Emoney Reward Point + Top Up Escrow + Top Up Master Agent + Top Up Agent +
diff --git a/src/pages/transfer/transfertype/blocks/EditDialog.tsx b/src/pages/transfer/transfertype/blocks/EditDialog.tsx index 1e3ca41..1d9803b 100644 --- a/src/pages/transfer/transfertype/blocks/EditDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/EditDialog.tsx @@ -589,7 +589,7 @@ const EditDialog = () => { - Disbursement + Disbursement Other Change Group Emoney Customer to Agent Change Group Emoney Agent to Customer @@ -600,6 +600,9 @@ const EditDialog = () => { Return Agent Merchant Return Agent Emoney Reward Point + Top Up Escrow + Top Up Master Agent + Top Up Agent
diff --git a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx index 942ee8f..7e886a3 100644 --- a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx +++ b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx @@ -159,7 +159,10 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React AD: 'Return Agent Deposit', AM: 'Return Agent Merchant', AE: 'Return Agent Emoney', - R: 'Reward Point' + R: 'Reward Point', + TE:'Top Up Escrow', + TM:'Top Up Master Agent', + TA:'Top Up Agent' }; return mapping[row.type] || 'Unknown'; diff --git a/yarn.lock b/yarn.lock index 68a5c2d..52913b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -631,11 +631,121 @@ resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz" integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + "@esbuild/darwin-arm64@0.21.5": version "0.21.5" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz" integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.1" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz" @@ -1580,11 +1690,96 @@ resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz" integrity sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA== +"@rollup/rollup-android-arm-eabi@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.2.tgz" + integrity sha512-ufoveNTKDg9t/b7nqI3lwbCG/9IJMhADBNjjz/Jn6LxIZxD7T5L8l2uO/wD99945F1Oo8FvgbbZJRguyk/BdzA== + +"@rollup/rollup-android-arm64@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.2.tgz" + integrity sha512-iZoYCiJz3Uek4NI0J06/ZxUgwAfNzqltK0MptPDO4OR0a88R4h0DSELMsflS6ibMCJ4PnLvq8f7O1d7WexUvIA== + "@rollup/rollup-darwin-arm64@4.24.2": version "4.24.2" resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.2.tgz" integrity sha512-/UhrIxobHYCBfhi5paTkUDQ0w+jckjRZDZ1kcBL132WeHZQ6+S5v9jQPVGLVrLbNUebdIRpIt00lQ+4Z7ys4Rg== +"@rollup/rollup-darwin-x64@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.2.tgz" + integrity sha512-1F/jrfhxJtWILusgx63WeTvGTwE4vmsT9+e/z7cZLKU8sBMddwqw3UV5ERfOV+H1FuRK3YREZ46J4Gy0aP3qDA== + +"@rollup/rollup-freebsd-arm64@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.2.tgz" + integrity sha512-1YWOpFcGuC6iGAS4EI+o3BV2/6S0H+m9kFOIlyFtp4xIX5rjSnL3AwbTBxROX0c8yWtiWM7ZI6mEPTI7VkSpZw== + +"@rollup/rollup-freebsd-x64@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.2.tgz" + integrity sha512-3qAqTewYrCdnOD9Gl9yvPoAoFAVmPJsBvleabvx4bnu1Kt6DrB2OALeRVag7BdWGWLhP1yooeMLEi6r2nYSOjg== + +"@rollup/rollup-linux-arm-gnueabihf@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.2.tgz" + integrity sha512-ArdGtPHjLqWkqQuoVQ6a5UC5ebdX8INPuJuJNWRe0RGa/YNhVvxeWmCTFQ7LdmNCSUzVZzxAvUznKaYx645Rig== + +"@rollup/rollup-linux-arm-musleabihf@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.2.tgz" + integrity sha512-B6UHHeNnnih8xH6wRKB0mOcJGvjZTww1FV59HqJoTJ5da9LCG6R4SEBt6uPqzlawv1LoEXSS0d4fBlHNWl6iYw== + +"@rollup/rollup-linux-arm64-gnu@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.2.tgz" + integrity sha512-kr3gqzczJjSAncwOS6i7fpb4dlqcvLidqrX5hpGBIM1wtt0QEVtf4wFaAwVv8QygFU8iWUMYEoJZWuWxyua4GQ== + +"@rollup/rollup-linux-arm64-musl@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.2.tgz" + integrity sha512-TDdHLKCWgPuq9vQcmyLrhg/bgbOvIQ8rtWQK7MRxJ9nvaxKx38NvY7/Lo6cYuEnNHqf6rMqnivOIPIQt6H2AoA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.2.tgz" + integrity sha512-xv9vS648T3X4AxFFZGWeB5Dou8ilsv4VVqJ0+loOIgDO20zIhYfDLkk5xoQiej2RiSQkld9ijF/fhLeonrz2mw== + +"@rollup/rollup-linux-riscv64-gnu@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.2.tgz" + integrity sha512-tbtXwnofRoTt223WUZYiUnbxhGAOVul/3StZ947U4A5NNjnQJV5irKMm76G0LGItWs6y+SCjUn/Q0WaMLkEskg== + +"@rollup/rollup-linux-s390x-gnu@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.2.tgz" + integrity sha512-gc97UebApwdsSNT3q79glOSPdfwgwj5ELuiyuiMY3pEWMxeVqLGKfpDFoum4ujivzxn6veUPzkGuSYoh5deQ2Q== + +"@rollup/rollup-linux-x64-gnu@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.2.tgz" + integrity sha512-jOG/0nXb3z+EM6SioY8RofqqmZ+9NKYvJ6QQaa9Mvd3RQxlH68/jcB/lpyVt4lCiqr04IyaC34NzhUqcXbB5FQ== + +"@rollup/rollup-linux-x64-musl@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.2.tgz" + integrity sha512-XAo7cJec80NWx9LlZFEJQxqKOMz/lX3geWs2iNT5CHIERLFfd90f3RYLLjiCBm1IMaQ4VOX/lTC9lWfzzQm14Q== + +"@rollup/rollup-win32-arm64-msvc@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.2.tgz" + integrity sha512-A+JAs4+EhsTjnPQvo9XY/DC0ztaws3vfqzrMNMKlwQXuniBKOIIvAAI8M0fBYiTCxQnElYu7mLk7JrhlQ+HeOw== + +"@rollup/rollup-win32-ia32-msvc@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.2.tgz" + integrity sha512-ZhcrakbqA1SCiJRMKSU64AZcYzlZ/9M5LaYil9QWxx9vLnkQ9Vnkve17Qn4SjlipqIIBFKjBES6Zxhnvh0EAEw== + +"@rollup/rollup-win32-x64-msvc@4.24.2": + version "4.24.2" + resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.2.tgz" + integrity sha512-2mLH46K1u3r6uwc95hU+OR9q/ggYMpnS7pSp83Ece1HUQgF9Nh/QwTK5rcgbFnV9j+08yBrU5sA/P0RK2MSBNA== + "@tanstack/query-core@5.59.20": version "5.59.20" resolved "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.20.tgz" @@ -3055,6 +3250,80 @@ merge2@^1.3.0: resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +"metronic-tailwind-react@file:": + version "9.1.2" + resolved "file:" + dependencies: + "@auth0/auth0-spa-js" "^2.1.3" + "@emotion/cache" "^11.13.1" + "@emotion/react" "^11.13.3" + "@emotion/styled" "^11.13.0" + "@faker-js/faker" "^9.1.0" + "@firebase/app" "^0.10.15" + "@firebase/auth" "^1.8.0" + "@firebase/firestore" "^4.7.4" + "@formatjs/intl-pluralrules" "^5.3.4" + "@formatjs/intl-relativetimeformat" "^11.4.4" + "@mui/base" "5.0.0-beta.40" + "@mui/icons-material" "^6.4.6" + "@mui/material" "^6.1.6" + "@mui/utils" "^6.1.6" + "@radix-ui/react-avatar" "^1.1.1" + "@radix-ui/react-checkbox" "^1.1.2" + "@radix-ui/react-collapsible" "^1.1.1" + "@radix-ui/react-dialog" "^1.1.2" + "@radix-ui/react-dropdown-menu" "^2.1.2" + "@radix-ui/react-popover" "^1.1.2" + "@radix-ui/react-scroll-area" "^1.2.0" + "@radix-ui/react-select" "^2.1.2" + "@radix-ui/react-separator" "^1.1.0" + "@radix-ui/react-slider" "^1.2.1" + "@radix-ui/react-slot" "^1.1.0" + "@radix-ui/react-switch" "^1.1.1" + "@radix-ui/react-tooltip" "^1.1.3" + "@tanstack/react-query" "^5.59.20" + "@tanstack/react-table" "^8.20.5" + apexcharts "3.52.0" + axios "^1.7.7" + class-variance-authority "^0.7.0" + clsx "^2.1.1" + cmdk "^1.0.4" + date-fns "^3.0.0" + formik "^2.4.6" + helmet "^8.1.0" + https "^1.0.0" + leaflet "^1.9.4" + lucide-react "^0.456.0" + metronic-tailwind-react "file:" + mini-svg-data-uri "^1.4.4" + moment "^2.30.1" + next-themes "^0.4.3" + notistack "^3.0.1" + postcss-preset-env "^10.1.0" + qs "^6.13.0" + react "^18.3.1" + react-apexcharts "1.4.1" + react-day-picker "^8.10.1" + react-dom "^18.3.1" + react-helmet "^6.1.0" + react-helmet-async "^2.0.5" + react-inlinesvg "^4.1.4" + react-intl "^6.8.7" + react-leaflet "^4.2.1" + react-number-format "^5.4.3" + react-query "^3.39.3" + react-router "^6.28.0" + react-router-dom "^6.28.0" + sonner "^1.7.0" + styled-components "^6.1.13" + stylis "^4.3.4" + stylis-plugin-rtl "^2.1.1" + tabs "^0.2.0" + tailwind-merge "^2.5.4" + tailwindcss-animate "^1.0.7" + vite-plugin-windicss "^1.9.3" + yup "^1.4.0" + micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.8" resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"