From 5b8ba073914be229b3a563ddc1f476b13ca25f71 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 20 Feb 2025 21:51:48 +0700 Subject: [PATCH 01/29] update: header color and size logo --- src/layouts/demo2/header/Header.tsx | 2 +- src/layouts/demo2/header/HeaderLogo.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/layouts/demo2/header/Header.tsx b/src/layouts/demo2/header/Header.tsx index fa2c522..474cf23 100644 --- a/src/layouts/demo2/header/Header.tsx +++ b/src/layouts/demo2/header/Header.tsx @@ -19,7 +19,7 @@ const Header = () => { return (
{ /> */} logo {
-

TPAY Dashboard Portal

+

TPAY Dashboard Portal

); From 276240fb3239033f01da7194734bbc9e63072d48 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 20 Feb 2025 21:53:17 +0700 Subject: [PATCH 02/29] feat: add static chart --- .../dashboards/home/DashboardHomePage.tsx | 6 +- src/pages/dashboards/home/blocks/Chart.tsx | 2 +- src/pages/dashboards/home/staticChart.tsx | 189 ++++++++++++++++++ 3 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 src/pages/dashboards/home/staticChart.tsx diff --git a/src/pages/dashboards/home/DashboardHomePage.tsx b/src/pages/dashboards/home/DashboardHomePage.tsx index fa75b05..61e3af5 100644 --- a/src/pages/dashboards/home/DashboardHomePage.tsx +++ b/src/pages/dashboards/home/DashboardHomePage.tsx @@ -14,6 +14,8 @@ import { useFetchCardData, useFetchChartData } from './hooks'; import { Button } from '@/components/ui/button'; import { useFetchYear } from './hooks/useFetchYear'; import { get5LastYear } from '@/utils/Date'; +import { staticChartData } from './staticChart'; + // sum -> nominal, count-> total type CountType = 'sum' | 'count'; type ChartType = 'line' | 'bar'; @@ -184,9 +186,9 @@ const DashboardHomePage = () => {
data.data)} chartType={chartType} chartLegend={chartLegend} /> diff --git a/src/pages/dashboards/home/blocks/Chart.tsx b/src/pages/dashboards/home/blocks/Chart.tsx index 34f2df5..25cdad0 100644 --- a/src/pages/dashboards/home/blocks/Chart.tsx +++ b/src/pages/dashboards/home/blocks/Chart.tsx @@ -37,7 +37,7 @@ const Chart = ({ plotOptions: { bar: { horizontal: false, - columnWidth: '50%' + columnWidth: '30%' } }, dataLabels: { diff --git a/src/pages/dashboards/home/staticChart.tsx b/src/pages/dashboards/home/staticChart.tsx new file mode 100644 index 0000000..f83830d --- /dev/null +++ b/src/pages/dashboards/home/staticChart.tsx @@ -0,0 +1,189 @@ +export const staticChartData = { + series: [ + { + categories: 'Jan', + data: [ + { + x: 'Jan 01', + y: 50 + }, + ] + }, + { + data: [ + { + x: 'Jan 02', + y: 75 + } + ] + }, + { + data: [ + { + x: 'Jan 03', + y: 200 + } + ] + }, + { + data: [ + { + x: 'Jan 04', + y: 125 + } + ] + }, + { + data: [ + { + x: 'Jan 05', + y: 150 + } + ] + }, + { + data: [ + { + x: 'Jan 06', + y: 175 + } + ] + } + ], + xaxis: { + categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + } +}; + +// const staticChartData = { +// series: [ +// { +// name: 'Sales', +// data: [ +// { +// x: 'Jan', +// y: 20 +// } +// ] +// }, +// { +// name: 'Orders', +// data: [ +// { +// x: 'Feb', +// y: 32 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'Mar', +// y: 41 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'Apr', +// y: 38 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'May', +// y: 50 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'Jun', +// y: 47 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'Jul', +// y: 62 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'Aug', +// y: 51 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'Sep', +// y: 25 +// } +// ] +// }, + +// { +// data: [ +// { +// x: 'Oct', +// y: 72 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'Nov', +// y: 70 +// } +// ] +// }, +// { +// data: [ +// { +// x: 'Des', +// y: 100 +// } +// ] +// }, +// ], +// options: { +// chart: { +// type: chartType, +// height: 350 +// }, +// title: { +// text: 'Overview', +// align: 'center' +// }, +// xaxis: { +// categories: [ +// 'Jan', +// 'Feb', +// 'Mar', +// 'Apr', +// 'May', +// 'Jun', +// 'Jul', +// 'Aug', +// 'Sep', +// 'Oct', +// 'Nov', +// 'Dec' +// ] +// }, +// legend: { +// show: chartLegend === 'true' +// } +// } +// }; From fa5f14355882277bf50beb90283a0215f60f1cea Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 20 Feb 2025 21:54:43 +0700 Subject: [PATCH 03/29] fix: use API prod siblysolution/api/d --- .env.development | 4 ++-- src/config/api.config.ts | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.env.development b/.env.development index 5c3d451..58a088c 100644 --- a/.env.development +++ b/.env.development @@ -2,6 +2,6 @@ VITE_APP_NAME=tpay-dashboard-tl VITE_APP_VERSION=1=9.1.1 GENERATE_SOURCEMAP=false -# VITE_APP_API_URL=https://tpay.shiblysolution.id/api -VITE_APP_API_URL=http://127.0.0.1:4003/api +VITE_APP_API_URL=https://tpay.shiblysolution.id/api +# VITE_APP_API_URL=http://127.0.0.1:4003/api VITE_ENV=development diff --git a/src/config/api.config.ts b/src/config/api.config.ts index 07e6b58..3d321e3 100644 --- a/src/config/api.config.ts +++ b/src/config/api.config.ts @@ -4,9 +4,11 @@ interface apiConfigProps { } const API_URL = import.meta.env.VITE_APP_API_URL; +console.log(API_URL); const apiConfig: apiConfigProps = { - service_dashboard: `${API_URL}${import.meta.env.VITE_ENV != 'development' ? '/d' : ""}`, - service_master_data: `${API_URL}/m`, + // service_dashboard: `${API_URL}${import.meta.env.VITE_ENV != 'development' ? '/d' : ''}`, + service_dashboard: `${API_URL}/d`, + service_master_data: `${API_URL}/m` }; export { apiConfig }; From fdabe259500074b6ba176a8e995fe565521d5795 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 20 Feb 2025 21:55:42 +0700 Subject: [PATCH 04/29] feat: add table component on manage account and manage groups --- src/components/ui/DataTable.tsx | 91 ++++++++++++++++++++ src/pages/account/manage/ManageAccount.tsx | 81 +++++++++++++++++ src/pages/account/manage/account/Columns.tsx | 71 +++++++++++++++ src/pages/groups/Column.tsx | 30 +++++++ src/pages/groups/ManageGroups.tsx | 36 ++++++++ 5 files changed, 309 insertions(+) create mode 100644 src/components/ui/DataTable.tsx create mode 100644 src/pages/account/manage/ManageAccount.tsx create mode 100644 src/pages/account/manage/account/Columns.tsx create mode 100644 src/pages/groups/Column.tsx create mode 100644 src/pages/groups/ManageGroups.tsx diff --git a/src/components/ui/DataTable.tsx b/src/components/ui/DataTable.tsx new file mode 100644 index 0000000..e18d65f --- /dev/null +++ b/src/components/ui/DataTable.tsx @@ -0,0 +1,91 @@ +'use client'; + +import { + ColumnDef, + ColumnFiltersState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + useReactTable +} from '@tanstack/react-table'; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow +} from '@/components/ui/table'; +import { useState } from 'react'; +import { Input } from './input'; + +interface DataTableProps { + columns: ColumnDef[]; + data: TData[]; +} + +export function DataTable({ columns, data }: DataTableProps) { + const [columnFilters, setColumnFilters] = useState([]); + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + state: { + columnFilters + } + }); + + return ( +
+
+ table.getColumn('name')?.setFilterValue(event.target.value)} + className="max-w-sm" + /> +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender(header.column.columnDef.header, header.getContext())} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+ ); +} diff --git a/src/pages/account/manage/ManageAccount.tsx b/src/pages/account/manage/ManageAccount.tsx new file mode 100644 index 0000000..522bf0a --- /dev/null +++ b/src/pages/account/manage/ManageAccount.tsx @@ -0,0 +1,81 @@ +import { apiConfig } from '@/config/api.config'; +import { Account, columns } from './account/Columns'; +import { DataTable } from '@/components/ui/DataTable'; +import axios from 'axios'; +import { useEffect, useState } from 'react'; +import { getData } from '@/utils'; +import { useCallApi } from '@/hooks'; + +const API_URL = apiConfig.service_dashboard; + +const dataAccount: Account[] = [ + { + id: 1, + name: 'eMoney Account', + description: 'Rekening Member eMoney', + systemAccount: false, + createdDate: new Date('2019-12-05'), + creditLimit: null, + currency: null + }, + { + id: 2, + name: 'Merchant Account', + description: 'Rekening Merchant', + systemAccount: false, + createdDate: new Date(), + creditLimit: null, + currency: null + } +]; + +const ManageAccount = () => { + const [accounts, setAccounts] = useState([]); + const { GetData } = useCallApi(); + // console.log(accounts); + + useEffect(() => { + const fetchAccount = async () => { + try { + const response = await fetch(`${API_URL}/user/list`); + const data: Account[] = await response.json(); + setAccounts(data); + } catch (error) { + console.error('Error fetching data', error); + } + }; + + fetchAccount(); + }, []); + + // const fetchAccount = async (page: number, limit: number, sorting: any, filter: any) => { + // try { + // const response = await GetData(`${API_URL}/user/list`, { + // limit: limit, + // page: page + 1, + // with_deleted: true, + // order_field: sorting[0].id, + // order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', + // filter: JSON.stringify(filter) + // }); + + // setAccounts(response?.data.list); + + // return { + // data: response?.data.list, + // totalCount: response?.data.total_count + // }; + // } catch (error) { + // console.log(error); + // } + // }; + + return ( +
+

Manage Account

+ +
+ ); +}; + +export default ManageAccount; diff --git a/src/pages/account/manage/account/Columns.tsx b/src/pages/account/manage/account/Columns.tsx new file mode 100644 index 0000000..64fc8fa --- /dev/null +++ b/src/pages/account/manage/account/Columns.tsx @@ -0,0 +1,71 @@ +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu'; +import { ColumnDef } from '@tanstack/react-table'; +import { MoreHorizontal } from 'lucide-react'; + +export type Account = { + createdDate: Date; + creditLimit: number | null; + currency: string | null; + description: string; + id: number; + name: string; + systemAccount: boolean; +}; + +export const columns: ColumnDef[] = [ + { + accessorKey: 'id', + header: 'ID' + }, + { + accessorKey: 'name', + header: 'Name' + }, + { + accessorKey: 'description', + header: 'Description' + }, + { + accessorKey: 'systemAccount', + header: 'System Account' + }, + { + accessorKey: 'createdDate', + header: 'Created Date', + cell: ({ row }) => new Date(row.original.createdDate).toLocaleDateString() + }, + { + id: 'actions', + cell: ({ row }) => { + const dataAccount = row.original; + + return ( + + + + + + Actions + navigator.clipboard.writeText(dataAccount.id.toString())} + > + Copy account ID + + {/* */} + + + ); + } + } +]; diff --git a/src/pages/groups/Column.tsx b/src/pages/groups/Column.tsx new file mode 100644 index 0000000..bcd9476 --- /dev/null +++ b/src/pages/groups/Column.tsx @@ -0,0 +1,30 @@ +import { ColumnDef } from '@tanstack/react-table'; + +export type Group = { + id: number; + createdDate: Date; + name: string; + description: string; +}; + +export const columns: ColumnDef[] = [ + { + accessorKey: 'id', + header: 'ID' + }, + { + accessorKey: 'createdDate', + header: 'Created Date' + }, + { + accessorKey: 'name', + header: 'Name' + }, + { + accessorKey: 'description', + header: 'Description' + }, + { + id: 'actions' + } +]; diff --git a/src/pages/groups/ManageGroups.tsx b/src/pages/groups/ManageGroups.tsx new file mode 100644 index 0000000..bdbdb34 --- /dev/null +++ b/src/pages/groups/ManageGroups.tsx @@ -0,0 +1,36 @@ +import { DataTable } from '@/components/ui/DataTable'; +import { columns, Group } from './Column'; + +const dataGroup: Group[] = [ + { + id: 1, + createdDate: new Date('2018-11-23'), + name: 'ADMIN', + description: 'Admin Web' + }, + { + id: 2, + createdDate: new Date('2019-02-08'), + name: 'BANK', + description: 'Bank/Switching Group' + }, + { + id: 3, + createdDate: new Date('2018-11-27'), + name: 'REGULER', + description: 'Reguler Member' + } +]; + +const ManageGroups = () => { + return ( +
+
+

Groups

+ +
+
+ ); +}; + +export default ManageGroups; From 743d2bfcb9e940f0a0227b64e050a0af076ca866 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 20 Feb 2025 21:56:30 +0700 Subject: [PATCH 05/29] fix: padding bot and margin bot --- src/layouts/demo2/navbar/Navbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/demo2/navbar/Navbar.tsx b/src/layouts/demo2/navbar/Navbar.tsx index a114628..86b7a2a 100644 --- a/src/layouts/demo2/navbar/Navbar.tsx +++ b/src/layouts/demo2/navbar/Navbar.tsx @@ -3,7 +3,7 @@ import { NavbarMenu } from '../'; const Navbar = () => { return ( -
+
From 2a1d10fd3d56ac362f45db55e78575c929ae2e7c Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 20 Feb 2025 21:57:10 +0700 Subject: [PATCH 06/29] feat: add routing for ManageAccount and ManageGroups --- .../account/manage/account/hooks/ManageAccountContext.tsx | 3 +++ src/routing/AppRoutingSetup.tsx | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 src/pages/account/manage/account/hooks/ManageAccountContext.tsx diff --git a/src/pages/account/manage/account/hooks/ManageAccountContext.tsx b/src/pages/account/manage/account/hooks/ManageAccountContext.tsx new file mode 100644 index 0000000..80ac1c0 --- /dev/null +++ b/src/pages/account/manage/account/hooks/ManageAccountContext.tsx @@ -0,0 +1,3 @@ +import { apiConfig } from '@/config/api.config'; + +const API_URL = apiConfig.service_dashboard; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index 33492a5..0ff7067 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -11,6 +11,8 @@ import ManageUserPage from '@/pages/settings/user/manage-user/ManageUserPage'; import LogActivityPage from '@/pages/settings/user/log-activity/LogActivityPage'; import ManagePositionPage from '@/pages/settings/user/manage-position/ManagePositionPage'; +import ManageAccount from '@/pages/account/manage/ManageAccount'; +import ManageGroups from '@/pages/groups/ManageGroups'; const AppRoutingSetup = (): ReactElement => { return ( @@ -18,6 +20,8 @@ const AppRoutingSetup = (): ReactElement => { }> }> } /> + } /> + } /> } /> @@ -26,6 +30,7 @@ const AppRoutingSetup = (): ReactElement => { path="/settings/user-management/manage-position" element={} /> + } /> } /> From 2a7492262146ce9d2b21bf8f328c5a80fe4834b8 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Fri, 21 Feb 2025 11:29:36 +0700 Subject: [PATCH 07/29] feat: add an opsional component for handling the create new group form --- src/components/ui/DataTable.tsx | 23 +++++- src/pages/groups/ManageGroups.tsx | 129 +++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 3 deletions(-) diff --git a/src/components/ui/DataTable.tsx b/src/components/ui/DataTable.tsx index e18d65f..73ca407 100644 --- a/src/components/ui/DataTable.tsx +++ b/src/components/ui/DataTable.tsx @@ -19,13 +19,26 @@ import { } from '@/components/ui/table'; import { useState } from 'react'; import { Input } from './input'; +import { Button } from './button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger +} from './dialog'; interface DataTableProps { columns: ColumnDef[]; data: TData[]; } -export function DataTable({ columns, data }: DataTableProps) { +export function DataTable({ + columns, + data, + createGroup +}: DataTableProps & { createGroup?: () => void }) { const [columnFilters, setColumnFilters] = useState([]); const table = useReactTable({ data, @@ -40,13 +53,19 @@ export function DataTable({ columns, data }: DataTableProps -
+
table.getColumn('name')?.setFilterValue(event.target.value)} className="max-w-sm" /> + + {createGroup && ( + + )}
diff --git a/src/pages/groups/ManageGroups.tsx b/src/pages/groups/ManageGroups.tsx index bdbdb34..8da31ba 100644 --- a/src/pages/groups/ManageGroups.tsx +++ b/src/pages/groups/ManageGroups.tsx @@ -1,5 +1,23 @@ import { DataTable } from '@/components/ui/DataTable'; import { columns, Group } from './Column'; +import { Button } from '@/components/ui/button'; +import { Link } from 'react-router-dom'; +import { + Dialog, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger +} from '@/components/ui/dialog'; +import { DialogContent } from '@mui/material'; +import { useState } from 'react'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; const dataGroup: Group[] = [ { @@ -23,11 +41,120 @@ const dataGroup: Group[] = [ ]; const ManageGroups = () => { + const [isDialogOpen, setIsDialogOpen] = useState(false); + const [formData, setFormData] = useState({ + groupName: '', + description: '', + pin_length: '', + max_pin_attempts: '', + default_notification: '' + }); + + const openDialog = () => setIsDialogOpen(true); + const closeDialog = () => setIsDialogOpen(false); + + const handleChange = (e: React.ChangeEvent) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value + }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + console.log('Submitted Data', formData); + closeDialog(); + }; + return (

Groups

- + + + + +
+ Create New Group + Fill out the form to create a new group +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + {/* */} +
+ + +
+
+
); From d1b95189dc33662e9b23bfe2b93b358f3acc0a9c Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Fri, 21 Feb 2025 11:31:16 +0700 Subject: [PATCH 08/29] update --- src/pages/account/manage/ManageAccount.tsx | 8 +- src/pages/dashboards/home/staticChart.tsx | 135 +-------------------- 2 files changed, 6 insertions(+), 137 deletions(-) diff --git a/src/pages/account/manage/ManageAccount.tsx b/src/pages/account/manage/ManageAccount.tsx index 522bf0a..402e5ca 100644 --- a/src/pages/account/manage/ManageAccount.tsx +++ b/src/pages/account/manage/ManageAccount.tsx @@ -71,9 +71,11 @@ const ManageAccount = () => { // }; return ( -
-

Manage Account

- +
+
+

Manage Account

+ +
); }; diff --git a/src/pages/dashboards/home/staticChart.tsx b/src/pages/dashboards/home/staticChart.tsx index f83830d..1c777f1 100644 --- a/src/pages/dashboards/home/staticChart.tsx +++ b/src/pages/dashboards/home/staticChart.tsx @@ -6,7 +6,7 @@ export const staticChartData = { { x: 'Jan 01', y: 50 - }, + } ] }, { @@ -54,136 +54,3 @@ export const staticChartData = { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] } }; - -// const staticChartData = { -// series: [ -// { -// name: 'Sales', -// data: [ -// { -// x: 'Jan', -// y: 20 -// } -// ] -// }, -// { -// name: 'Orders', -// data: [ -// { -// x: 'Feb', -// y: 32 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'Mar', -// y: 41 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'Apr', -// y: 38 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'May', -// y: 50 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'Jun', -// y: 47 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'Jul', -// y: 62 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'Aug', -// y: 51 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'Sep', -// y: 25 -// } -// ] -// }, - -// { -// data: [ -// { -// x: 'Oct', -// y: 72 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'Nov', -// y: 70 -// } -// ] -// }, -// { -// data: [ -// { -// x: 'Des', -// y: 100 -// } -// ] -// }, -// ], -// options: { -// chart: { -// type: chartType, -// height: 350 -// }, -// title: { -// text: 'Overview', -// align: 'center' -// }, -// xaxis: { -// categories: [ -// 'Jan', -// 'Feb', -// 'Mar', -// 'Apr', -// 'May', -// 'Jun', -// 'Jul', -// 'Aug', -// 'Sep', -// 'Oct', -// 'Nov', -// 'Dec' -// ] -// }, -// legend: { -// show: chartLegend === 'true' -// } -// } -// }; From ca6217b4cc5711d1326985ab7116e3f68935fe03 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Fri, 21 Feb 2025 17:50:32 +0700 Subject: [PATCH 09/29] feat: add pagination and sorting --- src/components/ui/DataTable.tsx | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/components/ui/DataTable.tsx b/src/components/ui/DataTable.tsx index 73ca407..1dd2605 100644 --- a/src/components/ui/DataTable.tsx +++ b/src/components/ui/DataTable.tsx @@ -6,6 +6,9 @@ import { flexRender, getCoreRowModel, getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + SortingState, useReactTable } from '@tanstack/react-table'; @@ -40,13 +43,19 @@ export function DataTable({ createGroup }: DataTableProps & { createGroup?: () => void }) { const [columnFilters, setColumnFilters] = useState([]); + const [sorting, setSorting] = useState([]); + const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), onColumnFiltersChange: setColumnFilters, + getPaginationRowModel: getPaginationRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), state: { + sorting, columnFilters } }); @@ -105,6 +114,24 @@ export function DataTable({
+
+ + +
); } From 6b37f3a2d03a309e2137028e3c40e9a3221e0647 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Fri, 21 Feb 2025 17:51:13 +0700 Subject: [PATCH 10/29] feat: ManageAccount and ManageMembers --- .../manage/{ => account}/ManageAccount.tsx | 2 +- src/pages/account/manage/members/Columns.tsx | 119 ++++++++++++++++++ .../account/manage/members/ManageMembers.tsx | 42 +++++++ src/routing/AppRoutingSetup.tsx | 5 +- 4 files changed, 166 insertions(+), 2 deletions(-) rename src/pages/account/manage/{ => account}/ManageAccount.tsx (97%) create mode 100644 src/pages/account/manage/members/Columns.tsx create mode 100644 src/pages/account/manage/members/ManageMembers.tsx diff --git a/src/pages/account/manage/ManageAccount.tsx b/src/pages/account/manage/account/ManageAccount.tsx similarity index 97% rename from src/pages/account/manage/ManageAccount.tsx rename to src/pages/account/manage/account/ManageAccount.tsx index 402e5ca..b2a5f31 100644 --- a/src/pages/account/manage/ManageAccount.tsx +++ b/src/pages/account/manage/account/ManageAccount.tsx @@ -1,5 +1,5 @@ import { apiConfig } from '@/config/api.config'; -import { Account, columns } from './account/Columns'; +import { Account, columns } from './Columns'; import { DataTable } from '@/components/ui/DataTable'; import axios from 'axios'; import { useEffect, useState } from 'react'; diff --git a/src/pages/account/manage/members/Columns.tsx b/src/pages/account/manage/members/Columns.tsx new file mode 100644 index 0000000..c217e7f --- /dev/null +++ b/src/pages/account/manage/members/Columns.tsx @@ -0,0 +1,119 @@ +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu'; +import { ColumnDef } from '@tanstack/react-table'; +import { ArrowUpDown, MoreHorizontal } from 'lucide-react'; + +export type Members = { + id: number; + username: number; + name: string; + group: string; + email: string; + createdDate: Date; +}; + +export const columns: ColumnDef[] = [ + { + accessorKey: 'id', + header: ({ column }) => { + return ( + + ); + } + }, + { + accessorKey: 'username', + header: ({ column }) => { + return ( + + ); + } + }, + { + accessorKey: 'name', + header: ({ column }) => { + return ( + + ); + } + }, + { + accessorKey: 'email', + header: ({ column }) => { + return ( + + ); + } + }, + { + accessorKey: 'createdDate', + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) => new Date(row.original.createdDate).toLocaleDateString() + }, + { + id: 'actions', + cell: ({ row }) => { + const dataMembers = row.original; + + return ( + + + + + + Actions + navigator.clipboard.writeText(dataMembers.id.toString())} + > + Copy account ID + + {/* */} + + + ); + } + } +]; diff --git a/src/pages/account/manage/members/ManageMembers.tsx b/src/pages/account/manage/members/ManageMembers.tsx new file mode 100644 index 0000000..3a099a3 --- /dev/null +++ b/src/pages/account/manage/members/ManageMembers.tsx @@ -0,0 +1,42 @@ +import { DataTable } from '@/components/ui/DataTable'; +import { columns, Members } from './Columns'; + +const dataMembers: Members[] = [ + { + id: 37026, + username: 67076807158, + name: 'Jumentino Carlos Luis da Costa', + group: 'REGULER', + email: 'Jumentinocldacoata@gmail.com', + createdDate: new Date('2025-02-21') + }, + { + id: 37027, + username: 67071827345, + name: 'Diego Costa', + group: 'REGULER', + email: 'DiegoCosta@gmail.com', + createdDate: new Date('2025-02-21') + }, + { + id: 37028, + username: 56123764212, + name: 'Luis Da Vista', + group: 'SUPERVISOR', + email: 'LuisdaVista@gmail.com', + createdDate: new Date('2024-01-21') + } +]; + +const ManageMembers = () => { + return ( +
+
+

Manage Members

+ +
+
+ ); +}; + +export default ManageMembers; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index 0ff7067..021c776 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -11,8 +11,9 @@ import ManageUserPage from '@/pages/settings/user/manage-user/ManageUserPage'; import LogActivityPage from '@/pages/settings/user/log-activity/LogActivityPage'; import ManagePositionPage from '@/pages/settings/user/manage-position/ManagePositionPage'; -import ManageAccount from '@/pages/account/manage/ManageAccount'; +import ManageAccount from '@/pages/account/manage/account/ManageAccount'; import ManageGroups from '@/pages/groups/ManageGroups'; +import ManageMembers from '@/pages/account/manage/members/ManageMembers'; const AppRoutingSetup = (): ReactElement => { return ( @@ -22,6 +23,8 @@ const AppRoutingSetup = (): ReactElement => { } /> } /> + } /> + } /> } /> From d55823b7b364e7845eb25c8b0c45dc0e499b1a26 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 24 Feb 2025 10:48:09 +0700 Subject: [PATCH 11/29] feat: add members kyc page --- src/pages/groups/Column.tsx | 3 +- src/pages/members/kyc/Kyc.tsx | 42 +++++ src/pages/members/kyc/blocks/ListToolBar.tsx | 55 +++++++ .../members/kyc/hooks/ManageKycContext.tsx | 145 ++++++++++++++++++ src/pages/members/kyc/hooks/index.ts | 2 + .../members/kyc/hooks/useManageKycContext.tsx | 12 ++ .../manage-members}/Columns.tsx | 0 .../manage-members}/ManageMembers.tsx | 0 src/routing/AppRoutingSetup.tsx | 4 +- 9 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 src/pages/members/kyc/Kyc.tsx create mode 100644 src/pages/members/kyc/blocks/ListToolBar.tsx create mode 100644 src/pages/members/kyc/hooks/ManageKycContext.tsx create mode 100644 src/pages/members/kyc/hooks/index.ts create mode 100644 src/pages/members/kyc/hooks/useManageKycContext.tsx rename src/pages/{account/manage/members => members/manage-members}/Columns.tsx (100%) rename src/pages/{account/manage/members => members/manage-members}/ManageMembers.tsx (100%) diff --git a/src/pages/groups/Column.tsx b/src/pages/groups/Column.tsx index bcd9476..234809a 100644 --- a/src/pages/groups/Column.tsx +++ b/src/pages/groups/Column.tsx @@ -14,7 +14,8 @@ export const columns: ColumnDef[] = [ }, { accessorKey: 'createdDate', - header: 'Created Date' + header: 'Created Date', + cell: ({ row }) => new Date(row.original.createdDate).toLocaleDateString() }, { accessorKey: 'name', diff --git a/src/pages/members/kyc/Kyc.tsx b/src/pages/members/kyc/Kyc.tsx new file mode 100644 index 0000000..50fc1a2 --- /dev/null +++ b/src/pages/members/kyc/Kyc.tsx @@ -0,0 +1,42 @@ +import { DataGridInner, TDataGridProps } from '@/components'; +import { Table } from '@tanstack/react-table'; +import React, { createContext, useContext, useState } from 'react'; +import { ManageKycContextProvider } from './hooks'; + +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; +}; + +const Kyc = () => { + const [loading, setLoading] = useState(false); + + return ( +
+
+

Manage Member KYC

+ +
+ +
+
+
+
+ ); +}; + +export default Kyc; diff --git a/src/pages/members/kyc/blocks/ListToolBar.tsx b/src/pages/members/kyc/blocks/ListToolBar.tsx new file mode 100644 index 0000000..f337df8 --- /dev/null +++ b/src/pages/members/kyc/blocks/ListToolBar.tsx @@ -0,0 +1,55 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { Button } from '@/components/ui/button'; +import { useKycContext } from '../hooks'; + +const ListToolBar = () => { + const { table, reload } = useDataGrid(); + const { handleDetailDialog, handleAddDialog } = useKycContext(); + + return ( +
+
+
+
+ + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export { ListToolBar }; diff --git a/src/pages/members/kyc/hooks/ManageKycContext.tsx b/src/pages/members/kyc/hooks/ManageKycContext.tsx new file mode 100644 index 0000000..2a63fe1 --- /dev/null +++ b/src/pages/members/kyc/hooks/ManageKycContext.tsx @@ -0,0 +1,145 @@ +import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; +import { Toaster } from '@/components/ui/sonner'; +import { apiConfig } from '@/config/api.config'; +import { ColumnDef } from '@tanstack/react-table'; +import { createContext, useCallback, useMemo, useState } from 'react'; +import { ListToolBar } from '../blocks/ListToolBar'; + +interface SelectedUser { + id: string; + name: string; + email: string; + role: string; + description: string; + created_date: Date; +} + +interface ContextProps { + showDetailDialog: boolean; + handleDetailDialog: (show: boolean, selected_user: SelectedUser | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + selectedUser: SelectedUser | null; +} + +const initialProps: ContextProps = { + showDetailDialog: false, + handleDetailDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + selectedUser: null +}; + +const ManageKycContext = createContext(initialProps); +const API_URL = apiConfig.service_dashboard; + +const ManageKycContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showDetailDialog, setShowDetailDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [selectedUser, setSelectedUser] = useState(null); + + const handleDetailDialog = useCallback((show: boolean, selected_user: SelectedUser | null) => { + setSelectedUser(show ? selected_user : null); + setShowDetailDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } + }, + { + accessorFn: (row) => row.created_date, + id: 'created_date', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[350px]' + } + }, + { + accessorFn: (row) => row.description, + id: 'description', + header: ({ column }) => , + enableSorting: true, + meta: { + headerClassName: 'w-[350px]' + } + }, + { + id: 'actions', + enableSorting: false, + header: ({ column }) => , + cell: (data: any) => { + const row = data.row.original; + + return ( + <> + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleDetailDialog] + ); + + return ( + + + + } + layout={{ card: true }} + sorting={[{ id: 'name', desc: false }]} + serverSide={true} + > + {children} + + + ); +}; + +export { ManageKycContextProvider, ManageKycContext }; +export type { SelectedUser }; diff --git a/src/pages/members/kyc/hooks/index.ts b/src/pages/members/kyc/hooks/index.ts new file mode 100644 index 0000000..7e05097 --- /dev/null +++ b/src/pages/members/kyc/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './ManageKycContext'; +export * from './useManageKycContext'; diff --git a/src/pages/members/kyc/hooks/useManageKycContext.tsx b/src/pages/members/kyc/hooks/useManageKycContext.tsx new file mode 100644 index 0000000..1043f87 --- /dev/null +++ b/src/pages/members/kyc/hooks/useManageKycContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageKycContext } from './ManageKycContext'; + +const useKycContext = () => { + const context = useContext(ManageKycContext); + + if (!context) throw new Error('useKycContext must be used within AuthProvider'); + + return context; +}; + +export { useKycContext }; diff --git a/src/pages/account/manage/members/Columns.tsx b/src/pages/members/manage-members/Columns.tsx similarity index 100% rename from src/pages/account/manage/members/Columns.tsx rename to src/pages/members/manage-members/Columns.tsx diff --git a/src/pages/account/manage/members/ManageMembers.tsx b/src/pages/members/manage-members/ManageMembers.tsx similarity index 100% rename from src/pages/account/manage/members/ManageMembers.tsx rename to src/pages/members/manage-members/ManageMembers.tsx diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index 021c776..fb49b36 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -13,7 +13,8 @@ import LogActivityPage from '@/pages/settings/user/log-activity/LogActivityPage' import ManagePositionPage from '@/pages/settings/user/manage-position/ManagePositionPage'; import ManageAccount from '@/pages/account/manage/account/ManageAccount'; import ManageGroups from '@/pages/groups/ManageGroups'; -import ManageMembers from '@/pages/account/manage/members/ManageMembers'; +import ManageMembers from '@/pages/members/manage-members/ManageMembers'; +import Kyc from '@/pages/members/kyc/Kyc'; const AppRoutingSetup = (): ReactElement => { return ( @@ -22,6 +23,7 @@ const AppRoutingSetup = (): ReactElement => { }> } /> } /> + } /> } /> From a0efe6a7fcea2d52c87bd6ecac006e2140eb6e02 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 24 Feb 2025 11:32:08 +0700 Subject: [PATCH 12/29] add route for all menu --- src/pages/access/access-type/AccessType.tsx | 11 ++++++ .../member-credentials/MemberCredential.tsx | 11 ++++++ .../account => manage-account}/Columns.tsx | 0 .../ManageAccount.tsx | 0 .../hooks/ManageAccountContext.tsx | 0 .../manage-currency/ManageCurrency.tsx | 11 ++++++ src/pages/members/kyc/blocks/AddDialog.tsx | 14 +++++++ ...ManageKycContext.tsx => useKycContext.tsx} | 0 src/pages/menu/manage-menu/ManageMenu.tsx | 11 ++++++ src/pages/menu/menu-category/MenuCategory.tsx | 11 ++++++ src/pages/menu/welcome/Welcome.tsx | 11 ++++++ src/pages/message/Inbox.tsx | 11 ++++++ src/pages/notification/ManageNotification.tsx | 11 ++++++ src/pages/transfer/TransferType.tsx | 11 ++++++ src/pages/webservice/ManageWebServices.tsx | 11 ++++++ src/routing/AppRoutingSetup.tsx | 37 ++++++++++++++++--- 16 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 src/pages/access/access-type/AccessType.tsx create mode 100644 src/pages/access/member-credentials/MemberCredential.tsx rename src/pages/account/{manage/account => manage-account}/Columns.tsx (100%) rename src/pages/account/{manage/account => manage-account}/ManageAccount.tsx (100%) rename src/pages/account/{manage/account => manage-account}/hooks/ManageAccountContext.tsx (100%) create mode 100644 src/pages/account/manage-currency/ManageCurrency.tsx create mode 100644 src/pages/members/kyc/blocks/AddDialog.tsx rename src/pages/members/kyc/hooks/{useManageKycContext.tsx => useKycContext.tsx} (100%) create mode 100644 src/pages/menu/manage-menu/ManageMenu.tsx create mode 100644 src/pages/menu/menu-category/MenuCategory.tsx create mode 100644 src/pages/menu/welcome/Welcome.tsx create mode 100644 src/pages/message/Inbox.tsx create mode 100644 src/pages/notification/ManageNotification.tsx create mode 100644 src/pages/transfer/TransferType.tsx create mode 100644 src/pages/webservice/ManageWebServices.tsx diff --git a/src/pages/access/access-type/AccessType.tsx b/src/pages/access/access-type/AccessType.tsx new file mode 100644 index 0000000..185c37f --- /dev/null +++ b/src/pages/access/access-type/AccessType.tsx @@ -0,0 +1,11 @@ +const AccessType = () => { + return ( +
+
+

Access Type

+
+
+ ); +}; + +export default AccessType; diff --git a/src/pages/access/member-credentials/MemberCredential.tsx b/src/pages/access/member-credentials/MemberCredential.tsx new file mode 100644 index 0000000..49509f9 --- /dev/null +++ b/src/pages/access/member-credentials/MemberCredential.tsx @@ -0,0 +1,11 @@ +const MemberCredential = () => { + return ( +
+
+

Member Credential

+
+
+ ); +}; + +export default MemberCredential; diff --git a/src/pages/account/manage/account/Columns.tsx b/src/pages/account/manage-account/Columns.tsx similarity index 100% rename from src/pages/account/manage/account/Columns.tsx rename to src/pages/account/manage-account/Columns.tsx diff --git a/src/pages/account/manage/account/ManageAccount.tsx b/src/pages/account/manage-account/ManageAccount.tsx similarity index 100% rename from src/pages/account/manage/account/ManageAccount.tsx rename to src/pages/account/manage-account/ManageAccount.tsx diff --git a/src/pages/account/manage/account/hooks/ManageAccountContext.tsx b/src/pages/account/manage-account/hooks/ManageAccountContext.tsx similarity index 100% rename from src/pages/account/manage/account/hooks/ManageAccountContext.tsx rename to src/pages/account/manage-account/hooks/ManageAccountContext.tsx diff --git a/src/pages/account/manage-currency/ManageCurrency.tsx b/src/pages/account/manage-currency/ManageCurrency.tsx new file mode 100644 index 0000000..98668f5 --- /dev/null +++ b/src/pages/account/manage-currency/ManageCurrency.tsx @@ -0,0 +1,11 @@ +const ManageCurrency = () => { + return ( +
+
+

Manage Currency

+
+
+ ); +}; + +export default ManageCurrency; diff --git a/src/pages/members/kyc/blocks/AddDialog.tsx b/src/pages/members/kyc/blocks/AddDialog.tsx new file mode 100644 index 0000000..68b4d58 --- /dev/null +++ b/src/pages/members/kyc/blocks/AddDialog.tsx @@ -0,0 +1,14 @@ +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/hooks/useManageKycContext.tsx b/src/pages/members/kyc/hooks/useKycContext.tsx similarity index 100% rename from src/pages/members/kyc/hooks/useManageKycContext.tsx rename to src/pages/members/kyc/hooks/useKycContext.tsx diff --git a/src/pages/menu/manage-menu/ManageMenu.tsx b/src/pages/menu/manage-menu/ManageMenu.tsx new file mode 100644 index 0000000..e9febec --- /dev/null +++ b/src/pages/menu/manage-menu/ManageMenu.tsx @@ -0,0 +1,11 @@ +const ManageMenu = () => { + return ( +
+
+

Manage Menu

+
+
+ ); +}; + +export default ManageMenu; diff --git a/src/pages/menu/menu-category/MenuCategory.tsx b/src/pages/menu/menu-category/MenuCategory.tsx new file mode 100644 index 0000000..a43e69f --- /dev/null +++ b/src/pages/menu/menu-category/MenuCategory.tsx @@ -0,0 +1,11 @@ +const MenuCategory = () => { + return ( +
+
+

Menu Category

+
+
+ ); +}; + +export default MenuCategory; diff --git a/src/pages/menu/welcome/Welcome.tsx b/src/pages/menu/welcome/Welcome.tsx new file mode 100644 index 0000000..6446120 --- /dev/null +++ b/src/pages/menu/welcome/Welcome.tsx @@ -0,0 +1,11 @@ +const Welcome = () => { + return ( +
+
+

Welcome

+
+
+ ); +}; + +export default Welcome; diff --git a/src/pages/message/Inbox.tsx b/src/pages/message/Inbox.tsx new file mode 100644 index 0000000..c3d9f4c --- /dev/null +++ b/src/pages/message/Inbox.tsx @@ -0,0 +1,11 @@ +const Inbox = () => { + return ( +
+
+

Inbox

+
+
+ ); +}; + +export default Inbox; diff --git a/src/pages/notification/ManageNotification.tsx b/src/pages/notification/ManageNotification.tsx new file mode 100644 index 0000000..58f154e --- /dev/null +++ b/src/pages/notification/ManageNotification.tsx @@ -0,0 +1,11 @@ +const ManageNotification = () => { + return ( +
+
+

Manage Notification

+
+
+ ); +}; + +export default ManageNotification; diff --git a/src/pages/transfer/TransferType.tsx b/src/pages/transfer/TransferType.tsx new file mode 100644 index 0000000..b81bc75 --- /dev/null +++ b/src/pages/transfer/TransferType.tsx @@ -0,0 +1,11 @@ +const TransferType = () => { + return ( +
+
+

Transfer Type

+
+
+ ); +}; + +export default TransferType; diff --git a/src/pages/webservice/ManageWebServices.tsx b/src/pages/webservice/ManageWebServices.tsx new file mode 100644 index 0000000..c85ecca --- /dev/null +++ b/src/pages/webservice/ManageWebServices.tsx @@ -0,0 +1,11 @@ +const ManageWebServices = () => { + return ( +
+
+

Manage Web Services

+
+
+ ); +}; + +export default ManageWebServices; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index fb49b36..1cfe6fc 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -11,10 +11,20 @@ import ManageUserPage from '@/pages/settings/user/manage-user/ManageUserPage'; import LogActivityPage from '@/pages/settings/user/log-activity/LogActivityPage'; import ManagePositionPage from '@/pages/settings/user/manage-position/ManagePositionPage'; -import ManageAccount from '@/pages/account/manage/account/ManageAccount'; +import ManageAccount from '@/pages/account/manage-account/ManageAccount'; import ManageGroups from '@/pages/groups/ManageGroups'; import ManageMembers from '@/pages/members/manage-members/ManageMembers'; import Kyc from '@/pages/members/kyc/Kyc'; +import AccessType from '@/pages/access/access-type/AccessType'; +import MemberCredential from '@/pages/access/member-credentials/MemberCredential'; +import ManageCurrency from '@/pages/account/manage-currency/ManageCurrency'; +import TransferType from '@/pages/transfer/TransferType'; +import ManageNotification from '@/pages/notification/ManageNotification'; +import MenuCategory from '@/pages/menu/menu-category/MenuCategory'; +import ManageMenu from '@/pages/menu/manage-menu/ManageMenu'; +import Welcome from '@/pages/menu/welcome/Welcome'; +import Inbox from '@/pages/message/Inbox'; +import ManageWebServices from '@/pages/webservice/ManageWebServices'; const AppRoutingSetup = (): ReactElement => { return ( @@ -22,12 +32,30 @@ const AppRoutingSetup = (): ReactElement => { }> }> } /> - } /> - } /> + } /> + } /> + + } /> } /> - } /> + } /> + } /> + + } /> + } /> + + } /> + + } /> + + } /> + } /> + } /> + + } /> + + } /> } /> } /> @@ -35,7 +63,6 @@ const AppRoutingSetup = (): ReactElement => { path="/settings/user-management/manage-position" element={} /> - } /> } /> From b4fd2791e8a2823c09528a6e93a9acc36eb33d77 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 24 Feb 2025 11:32:57 +0700 Subject: [PATCH 13/29] remove add data button on table kyc --- src/pages/members/kyc/blocks/ListToolBar.tsx | 7 ------- src/pages/members/kyc/hooks/index.ts | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/pages/members/kyc/blocks/ListToolBar.tsx b/src/pages/members/kyc/blocks/ListToolBar.tsx index f337df8..8d99350 100644 --- a/src/pages/members/kyc/blocks/ListToolBar.tsx +++ b/src/pages/members/kyc/blocks/ListToolBar.tsx @@ -33,13 +33,6 @@ const ListToolBar = () => {
- + +
+
+ +
+ + + + ); +}; + +export default AddDialog; diff --git a/src/pages/access/access-type/blocks/ListToolBar.tsx b/src/pages/access/access-type/blocks/ListToolBar.tsx new file mode 100644 index 0000000..b99d8e1 --- /dev/null +++ b/src/pages/access/access-type/blocks/ListToolBar.tsx @@ -0,0 +1,49 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useManageAccessTypeContext } from '../hooks/useManageAccessTypeContext'; +import { Button } from '@/components/ui/button'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog, handleEditDialog } = useManageAccessTypeContext(); + + return ( +
+
+
+
+ + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/access/access-type/hooks/ManageAccessTypeContext.tsx b/src/pages/access/access-type/hooks/ManageAccessTypeContext.tsx new file mode 100644 index 0000000..1cf9649 --- /dev/null +++ b/src/pages/access/access-type/hooks/ManageAccessTypeContext.tsx @@ -0,0 +1,178 @@ +import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { Toaster } from '@/components/ui/sonner'; +import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { ColumnDef } from '@tanstack/react-table'; +import { createContext, useCallback, useEffect, useMemo, useState } from 'react'; +import ListToolbar from '../blocks/ListToolBar'; + +interface SelectedUser { + id: string; + name: string; + internal_name: string; + description: string; +} + +interface AccountProps { + id: string; + name: string; +} + +const accounts: string[] = [ + 'eMoney Account', + 'Topup Account', + 'Merchant Account', + 'Deposit Account', + 'Cash out/in' +]; + +interface ContextProps { + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_user: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + selectedUser: string | null; + accounts: AccountProps[]; +} + +const initialProps: ContextProps = { + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + selectedUser: null, + accounts: [] +}; + +const ManageAccessTypeContext = createContext(initialProps); +const API_URL = apiConfig.service_dashboard; + +const ManageAccessTypeContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [selectedUser, setSelectedUser] = useState(null); + const [accounts, setAccount] = useState([]); + const { GetData } = useCallApi(); + + useEffect(() => { + setAccount([ + { id: '1', name: 'eMoney Account' }, + { id: '2', name: 'Topup Account' }, + { id: '3', name: 'Merchant Account' }, + { id: '4', name: 'Deposit Account' }, + { id: '5', name: 'Cash in/out Account' } + ]); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_user: string | null) => { + setSelectedUser(show ? selected_user : null); + setShowEditDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } + }, + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.internal_name, + id: 'internal_name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.description, + id: 'description', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + id: 'actions', + enableSorting: false, + header: ({ column }) => , + cell: ({ row }) => { + return ( + <> + + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleAddDialog, handleEditDialog] + ); + + return ( +
+
+

Manage Access Type

+
+ + + } + sorting={[{ id: 'id', desc: true }]} + serverSide={true} + > + {children} + + +
+ ); +}; + +export { ManageAccessTypeContext, ManageAccessTypeContextProvider }; +export type { SelectedUser }; diff --git a/src/pages/access/access-type/hooks/useManageAccessTypeContext.tsx b/src/pages/access/access-type/hooks/useManageAccessTypeContext.tsx new file mode 100644 index 0000000..2113167 --- /dev/null +++ b/src/pages/access/access-type/hooks/useManageAccessTypeContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageAccessTypeContext } from './ManageAccessTypeContext'; + +const useManageAccessTypeContext = () => { + const context = useContext(ManageAccessTypeContext); + + if (!context) throw new Error('useManageAccessTypeContext must be used within AuthProvider'); + + return context; +}; + +export { useManageAccessTypeContext }; diff --git a/src/pages/settings/user/manage-user/blocks/AddDialog.tsx b/src/pages/settings/user/manage-user/blocks/AddDialog.tsx index 2b4ee68..a7647cc 100644 --- a/src/pages/settings/user/manage-user/blocks/AddDialog.tsx +++ b/src/pages/settings/user/manage-user/blocks/AddDialog.tsx @@ -336,6 +336,7 @@ const AddDialog = () => { +
+
+ + ); +}; + +export default MemberCredentialsForm; diff --git a/src/pages/access/member-credentials/hooks/index.ts b/src/pages/access/member-credentials/hooks/index.ts new file mode 100644 index 0000000..e3b3fc4 --- /dev/null +++ b/src/pages/access/member-credentials/hooks/index.ts @@ -0,0 +1 @@ +export * from './useMemberCredentials'; diff --git a/src/pages/access/member-credentials/hooks/useMemberCredentials.tsx b/src/pages/access/member-credentials/hooks/useMemberCredentials.tsx new file mode 100644 index 0000000..4cfd302 --- /dev/null +++ b/src/pages/access/member-credentials/hooks/useMemberCredentials.tsx @@ -0,0 +1,42 @@ +import { useState } from 'react'; + +type AccessType = 'Pin Credentials' | 'Secret Auth' | 'APIKey' | 'Web Credentials' | 'OTM Tpay'; + +interface MemberCredentials { + accessType: AccessType | null; + username: string; + credential: string; + confirmCredential: string; +} + +export const useMemberCredentials = () => { + const [memberCredentials, setMemberCredentials] = useState({ + accessType: null, + username: '', + credential: '', + confirmCredential: '' + }); + const [error, setError] = useState(null); + + const handleChange = (key: keyof MemberCredentials, value: string) => { + setMemberCredentials((prevCredentials) => ({ ...prevCredentials, [key]: value })); + }; + + const handleSubmit = () => { + setError(null); + + if (memberCredentials.username === '' || memberCredentials.credential === '') { + setError('Please fill in all fields'); + return; + } + + if (memberCredentials.credential !== memberCredentials.confirmCredential) { + setError('Credentials do not match'); + return; + } + + console.log('Data Submitted: ', memberCredentials); + }; + + return { memberCredentials, handleChange, handleSubmit, error }; +}; From b45fa2daafa84faa915b1579d3f2f6fb4c3fd127 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 25 Feb 2025 10:32:57 +0700 Subject: [PATCH 16/29] add the Manage Transfer Type page and handle the create transfer type form --- src/pages/transfer/TransferType.tsx | 20 +- src/pages/transfer/blocks/AddDialog.tsx | 294 ++++++++++++++++++ src/pages/transfer/blocks/ListToolBar.tsx | 49 +++ .../hooks/ManageTransferTypeContext.tsx | 178 +++++++++++ .../hooks/useManageTransferTypeContext.tsx | 12 + src/routing/AppRoutingSetup.tsx | 4 +- 6 files changed, 550 insertions(+), 7 deletions(-) create mode 100644 src/pages/transfer/blocks/AddDialog.tsx create mode 100644 src/pages/transfer/blocks/ListToolBar.tsx create mode 100644 src/pages/transfer/hooks/ManageTransferTypeContext.tsx create mode 100644 src/pages/transfer/hooks/useManageTransferTypeContext.tsx diff --git a/src/pages/transfer/TransferType.tsx b/src/pages/transfer/TransferType.tsx index b81bc75..2e5d03e 100644 --- a/src/pages/transfer/TransferType.tsx +++ b/src/pages/transfer/TransferType.tsx @@ -1,10 +1,20 @@ +import { Container, DataGridInner } from '@/components'; +import { + ManageTransferTypeContext, + ManageTransferTypeContextProvider +} from './hooks/ManageTransferTypeContext'; +import AddDialog from './blocks/AddDialog'; + const TransferType = () => { return ( -
-
-

Transfer Type

-
-
+ + +
+ +
+ +
+
); }; diff --git a/src/pages/transfer/blocks/AddDialog.tsx b/src/pages/transfer/blocks/AddDialog.tsx new file mode 100644 index 0000000..300425e --- /dev/null +++ b/src/pages/transfer/blocks/AddDialog.tsx @@ -0,0 +1,294 @@ +import { apiConfig } from '@/config/api.config'; +import { useRef, useState } from 'react'; +import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; +import { Alert, KeenIcon, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { Button } from '@/components/ui/button'; + +interface CreateTransferTypeParams { + transfer_type_name: string; + description: string; + from_account: string; + to_account: string; + minimal_amount: number; + maximum_amount: number; + otp_threshold: number; + maximum_transaction_perDay: number; +} + +const API_URL = apiConfig.service_dashboard; + +const AddDialog = () => { + const parentRef = useRef(null); + const { showAddDialog, handleAddDialog, accounts } = useManageTransferTypeContext(); + const { reload } = useDataGrid(); + const { PostData, PutData } = useCallApi(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const initialState = { + transfer_type_name: '', + description: '', + from_account: '', + to_account: '', + minimal_amount: 0, + maximum_amount: 0, + otp_threshold: 0, + maximum_transaction_perDay: 0 + }; + + const [formField, setFormField] = useState(initialState); + const resetForm = () => { + setFormField(initialState); + }; + const [isSubmitting, setIsSubmitting] = useState(false); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + // setIsSubmitting(true); + const payload = { + transfer_type_name: formField.transfer_type_name, + description: formField.description, + from_account: formField.from_account, + to_account: formField.to_account, + minimal_amount: formField.minimal_amount, + maximum_amount: formField.maximum_amount, + otp_threshold: formField.otp_threshold, + maximum_transaction_perDay: formField.maximum_transaction_perDay + }; + console.log(payload); + }; + + return ( + handleAddDialog(open)}> + + +
+
+

+ Create Transfer Type +

+
+
+
{ + handleAddDialog(false); + resetForm(); + }} + > + +
+
+
+ +
+ {alert.show && ( + +

{alert.message}

+
+ )} +
+
+
+
+ + + setFormField((prev) => ({ ...prev, transfer_type_name: target.value })) + } + /> +
+
+ +
+
+ + + setFormField((prev) => ({ ...prev, description: target.value })) + } + /> +
+
+ +
+
+ + +
+ +
+
+
+ +
+
+ + +
+ +
+
+
+ +
+
+ + + setFormField((prev) => ({ + ...prev, + minimal_amount: Number(target.value) + })) + } + /> +
+
+ +
+
+ + + setFormField((prev) => ({ + ...prev, + maximum_amount: Number(target.value) + })) + } + /> +
+
+ +
+
+ + + setFormField((prev) => ({ + ...prev, + otp_threshold: Number(target.value) + })) + } + /> +
+
+ +
+
+ + + setFormField((prev) => ({ + ...prev, + maximum_transaction_perDay: Number(target.value) + })) + } + /> +
+
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/transfer/blocks/ListToolBar.tsx b/src/pages/transfer/blocks/ListToolBar.tsx new file mode 100644 index 0000000..a3af2c3 --- /dev/null +++ b/src/pages/transfer/blocks/ListToolBar.tsx @@ -0,0 +1,49 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; +import { Button } from '@/components/ui/button'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog, handleEditDialog } = useManageTransferTypeContext(); + + return ( +
+
+
+
+ + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/transfer/hooks/ManageTransferTypeContext.tsx b/src/pages/transfer/hooks/ManageTransferTypeContext.tsx new file mode 100644 index 0000000..5a3d5d3 --- /dev/null +++ b/src/pages/transfer/hooks/ManageTransferTypeContext.tsx @@ -0,0 +1,178 @@ +import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { Toaster } from '@/components/ui/sonner'; +import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { ColumnDef } from '@tanstack/react-table'; +import { createContext, useCallback, useEffect, useMemo, useState } from 'react'; +import ListToolbar from '../blocks/ListToolBar'; + +interface SelectedUser { + id: string; + name: string; + internal_name: string; + description: string; +} + +interface AccountProps { + id: string; + name: string; +} + +const accounts: string[] = [ + 'eMoney Account', + 'Topup Account', + 'Merchant Account', + 'Deposit Account', + 'Cash out/in' +]; + +interface ContextProps { + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_user: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + selectedUser: string | null; + accounts: AccountProps[]; +} + +const initialProps: ContextProps = { + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + selectedUser: null, + accounts: [] +}; + +const ManageTransferTypeContext = createContext(initialProps); +const API_URL = apiConfig.service_dashboard; + +const ManageTransferTypeContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [selectedUser, setSelectedUser] = useState(null); + const [accounts, setAccount] = useState([]); + const { GetData } = useCallApi(); + + useEffect(() => { + setAccount([ + { id: '1', name: 'eMoney Account' }, + { id: '2', name: 'Topup Account' }, + { id: '3', name: 'Merchant Account' }, + { id: '4', name: 'Deposit Account' }, + { id: '5', name: 'Cash in/out Account' } + ]); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_user: string | null) => { + setSelectedUser(show ? selected_user : null); + setShowEditDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } + }, + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.internal_name, + id: 'internal_name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.description, + id: 'description', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + id: 'actions', + enableSorting: false, + header: ({ column }) => , + cell: ({ row }) => { + return ( + <> + + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleAddDialog, handleEditDialog] + ); + + return ( +
+
+

Manage Access Type

+
+ + + } + sorting={[{ id: 'id', desc: true }]} + serverSide={true} + > + {children} + + +
+ ); +}; + +export { ManageTransferTypeContext, ManageTransferTypeContextProvider }; +export type { SelectedUser }; diff --git a/src/pages/transfer/hooks/useManageTransferTypeContext.tsx b/src/pages/transfer/hooks/useManageTransferTypeContext.tsx new file mode 100644 index 0000000..b726a7c --- /dev/null +++ b/src/pages/transfer/hooks/useManageTransferTypeContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageTransferTypeContext } from './ManageTransferTypeContext'; + +const useManageTransferTypeContext = () => { + const context = useContext(ManageTransferTypeContext); + + if (!context) throw new Error('useManageAccessTypeContext must be used within AuthProvider'); + + return context; +}; + +export { useManageTransferTypeContext }; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index 1cfe6fc..707b9b1 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -16,15 +16,15 @@ import ManageGroups from '@/pages/groups/ManageGroups'; import ManageMembers from '@/pages/members/manage-members/ManageMembers'; import Kyc from '@/pages/members/kyc/Kyc'; import AccessType from '@/pages/access/access-type/AccessType'; -import MemberCredential from '@/pages/access/member-credentials/MemberCredential'; +import MemberCredential from '@/pages/access/member-credentials/MemberCredentials'; import ManageCurrency from '@/pages/account/manage-currency/ManageCurrency'; -import TransferType from '@/pages/transfer/TransferType'; import ManageNotification from '@/pages/notification/ManageNotification'; import MenuCategory from '@/pages/menu/menu-category/MenuCategory'; import ManageMenu from '@/pages/menu/manage-menu/ManageMenu'; import Welcome from '@/pages/menu/welcome/Welcome'; import Inbox from '@/pages/message/Inbox'; import ManageWebServices from '@/pages/webservice/ManageWebServices'; +import TransferType from '@/pages/transfer/TransferType'; const AppRoutingSetup = (): ReactElement => { return ( From aee720312511d3049fd41e3507252ac30b98693e Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 25 Feb 2025 10:41:33 +0700 Subject: [PATCH 17/29] refactor: form access type --- .../access/access-type/blocks/AddDialog.tsx | 173 ++---------------- .../hooks/ManageAccessTypeContext.tsx | 30 +-- 2 files changed, 24 insertions(+), 179 deletions(-) diff --git a/src/pages/access/access-type/blocks/AddDialog.tsx b/src/pages/access/access-type/blocks/AddDialog.tsx index 19189e0..eaa6d16 100644 --- a/src/pages/access/access-type/blocks/AddDialog.tsx +++ b/src/pages/access/access-type/blocks/AddDialog.tsx @@ -21,22 +21,11 @@ import { } from '@/components/ui/select'; import { Button } from '@/components/ui/button'; -interface CreateTransferTypeParams { - transfer_type_name: string; - description: string; - from_account: string; - to_account: string; - minimal_amount: number; - maximum_amount: number; - otp_threshold: number; - maximum_transaction_perDay: number; -} - const API_URL = apiConfig.service_dashboard; const AddDialog = () => { const parentRef = useRef(null); - const { showAddDialog, handleAddDialog, accounts } = useManageAccessTypeContext(); + const { showAddDialog, handleAddDialog, accessTypes } = useManageAccessTypeContext(); const { reload } = useDataGrid(); const { PostData, PutData } = useCallApi(); const [alert, setAlert] = useState({ @@ -45,14 +34,9 @@ const AddDialog = () => { }); const initialState = { - transfer_type_name: '', + name: '', description: '', - from_account: '', - to_account: '', - minimal_amount: 0, - maximum_amount: 0, - otp_threshold: 0, - maximum_transaction_perDay: 0 + internal_name: '' }; const [formField, setFormField] = useState(initialState); @@ -64,17 +48,11 @@ const AddDialog = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // setIsSubmitting(true); - const payload = { - transfer_type_name: formField.transfer_type_name, - description: formField.description, - from_account: formField.from_account, - to_account: formField.to_account, - minimal_amount: formField.minimal_amount, - maximum_amount: formField.maximum_amount, - otp_threshold: formField.otp_threshold, - maximum_transaction_perDay: formField.maximum_transaction_perDay - }; - console.log(payload); + console.log(formField); + }; + + const handleReset = () => { + setFormField(initialState); }; return ( @@ -84,7 +62,7 @@ const AddDialog = () => {

- Create Transfer Type + Create Access Type

@@ -110,16 +88,14 @@ const AddDialog = () => {
- + - setFormField((prev) => ({ ...prev, transfer_type_name: target.value })) + setFormField((prev) => ({ ...prev, name: target.value })) } />
@@ -142,140 +118,25 @@ const AddDialog = () => {
-
-
- - -
- -
-
-
- -
-
- - -
- -
-
-
-
- setFormField((prev) => ({ - ...prev, - minimal_amount: Number(target.value) - })) - } - /> -
-
- -
-
- - - setFormField((prev) => ({ - ...prev, - maximum_amount: Number(target.value) - })) - } - /> -
-
- -
-
- - - setFormField((prev) => ({ - ...prev, - otp_threshold: Number(target.value) - })) - } - /> -
-
- -
-
- - - setFormField((prev) => ({ - ...prev, - maximum_transaction_perDay: Number(target.value) - })) + setFormField((prev) => ({ ...prev, internal_name: target.value })) } />
- + +
+
+ + + + + + ); +}; + +export default AddDialog; diff --git a/src/pages/account/manage-currency/blocks/ListToolBar.tsx b/src/pages/account/manage-currency/blocks/ListToolBar.tsx new file mode 100644 index 0000000..aa01dbb --- /dev/null +++ b/src/pages/account/manage-currency/blocks/ListToolBar.tsx @@ -0,0 +1,49 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useManageCurrencyContext } from '../hooks/useManageAccessTypeContext'; +import { Button } from '@/components/ui/button'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog, handleEditDialog } = useManageCurrencyContext(); + + return ( +
+
+
+
+ + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/account/manage-currency/hooks/ManageCurrencyContext.tsx b/src/pages/account/manage-currency/hooks/ManageCurrencyContext.tsx new file mode 100644 index 0000000..e4bb43b --- /dev/null +++ b/src/pages/account/manage-currency/hooks/ManageCurrencyContext.tsx @@ -0,0 +1,207 @@ +import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { Toaster } from '@/components/ui/sonner'; +import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { ColumnDef } from '@tanstack/react-table'; +import { createContext, useCallback, useMemo, useState } from 'react'; +import ListToolbar from '../blocks/ListToolBar'; + +interface SelectedUser { + id: string; + name: string; + code: string; + prefix: string; + trailer: string; + format: string; + grouping_separator: string; + decimal_separator: string; +} + +interface CurrencyProps { + id: string; + name: string; + code: string; + prefix: string; + trailer: string; + format: string; + grouping_separator: string; + decimal_separator: string; +} + +interface ContextProps { + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_user: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + selectedUser: string | null; + currencies: CurrencyProps[]; +} + +const initialProps: ContextProps = { + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + selectedUser: null, + currencies: [] +}; + +const ManageCurrencyContext = createContext(initialProps); +const API_URL = apiConfig.service_dashboard; + +const ManageCurrencyContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [selectedUser, setSelectedUser] = useState(null); + const [currencies, setCurrencies] = useState([]); + const { GetData } = useCallApi(); + + const handleEditDialog = useCallback((show: boolean, selected_user: string | null) => { + setSelectedUser(show ? selected_user : null); + setShowEditDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } + }, + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.code, + id: 'code', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.prefix, + id: 'prefix', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.Trailer, + id: 'trailer', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.format, + id: 'format', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.grouping_separator, + id: 'grouping_separator', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.decimal_separator, + id: 'decimal_separator', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + id: 'actions', + enableSorting: false, + header: ({ column }) => , + cell: ({ row }) => { + return ( + <> + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleAddDialog, handleEditDialog] + ); + + return ( +
+
+

Manage Access Type

+
+ + + } + sorting={[{ id: 'id', desc: true }]} + serverSide={true} + > + {children} + + +
+ ); +}; + +export { ManageCurrencyContext, ManageCurrencyContextProvider }; +export type { SelectedUser }; diff --git a/src/pages/account/manage-currency/hooks/useManageAccessTypeContext.tsx b/src/pages/account/manage-currency/hooks/useManageAccessTypeContext.tsx new file mode 100644 index 0000000..d1f682c --- /dev/null +++ b/src/pages/account/manage-currency/hooks/useManageAccessTypeContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageCurrencyContext } from './ManageCurrencyContext'; + +const useManageCurrencyContext = () => { + const context = useContext(ManageCurrencyContext); + + if (!context) throw new Error('useManageCurrencyContext must be used within AuthProvider'); + + return context; +}; + +export { useManageCurrencyContext }; From 754c67a6d219418ec1f5bd97a1067198b0ac5ad5 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 25 Feb 2025 13:42:37 +0700 Subject: [PATCH 20/29] update data currency --- .../manage-currency/blocks/ListToolBar.tsx | 2 +- .../hooks/ManageCurrencyContext.tsx | 80 +++++++++++++++---- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/pages/account/manage-currency/blocks/ListToolBar.tsx b/src/pages/account/manage-currency/blocks/ListToolBar.tsx index aa01dbb..53af0d6 100644 --- a/src/pages/account/manage-currency/blocks/ListToolBar.tsx +++ b/src/pages/account/manage-currency/blocks/ListToolBar.tsx @@ -15,7 +15,7 @@ const ListToolbar = () => { table.getColumn('name')?.setFilterValue(event.target.value)} /> diff --git a/src/pages/account/manage-currency/hooks/ManageCurrencyContext.tsx b/src/pages/account/manage-currency/hooks/ManageCurrencyContext.tsx index e4bb43b..c5cd102 100644 --- a/src/pages/account/manage-currency/hooks/ManageCurrencyContext.tsx +++ b/src/pages/account/manage-currency/hooks/ManageCurrencyContext.tsx @@ -3,7 +3,7 @@ import { Toaster } from '@/components/ui/sonner'; import { apiConfig } from '@/config/api.config'; import { useCallApi } from '@/hooks'; import { ColumnDef } from '@tanstack/react-table'; -import { createContext, useCallback, useMemo, useState } from 'react'; +import { createContext, useCallback, useEffect, useMemo, useState } from 'react'; import ListToolbar from '../blocks/ListToolBar'; interface SelectedUser { @@ -56,6 +56,52 @@ const ManageCurrencyContextProvider = ({ children }: { children: React.ReactNode const [currencies, setCurrencies] = useState([]); const { GetData } = useCallApi(); + useEffect(() => { + const dummyData: CurrencyProps[] = [ + { + id: '1', + name: 'US Dollar', + code: 'USD', + prefix: '$', + trailer: '', + format: '#,##0.00', + grouping_separator: ',', + decimal_separator: '.' + }, + { + id: '2', + name: 'Euro', + code: 'EUR', + prefix: '€', + trailer: '', + format: '#.##0,00', + grouping_separator: '.', + decimal_separator: ',' + }, + { + id: '3', + name: 'Japanese Yen', + code: 'JPY', + prefix: '¥', + trailer: '', + format: '#,##0', + grouping_separator: ',', + decimal_separator: '.' + }, + { + id: '4', + name: 'Indonesia Rupiah', + code: 'IDR', + prefix: 'Rp', + trailer: '', + format: '#,##0', + grouping_separator: '.', + decimal_separator: ',' + } + ]; + setCurrencies(dummyData); + }, []); + const handleEditDialog = useCallback((show: boolean, selected_user: string | null) => { setSelectedUser(show ? selected_user : null); setShowEditDialog(show); @@ -108,7 +154,7 @@ const ManageCurrencyContextProvider = ({ children }: { children: React.ReactNode } }, { - accessorFn: (row) => row.Trailer, + accessorFn: (row) => row.trailer, id: 'trailer', header: ({ column }) => , enableSorting: true, @@ -171,11 +217,11 @@ const ManageCurrencyContextProvider = ({ children }: { children: React.ReactNode ], [handleAddDialog, handleEditDialog] ); - + console.log(currencies); return (
-

Manage Access Type

+

Manage Currency

- } - sorting={[{ id: 'id', desc: true }]} - serverSide={true} - > - {children} - + + {currencies.length > 0 ? ( + } + sorting={[{ id: 'id', desc: true }]} + serverSide={true} + > + {children} + + ) : ( +

loading

+ )}
); From 5c6feb8ab5538efd366b3b9135f9f54bb8aceccb Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 25 Feb 2025 14:27:54 +0700 Subject: [PATCH 21/29] add the Manage Notifications page and handle the create notification form --- src/pages/notification/ManageNotification.tsx | 17 +- src/pages/notification/blocks/AddDialog.tsx | 147 ++++++++++++++++++ src/pages/notification/blocks/ListToolbar.tsx | 57 +++++++ .../hooks/ManageNotificationContext.tsx | 142 +++++++++++++++++ .../hooks/useManageNotificationContext.tsx | 12 ++ 5 files changed, 370 insertions(+), 5 deletions(-) create mode 100644 src/pages/notification/blocks/AddDialog.tsx create mode 100644 src/pages/notification/blocks/ListToolbar.tsx create mode 100644 src/pages/notification/hooks/ManageNotificationContext.tsx create mode 100644 src/pages/notification/hooks/useManageNotificationContext.tsx diff --git a/src/pages/notification/ManageNotification.tsx b/src/pages/notification/ManageNotification.tsx index 58f154e..3f26388 100644 --- a/src/pages/notification/ManageNotification.tsx +++ b/src/pages/notification/ManageNotification.tsx @@ -1,10 +1,17 @@ +import { Container, DataGridInner } from '@/components'; +import { ManageNotifContextProvider } from './hooks/ManageNotificationContext'; +import AddDialog from './blocks/AddDialog'; + const ManageNotification = () => { return ( -
-
-

Manage Notification

-
-
+ + +
+ +
+ +
+
); }; diff --git a/src/pages/notification/blocks/AddDialog.tsx b/src/pages/notification/blocks/AddDialog.tsx new file mode 100644 index 0000000..9daebf8 --- /dev/null +++ b/src/pages/notification/blocks/AddDialog.tsx @@ -0,0 +1,147 @@ +import { apiConfig } from '@/config/api.config'; +import { useRef, useState } from 'react'; +import { Alert, KeenIcon, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import { useManageNotificationContext } from '../hooks/useManageNotificationContext'; + +const API_URL = apiConfig.service_dashboard; + +const AddDialog = () => { + const parentRef = useRef(null); + const { + handleAddDialog, + handleEditDialog, + showAddDialog, + showEditDialog, + selectedNotification, + notifications + } = useManageNotificationContext(); + + const { reload } = useDataGrid(); + const { PostData, PutData } = useCallApi(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const initialState = { + name: '', + destination_module: '' + }; + + const [formField, setFormField] = useState(initialState); + const resetForm = () => { + setFormField(initialState); + }; + const [isSubmitting, setIsSubmitting] = useState(false); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '' || formField.destination_module === '') { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + const handleReset = () => { + setFormField(initialState); + }; + + return ( + handleAddDialog(open)}> + + + + +
+
+

+ Create Notification +

+
+
+
{ + handleAddDialog(false); + resetForm(); + }} + > + +
+
+
+ +
+ {alert.show && ( + + {alert.message} + + )} +
+
+
+
+ + + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> +
+
+ +
+
+ + + setFormField((prev) => ({ ...prev, destination_module: target.value })) + } + /> +
+
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/notification/blocks/ListToolbar.tsx b/src/pages/notification/blocks/ListToolbar.tsx new file mode 100644 index 0000000..aa88983 --- /dev/null +++ b/src/pages/notification/blocks/ListToolbar.tsx @@ -0,0 +1,57 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useManageNotificationContext } from '../hooks/useManageNotificationContext'; +import { Button } from '@/components/ui/button'; + +const ListToolBar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog } = useManageNotificationContext(); + + return ( +
+
+
+
+ + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export { ListToolBar }; diff --git a/src/pages/notification/hooks/ManageNotificationContext.tsx b/src/pages/notification/hooks/ManageNotificationContext.tsx new file mode 100644 index 0000000..238922f --- /dev/null +++ b/src/pages/notification/hooks/ManageNotificationContext.tsx @@ -0,0 +1,142 @@ +import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { Toaster } from '@/components/ui/sonner'; +import { apiConfig } from '@/config/api.config'; +import { ColumnDef } from '@tanstack/react-table'; +import React, { createContext, useCallback, useMemo, useState } from 'react'; +import { ListToolBar } from '../blocks/ListToolbar'; + +interface ContextProps { + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_user: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + selectedNotification: string | null; + notifications: NotificationProps[]; +} + +interface SelectedNotification { + id: string; + name: string; + destination_module: string; +} + +interface NotificationProps { + id: string; + name: string; + destination_module: string; +} + +const initialProps: ContextProps = { + showEditDialog: false, + showAddDialog: false, + handleEditDialog: () => {}, + handleAddDialog: () => {}, + selectedNotification: null, + notifications: [] +}; + +const ManageNotifContext = createContext(initialProps); +const API_URL = apiConfig.service_dashboard; + +const ManageNotifContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [selectedNotification, setSelectedNotification] = useState(null); + const [notifications, setNotifications] = useState([]); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_notification: string | null) => { + setSelectedNotification(show ? selected_notification : null); + setShowEditDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } + }, + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false + }, + { + accessorFn: (row) => row.destination_module, + id: 'destination_module', + header: ({ column }) => , + enableSorting: true, + enableHiding: false + }, + { + id: 'actions', + header: ({ column }) => , + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + }, + cell: (data: any) => { + const row = data.row.original; + + return ( +
+ +
+ ); + } + } + ], + [handleEditDialog, handleAddDialog] + ); + + return ( +
+
+

Manage Notifications

+
+ + + + } + layout={{ card: true }} + sorting={[{ id: 'username', desc: false }]} + serverSide={true} + > + {children} + + +
+ ); +}; + +export { ManageNotifContext, ManageNotifContextProvider }; +export type { SelectedNotification }; diff --git a/src/pages/notification/hooks/useManageNotificationContext.tsx b/src/pages/notification/hooks/useManageNotificationContext.tsx new file mode 100644 index 0000000..ceb5f0a --- /dev/null +++ b/src/pages/notification/hooks/useManageNotificationContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageNotifContext } from './ManageNotificationContext'; + +const useManageNotificationContext = () => { + const context = useContext(ManageNotifContext); + + if (!context) throw new Error('useManageNotificationContext must be used within AuthProvider'); + + return context; +}; + +export { useManageNotificationContext }; From c82abc3f1bcff713aa87449f05f4409a435aee20 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Wed, 26 Feb 2025 17:05:59 +0700 Subject: [PATCH 22/29] add master data route --- src/pages/master/MasterData.tsx | 11 +++++++++++ src/pages/master/aldeias/AldeiasMaster.tsx | 11 +++++++++++ src/pages/master/municipios/Municipios.tsx | 15 +++++++++++++++ src/pages/master/postoadms/PostoAdmsMaster.tsx | 11 +++++++++++ src/pages/master/sucos/SucosMaster.tsx | 11 +++++++++++ src/routing/AppRoutingSetup.tsx | 12 ++++++++++++ 6 files changed, 71 insertions(+) create mode 100644 src/pages/master/MasterData.tsx create mode 100644 src/pages/master/aldeias/AldeiasMaster.tsx create mode 100644 src/pages/master/municipios/Municipios.tsx create mode 100644 src/pages/master/postoadms/PostoAdmsMaster.tsx create mode 100644 src/pages/master/sucos/SucosMaster.tsx diff --git a/src/pages/master/MasterData.tsx b/src/pages/master/MasterData.tsx new file mode 100644 index 0000000..4cdb4cb --- /dev/null +++ b/src/pages/master/MasterData.tsx @@ -0,0 +1,11 @@ +const MasterData = () => { + return ( +
+
+

Master Data Page

+
+
+ ); +}; + +export default MasterData; diff --git a/src/pages/master/aldeias/AldeiasMaster.tsx b/src/pages/master/aldeias/AldeiasMaster.tsx new file mode 100644 index 0000000..851f5f1 --- /dev/null +++ b/src/pages/master/aldeias/AldeiasMaster.tsx @@ -0,0 +1,11 @@ +const AldeiasMaster = () => { + return ( +
+
+

Aldeias Master Data

+
+
+ ); +}; + +export default AldeiasMaster; diff --git a/src/pages/master/municipios/Municipios.tsx b/src/pages/master/municipios/Municipios.tsx new file mode 100644 index 0000000..3a3cf87 --- /dev/null +++ b/src/pages/master/municipios/Municipios.tsx @@ -0,0 +1,15 @@ +import { Container } from '@/components'; +import { ManageMunicipiosProvider } from './hooks/ManageMunicipiosContext'; +import MunicipiosContent from './MunicipiosContent'; + +const Municipios = () => { + return ( + + + + + + ); +}; + +export default Municipios; diff --git a/src/pages/master/postoadms/PostoAdmsMaster.tsx b/src/pages/master/postoadms/PostoAdmsMaster.tsx new file mode 100644 index 0000000..0394206 --- /dev/null +++ b/src/pages/master/postoadms/PostoAdmsMaster.tsx @@ -0,0 +1,11 @@ +const PostoAdmsMaster = () => { + return ( +
+
+

PostoAdms Master Data

+
+
+ ); +}; + +export default PostoAdmsMaster; diff --git a/src/pages/master/sucos/SucosMaster.tsx b/src/pages/master/sucos/SucosMaster.tsx new file mode 100644 index 0000000..6feede3 --- /dev/null +++ b/src/pages/master/sucos/SucosMaster.tsx @@ -0,0 +1,11 @@ +const SucosMaster = () => { + return ( +
+
+

Sucos Master Data

+
+
+ ); +}; + +export default SucosMaster; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index 707b9b1..7871b10 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -25,6 +25,11 @@ import Welcome from '@/pages/menu/welcome/Welcome'; import Inbox from '@/pages/message/Inbox'; import ManageWebServices from '@/pages/webservice/ManageWebServices'; import TransferType from '@/pages/transfer/TransferType'; +import MasterData from '@/pages/master/MasterData'; +import PostoAdmsMaster from '@/pages/master/postoadms/PostoAdmsMaster'; +import SucosMaster from '@/pages/master/sucos/SucosMaster'; +import AldeiasMaster from '@/pages/master/aldeias/AldeiasMaster'; +import Municipios from '@/pages/master/municipios/Municipios'; const AppRoutingSetup = (): ReactElement => { return ( @@ -32,6 +37,13 @@ const AppRoutingSetup = (): ReactElement => { }> }> } /> + + } /> + } /> + } /> + } /> + } /> + } /> } /> From 1e9d347b4d70d6d788ac9fdbfd61b34bf59fdc3d Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Wed, 26 Feb 2025 17:07:12 +0700 Subject: [PATCH 23/29] fetch get data Municipios --- .../master/municipios/MunicipiosContent.tsx | 34 +++++ .../hooks/ManageMunicipiosContext.tsx | 124 ++++++++++++++++++ .../hooks/useManageMunicipiosContext.tsx | 12 ++ 3 files changed, 170 insertions(+) create mode 100644 src/pages/master/municipios/MunicipiosContent.tsx create mode 100644 src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx create mode 100644 src/pages/master/municipios/hooks/useManageMunicipiosContext.tsx diff --git a/src/pages/master/municipios/MunicipiosContent.tsx b/src/pages/master/municipios/MunicipiosContent.tsx new file mode 100644 index 0000000..273072f --- /dev/null +++ b/src/pages/master/municipios/MunicipiosContent.tsx @@ -0,0 +1,34 @@ +import { ManageMunicipiosProvider } from './hooks/ManageMunicipiosContext'; +import { useManageMunicipiosContext } from './hooks/useManageMunicipiosContext'; + +const MunicipiosContent = () => { + const { + municipios, + getMunicipiosLists, + getMunicipiosByName, + createMunicipios, + deleteMunicipios, + updateMunicipios, + restoreMunicipios + } = useManageMunicipiosContext(); + return ( +
+

Municipios

+
    + {/* {municipios.map((municipio) => ( +
  • + {municipio.name} + + + +
  • + ))} */} +
+ +
+ ); +}; + +export default MunicipiosContent; diff --git a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx new file mode 100644 index 0000000..925cf8f --- /dev/null +++ b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx @@ -0,0 +1,124 @@ +import { apiConfig } from '@/config/api.config'; +import axios from 'axios'; +import React, { createContext, useEffect, useState } from 'react'; + +interface MunicipiosProps { + id: number; + name: string; +} + +interface MunicipiosContext { + municipios: MunicipiosProps[]; + getMunicipiosLists: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: string, + order_direction: 'ASC' | 'DESC' + ) => Promise; + getMunicipiosByName: (name: string) => Promise; + createMunicipios: (data: Partial) => Promise; + updateMunicipios: (id: number, data: Partial) => Promise; + deleteMunicipios: (id: number, hardDelete?: boolean) => Promise; + restoreMunicipios: (id: number) => Promise; +} + +const ManageMunicipiosContext = createContext(undefined); +const API_URL = apiConfig.service_master_data; + +const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) => { + const [municipios, setMunicipios] = useState([]); + + const getMunicipiosLists = async ( + limit: number, + page: number, + with_deleted: boolean, + order_field: string, + order_direction: 'ASC' | 'DESC' + ) => { + try { + const response = await axios.get(`${API_URL}/municipios/list`, { + params: { + limit: limit, + page: page, + with_deleted: with_deleted, + order_field: order_field, + order_direction: order_direction + } + }); + setMunicipios(response.data); + console.log(municipios); + } catch (error) { + console.error('Error fetching municipios', error); + } + }; + + const getMunicipiosByName = async (name: string) => { + try { + const response = await axios.get(`${API_URL}/municipios/postoadms/${name}`); + const data = response.data; + console.log(data); + } catch (error) { + console.error(`Error fetching municipios by ${name}`, error); + } + }; + + const createMunicipios = async (data: Partial) => { + try { + await axios.post(`${API_URL}/municipios/create`, data); + getMunicipiosLists(10, 1, false, 'name', 'ASC'); + } catch (error) { + console.error('Error creating municipios', error); + } + }; + + const updateMunicipios = async (id: number, data: Partial) => { + try { + await axios.put(`${API_URL}/update/${id}`, data); + getMunicipiosLists(10, 1, false, 'name', 'ASC'); + } catch (error) { + console.error('Error updating municipios', error); + } + }; + + const deleteMunicipios = async (id: number, hardDelete?: boolean) => { + try { + await axios.delete(`${API_URL}/delete/${id}/${hardDelete}`); + getMunicipiosLists(10, 1, false, 'name', 'ASC'); + } catch (error) { + console.error('Error deleting municipios', error); + } + }; + + const restoreMunicipios = async (id: number) => { + try { + await axios.put(`${API_URL}/restore/${id}`); + getMunicipiosLists(10, 1, false, 'name', 'ASC'); + } catch (error) { + console.error('Error restoring municipios', error); + } + }; + + useEffect(() => { + getMunicipiosLists(10, 1, false, 'name', 'ASC'); + }, []); + console.log(municipios); + return ( + + {children} + + ); +}; + +export { ManageMunicipiosProvider, ManageMunicipiosContext }; +export type { MunicipiosProps }; diff --git a/src/pages/master/municipios/hooks/useManageMunicipiosContext.tsx b/src/pages/master/municipios/hooks/useManageMunicipiosContext.tsx new file mode 100644 index 0000000..6dba2e7 --- /dev/null +++ b/src/pages/master/municipios/hooks/useManageMunicipiosContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageMunicipiosContext } from './ManageMunicipiosContext'; + +const useManageMunicipiosContext = () => { + const context = useContext(ManageMunicipiosContext); + + if (!context) throw new Error('useManageMunicipiosContext must be used within AuthProvider'); + + return context; +}; + +export { useManageMunicipiosContext }; From 7e511baecea96f4329544d80f0cf71080a2124cc Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 27 Feb 2025 10:47:38 +0700 Subject: [PATCH 24/29] add table for list municipios --- .../master/municipios/MunicipiosContent.tsx | 26 +-- .../master/municipios/blocks/ListToolbar.tsx | 57 +++++++ .../hooks/ManageMunicipiosContext.tsx | 155 ++++++++++++++---- 3 files changed, 183 insertions(+), 55 deletions(-) create mode 100644 src/pages/master/municipios/blocks/ListToolbar.tsx diff --git a/src/pages/master/municipios/MunicipiosContent.tsx b/src/pages/master/municipios/MunicipiosContent.tsx index 273072f..53a173d 100644 --- a/src/pages/master/municipios/MunicipiosContent.tsx +++ b/src/pages/master/municipios/MunicipiosContent.tsx @@ -1,32 +1,14 @@ +import { DataGridInner } from '@/components'; import { ManageMunicipiosProvider } from './hooks/ManageMunicipiosContext'; import { useManageMunicipiosContext } from './hooks/useManageMunicipiosContext'; const MunicipiosContent = () => { - const { - municipios, - getMunicipiosLists, - getMunicipiosByName, - createMunicipios, - deleteMunicipios, - updateMunicipios, - restoreMunicipios - } = useManageMunicipiosContext(); return (

Municipios

-
    - {/* {municipios.map((municipio) => ( -
  • - {municipio.name} - - - -
  • - ))} */} -
- +
+ +
); }; diff --git a/src/pages/master/municipios/blocks/ListToolbar.tsx b/src/pages/master/municipios/blocks/ListToolbar.tsx new file mode 100644 index 0000000..6865044 --- /dev/null +++ b/src/pages/master/municipios/blocks/ListToolbar.tsx @@ -0,0 +1,57 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useManageMunicipiosContext } from '../hooks/useManageMunicipiosContext'; +import { Button } from '@/components/ui/button'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog } = useManageMunicipiosContext(); + + return ( +
+
+
+
+ + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx index 925cf8f..87af97c 100644 --- a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx +++ b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx @@ -1,20 +1,53 @@ +import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { Toaster } from '@/components/ui/sonner'; import { apiConfig } from '@/config/api.config'; +import { ColumnDef } from '@tanstack/react-table'; import axios from 'axios'; -import React, { createContext, useEffect, useState } from 'react'; +import React, { createContext, useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallApi } from '@/hooks'; +import ListToolbar from '../blocks/ListToolbar'; interface MunicipiosProps { id: number; name: string; } +interface ContextProps { + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_user: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + showDeleteDialog: boolean; + handleDeleteDialog: (show: boolean, selected_user: string | null) => void; + selectedMunicipios: string | null; + getMunicipiosLists: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: any, + order_direction: any + ) => Promise<{ data: MunicipiosProps[]; totalCount: number } | undefined>; +} + +const initialProps: ContextProps = { + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + showDeleteDialog: false, + handleDeleteDialog: () => {}, + selectedMunicipios: null, + getMunicipiosLists: async () => ({ data: [], totalCount: 0 }) +}; + interface MunicipiosContext { municipios: MunicipiosProps[]; getMunicipiosLists: ( limit: number, page: number, with_deleted: boolean, - order_field: string, - order_direction: 'ASC' | 'DESC' + order_field: any, + order_direction: any ) => Promise; getMunicipiosByName: (name: string) => Promise; createMunicipios: (data: Partial) => Promise; @@ -23,31 +56,72 @@ interface MunicipiosContext { restoreMunicipios: (id: number) => Promise; } -const ManageMunicipiosContext = createContext(undefined); +const ManageMunicipiosContext = createContext(initialProps); const API_URL = apiConfig.service_master_data; const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) => { + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [selectedMunicipios, setSelectedMunicipios] = useState(null); const [municipios, setMunicipios] = useState([]); + const { GetData } = useCallApi(); - const getMunicipiosLists = async ( - limit: number, - page: number, - with_deleted: boolean, - order_field: string, - order_direction: 'ASC' | 'DESC' - ) => { + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_municipios: string | null) => { + setSelectedMunicipios(show ? selected_municipios : null); + setShowEditDialog(show); + }, []); + + const handleDeleteDialog = useCallback((show: boolean, selected_municipios: string | null) => { + setSelectedMunicipios(show ? selected_municipios : null); + setShowDeleteDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } + }, + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + } + ], + [handleEditDialog, handleDeleteDialog] + ); + + const getMunicipiosLists = async (page: number, limit: number, sorting: any, filter: any) => { try { + sorting = sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting; + filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; const response = await axios.get(`${API_URL}/municipios/list`, { params: { - limit: limit, - page: page, - with_deleted: with_deleted, - order_field: order_field, - order_direction: order_direction + limit, + page: 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc == false ? 'ASC' : 'DESC' } }); - setMunicipios(response.data); - console.log(municipios); + console.log(response.data); + return { data: response?.data.data.list, totalCount: response?.data.total_count }; } catch (error) { console.error('Error fetching municipios', error); } @@ -66,7 +140,7 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = const createMunicipios = async (data: Partial) => { try { await axios.post(`${API_URL}/municipios/create`, data); - getMunicipiosLists(10, 1, false, 'name', 'ASC'); + // getMunicipiosLists(10, 1, false, 'name', 'ASC'); } catch (error) { console.error('Error creating municipios', error); } @@ -75,7 +149,7 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = const updateMunicipios = async (id: number, data: Partial) => { try { await axios.put(`${API_URL}/update/${id}`, data); - getMunicipiosLists(10, 1, false, 'name', 'ASC'); + // getMunicipiosLists(10, 1, false, 'name', 'ASC'); } catch (error) { console.error('Error updating municipios', error); } @@ -84,7 +158,7 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = const deleteMunicipios = async (id: number, hardDelete?: boolean) => { try { await axios.delete(`${API_URL}/delete/${id}/${hardDelete}`); - getMunicipiosLists(10, 1, false, 'name', 'ASC'); + // getMunicipiosLists(10, 1, false, 'name', 'ASC'); } catch (error) { console.error('Error deleting municipios', error); } @@ -93,29 +167,44 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = const restoreMunicipios = async (id: number) => { try { await axios.put(`${API_URL}/restore/${id}`); - getMunicipiosLists(10, 1, false, 'name', 'ASC'); + // getMunicipiosLists(10, 1, false, 'name', 'ASC'); } catch (error) { console.error('Error restoring municipios', error); } }; - useEffect(() => { - getMunicipiosLists(10, 1, false, 'name', 'ASC'); - }, []); + // useEffect(() => { + // getMunicipiosLists(10, 1, false, 'name', 'ASC'); + // }, []); console.log(municipios); return ( - {children} + + + } + layout={{ card: true }} + sorting={[{ id: 'id', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + getMunicipiosLists(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + ); }; From 3d9ec24d5fc31aef67f6afa25c80ea47127e3ee1 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 27 Feb 2025 16:33:06 +0700 Subject: [PATCH 25/29] add form handling add municipio --- src/pages/master/municipios/Municipios.tsx | 12 +- .../master/municipios/MunicipiosContent.tsx | 16 --- .../master/municipios/blocks/AddDialog.tsx | 111 ++++++++++++++++++ .../master/municipios/blocks/ListToolbar.tsx | 2 +- .../hooks/ManageMunicipiosContext.tsx | 24 ++-- 5 files changed, 135 insertions(+), 30 deletions(-) delete mode 100644 src/pages/master/municipios/MunicipiosContent.tsx create mode 100644 src/pages/master/municipios/blocks/AddDialog.tsx diff --git a/src/pages/master/municipios/Municipios.tsx b/src/pages/master/municipios/Municipios.tsx index 3a3cf87..653cbb8 100644 --- a/src/pages/master/municipios/Municipios.tsx +++ b/src/pages/master/municipios/Municipios.tsx @@ -1,12 +1,16 @@ -import { Container } from '@/components'; +import { Container, DataGridInner } from '@/components'; import { ManageMunicipiosProvider } from './hooks/ManageMunicipiosContext'; -import MunicipiosContent from './MunicipiosContent'; +import AddDialog from './blocks/AddDialog'; const Municipios = () => { return ( - - + +

MUNICIPIOS

+
+ +
+
); diff --git a/src/pages/master/municipios/MunicipiosContent.tsx b/src/pages/master/municipios/MunicipiosContent.tsx deleted file mode 100644 index 53a173d..0000000 --- a/src/pages/master/municipios/MunicipiosContent.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { DataGridInner } from '@/components'; -import { ManageMunicipiosProvider } from './hooks/ManageMunicipiosContext'; -import { useManageMunicipiosContext } from './hooks/useManageMunicipiosContext'; - -const MunicipiosContent = () => { - return ( -
-

Municipios

-
- -
-
- ); -}; - -export default MunicipiosContent; diff --git a/src/pages/master/municipios/blocks/AddDialog.tsx b/src/pages/master/municipios/blocks/AddDialog.tsx new file mode 100644 index 0000000..2916f94 --- /dev/null +++ b/src/pages/master/municipios/blocks/AddDialog.tsx @@ -0,0 +1,111 @@ +import React, { useRef, useState } from 'react'; +import { useManageMunicipiosContext } from '../hooks/useManageMunicipiosContext'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Alert, KeenIcon } from '@/components'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; + +const AddDialog = () => { + const parentRef = useRef(null); + const { showAddDialog, handleAddDialog } = useManageMunicipiosContext(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + name: '' + }; + + const [formField, setFormField] = useState(initialState); + const resetForm = () => { + setFormField(initialState); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '') { + setAlert({ show: true, message: 'Please fill name field.' }); + return; + } + + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + const handleReset = () => { + setFormField(initialState); + }; + + return ( + handleAddDialog(open)}> + + + + +
+
+

Add Municipios

+
+
+
{ + handleAddDialog(false); + resetForm(); + }} + > + +
+
+
+ +
+ {alert.show && ( + + {alert.message} + + )} +
+
+
+ + + + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> +
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/master/municipios/blocks/ListToolbar.tsx b/src/pages/master/municipios/blocks/ListToolbar.tsx index 6865044..a1a90db 100644 --- a/src/pages/master/municipios/blocks/ListToolbar.tsx +++ b/src/pages/master/municipios/blocks/ListToolbar.tsx @@ -15,7 +15,7 @@ const ListToolbar = () => { table.getColumn('name')?.setFilterValue(event.target.value) diff --git a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx index 87af97c..031f8a2 100644 --- a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx +++ b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx @@ -96,12 +96,22 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = { accessorFn: (row) => row.name, id: 'name', - header: ({ column }) => , + header: ({ column }) => , enableSorting: true, enableHiding: false, meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.postoadms, + id: 'postoadms', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } } ], [handleEditDialog, handleDeleteDialog] @@ -113,21 +123,21 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; const response = await axios.get(`${API_URL}/municipios/list`, { params: { - limit, - page: 1, + limit: limit, + page: page + 1, with_deleted: false, order_field: sorting[0].id, order_direction: sorting[0].desc == false ? 'ASC' : 'DESC' } }); console.log(response.data); - return { data: response?.data.data.list, totalCount: response?.data.total_count }; + return { data: response?.data.data.list, totalCount: response?.data.data.total_count }; } catch (error) { console.error('Error fetching municipios', error); } }; - const getMunicipiosByName = async (name: string) => { + const getPostoadmsByMunicipio = async (name: string) => { try { const response = await axios.get(`${API_URL}/municipios/postoadms/${name}`); const data = response.data; @@ -173,10 +183,6 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = } }; - // useEffect(() => { - // getMunicipiosLists(10, 1, false, 'name', 'ASC'); - // }, []); - console.log(municipios); return ( Date: Fri, 28 Feb 2025 14:49:42 +0700 Subject: [PATCH 26/29] add dynamic routing for postoadms by municipioId --- src/routing/AppRoutingSetup.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index 7871b10..971fbaa 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -44,6 +44,8 @@ const AppRoutingSetup = (): ReactElement => { } /> } /> + } /> + } /> } /> From 126a7b2ba66081e50da645f5bf706863c5cb9a67 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Fri, 28 Feb 2025 14:51:03 +0700 Subject: [PATCH 27/29] add table page for postoadms by municipioId --- .../master/postoadms/PostoAdmsMaster.tsx | 16 +- .../master/postoadms/blocks/ListToolbar.tsx | 63 +++++++ .../hooks/ManagePostoAdmsContext.tsx | 178 ++++++++++++++++++ .../hooks/useManagePostoAdmsContext.tsx | 12 ++ 4 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 src/pages/master/postoadms/blocks/ListToolbar.tsx create mode 100644 src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx create mode 100644 src/pages/master/postoadms/hooks/useManagePostoAdmsContext.tsx diff --git a/src/pages/master/postoadms/PostoAdmsMaster.tsx b/src/pages/master/postoadms/PostoAdmsMaster.tsx index 0394206..a8e00d4 100644 --- a/src/pages/master/postoadms/PostoAdmsMaster.tsx +++ b/src/pages/master/postoadms/PostoAdmsMaster.tsx @@ -1,10 +1,16 @@ +import { ManagePostoAdmsContextProvider } from './hooks/ManagePostoAdmsContext'; +import { Container, DataGridInner } from '@/components'; + const PostoAdmsMaster = () => { return ( -
-
-

PostoAdms Master Data

-
-
+ + +

Postu Administrativo

+
+ +
+
+
); }; diff --git a/src/pages/master/postoadms/blocks/ListToolbar.tsx b/src/pages/master/postoadms/blocks/ListToolbar.tsx new file mode 100644 index 0000000..a05e53c --- /dev/null +++ b/src/pages/master/postoadms/blocks/ListToolbar.tsx @@ -0,0 +1,63 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; + +import { Button } from '@/components/ui/button'; +import { useManagePostoAdmsContext } from '../hooks/useManagePostoAdmsContext'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog, handleSearchDialog } = useManagePostoAdmsContext(); + + return ( +
+
+
+
+ + + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx b/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx new file mode 100644 index 0000000..2b8858f --- /dev/null +++ b/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx @@ -0,0 +1,178 @@ +import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { Button } from '@/components/ui/button'; +import { Toaster } from '@/components/ui/sonner'; +import { apiConfig } from '@/config/api.config'; +import { ColumnDef } from '@tanstack/react-table'; +import axios from 'axios'; +import { createContext, useCallback, useMemo, useState } from 'react'; +import { useNavigate, useParams } from 'react-router'; +import ListToolbar from '../blocks/ListToolbar'; + +interface PostoAdmsProps { + id: number; + name: string; +} + +interface ContextProps { + showSearchDialog: boolean; + handleSearchDialog: (show: boolean) => void; + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_postoAdms: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + showDeleteDialog: boolean; + handleDeleteDialog: (show: boolean, selected_postoAdms: string | null) => void; + selectedPostoAdms: string | null; + getPostoAdmsLists: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: any, + order_direction: any + ) => Promise<{ data: PostoAdmsProps[]; totalCount: number } | undefined>; +} + +const initialProps: ContextProps = { + showSearchDialog: false, + handleSearchDialog: (show: boolean) => {}, + showEditDialog: false, + handleEditDialog: (show: boolean, selected_postoAdms: string | null) => {}, + showAddDialog: false, + handleAddDialog: (show: boolean) => {}, + showDeleteDialog: false, + handleDeleteDialog: (show: boolean, selected_postoAdms: string | null) => {}, + selectedPostoAdms: null, + getPostoAdmsLists: async () => ({ data: [], totalCount: 0 }) +}; + +const ManagePostoAdmsContext = createContext(initialProps); +const API_URL = apiConfig.service_master_data; + +const ManagePostoAdmsContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showSearchDialog, setShowSearchDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showEditDialog, setShowEditDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [selectedPostoAdms, setSelectedPostoAdms] = useState(null); + + const navigate = useNavigate(); + const { municipioId } = useParams(); + + const handleSearchDialog = useCallback((show: boolean) => { + setShowSearchDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_postoAdms: string | null) => { + setSelectedPostoAdms(show ? selected_postoAdms : null); + setShowEditDialog(show); + }, []); + + const handleDeleteDialog = useCallback((show: boolean, selected_postoAdms: string | null) => { + setSelectedPostoAdms(show ? selected_postoAdms : null); + setShowDeleteDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } + }, + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[1000px]' + } + }, + { + id: 'actions', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { + headerClassName: 'w-[100px], text-center', + cellClassName: 'text-center' + }, + cell: (info) => ( + + ) + } + ], + [handleEditDialog, handleDeleteDialog] + ); + + const getPostoAdmsLists = async (page: number, limit: number, sorting: any, filter: any) => { + sorting: sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting; + filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; + try { + const response = await axios.get(`${API_URL}/municipios/postoadms/${municipioId}`, { + params: { + limit, + page: page + 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'DESC' : 'ASC' + } + }); + console.log(response.data); + return { data: response.data.data, totalCount: response.data.data.total_count }; + } catch (error) { + console.error('Error fetching Postu Administrativo', error); + } + }; + + return ( + + + + } + layout={{ card: true }} + sorting={[{ id: 'id', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + getPostoAdmsLists(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + + + ); +}; + +export { ManagePostoAdmsContextProvider, ManagePostoAdmsContext }; +export type { PostoAdmsProps }; diff --git a/src/pages/master/postoadms/hooks/useManagePostoAdmsContext.tsx b/src/pages/master/postoadms/hooks/useManagePostoAdmsContext.tsx new file mode 100644 index 0000000..8665426 --- /dev/null +++ b/src/pages/master/postoadms/hooks/useManagePostoAdmsContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManagePostoAdmsContext } from './ManagePostoAdmsContext'; + +const useManagePostoAdmsContext = () => { + const context = useContext(ManagePostoAdmsContext); + + if (!context) throw new Error('useManagePostoAdmsContext must be used within AuthProvider'); + + return context; +}; + +export { useManagePostoAdmsContext }; From f13496a26263483185f6f58259f7fb8586ba9873 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Fri, 28 Feb 2025 18:36:32 +0700 Subject: [PATCH 28/29] add button search postoadms --- src/pages/master/municipios/Municipios.tsx | 2 + .../master/municipios/blocks/ListToolbar.tsx | 13 +- .../master/municipios/blocks/SearchDialog.tsx | 177 ++++++++++++++++++ .../hooks/ManageMunicipiosContext.tsx | 85 ++++++--- 4 files changed, 246 insertions(+), 31 deletions(-) create mode 100644 src/pages/master/municipios/blocks/SearchDialog.tsx diff --git a/src/pages/master/municipios/Municipios.tsx b/src/pages/master/municipios/Municipios.tsx index 653cbb8..0538fbd 100644 --- a/src/pages/master/municipios/Municipios.tsx +++ b/src/pages/master/municipios/Municipios.tsx @@ -1,6 +1,7 @@ import { Container, DataGridInner } from '@/components'; import { ManageMunicipiosProvider } from './hooks/ManageMunicipiosContext'; import AddDialog from './blocks/AddDialog'; +import SearchDialog from './blocks/SearchDialog'; const Municipios = () => { return ( @@ -11,6 +12,7 @@ const Municipios = () => { + ); diff --git a/src/pages/master/municipios/blocks/ListToolbar.tsx b/src/pages/master/municipios/blocks/ListToolbar.tsx index a1a90db..0129c85 100644 --- a/src/pages/master/municipios/blocks/ListToolbar.tsx +++ b/src/pages/master/municipios/blocks/ListToolbar.tsx @@ -4,7 +4,7 @@ import { Button } from '@/components/ui/button'; const ListToolbar = () => { const { table, reload } = useDataGrid(); - const { handleAddDialog } = useManageMunicipiosContext(); + const { handleAddDialog, handleSearchDialog } = useManageMunicipiosContext(); return (
@@ -17,9 +17,7 @@ const ListToolbar = () => { type="text" placeholder="Search Municipios" value={(table.getColumn('name')?.getFilterValue() as string) ?? ''} - onChange={(event) => - table.getColumn('name')?.setFilterValue(event.target.value) - } + onChange={(event) => table.getColumn('name')?.setFilterValue(event.target.value)} /> @@ -33,6 +31,13 @@ const ListToolbar = () => { +
+ +
+ + + + + + + ); +}; + +export default SearchDialog; diff --git a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx index 031f8a2..808f57e 100644 --- a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx +++ b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx @@ -6,6 +6,8 @@ import axios from 'axios'; import React, { createContext, useCallback, useEffect, useMemo, useState } from 'react'; import { useCallApi } from '@/hooks'; import ListToolbar from '../blocks/ListToolbar'; +import { Button } from '@/components/ui/button'; +import { useNavigate } from 'react-router'; interface MunicipiosProps { id: number; @@ -13,6 +15,9 @@ interface MunicipiosProps { } interface ContextProps { + municipios: MunicipiosProps[]; + showSearchDialog: boolean; + handleSearchDialog: (show: boolean) => void; showEditDialog: boolean; handleEditDialog: (show: boolean, selected_user: string | null) => void; showAddDialog: boolean; @@ -30,42 +35,51 @@ interface ContextProps { } const initialProps: ContextProps = { + municipios: [], + showSearchDialog: false, + handleSearchDialog: (show: boolean) => {}, showEditDialog: false, - handleEditDialog: () => {}, + handleEditDialog: (show: boolean, selected_user: string | null) => {}, showAddDialog: false, - handleAddDialog: () => {}, + handleAddDialog: (show: boolean) => {}, showDeleteDialog: false, - handleDeleteDialog: () => {}, + handleDeleteDialog: (show: boolean, selected_user: string | null) => {}, selectedMunicipios: null, getMunicipiosLists: async () => ({ data: [], totalCount: 0 }) }; -interface MunicipiosContext { - municipios: MunicipiosProps[]; - getMunicipiosLists: ( - limit: number, - page: number, - with_deleted: boolean, - order_field: any, - order_direction: any - ) => Promise; - getMunicipiosByName: (name: string) => Promise; - createMunicipios: (data: Partial) => Promise; - updateMunicipios: (id: number, data: Partial) => Promise; - deleteMunicipios: (id: number, hardDelete?: boolean) => Promise; - restoreMunicipios: (id: number) => Promise; -} +// interface MunicipiosContext { +// municipios: MunicipiosProps[]; +// getMunicipiosLists: ( +// limit: number, +// page: number, +// with_deleted: boolean, +// order_field: any, +// order_direction: any +// ) => Promise; +// getMunicipiosByName: (name: string) => Promise; +// createMunicipios: (data: Partial) => Promise; +// updateMunicipios: (id: number, data: Partial) => Promise; +// deleteMunicipios: (id: number, hardDelete?: boolean) => Promise; +// restoreMunicipios: (id: number) => Promise; +// } const ManageMunicipiosContext = createContext(initialProps); const API_URL = apiConfig.service_master_data; const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) => { + const [showSearchDialog, setShowSearchDialog] = useState(false); const [showEditDialog, setShowEditDialog] = useState(false); const [showAddDialog, setShowAddDialog] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [selectedMunicipios, setSelectedMunicipios] = useState(null); const [municipios, setMunicipios] = useState([]); const { GetData } = useCallApi(); + const navigate = useNavigate(); + + const handleSearchDialog = useCallback((show: boolean) => { + setShowSearchDialog(show); + }, []); const handleAddDialog = useCallback((show: boolean) => { setShowAddDialog(show); @@ -81,6 +95,11 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = setShowDeleteDialog(show); }, []); + const handleNavigate = (path: string) => { + const url = navigate(`${API_URL}/municipios/postoadms/${path}`); + console.log(url); + }; + const columns = useMemo[]>( () => [ { @@ -100,18 +119,26 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = enableSorting: true, enableHiding: false, meta: { - headerClassName: 'w-[250px]' + headerClassName: 'w-[1000px]' } }, { - accessorFn: (row) => row.postoadms, - id: 'postoadms', - header: ({ column }) => , - enableSorting: true, + id: 'actions', + header: ({ column }) => , + enableSorting: false, enableHiding: false, meta: { - headerClassName: 'w-[100px]' - } + headerClassName: 'w-[100px], text-center', + cellClassName: 'text-center' + }, + cell: (info) => ( + + ) } ], [handleEditDialog, handleDeleteDialog] @@ -131,6 +158,7 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = } }); console.log(response.data); + setMunicipios(response.data.data.list); return { data: response?.data.data.list, totalCount: response?.data.data.total_count }; } catch (error) { console.error('Error fetching municipios', error); @@ -182,10 +210,13 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = console.error('Error restoring municipios', error); } }; - + console.log(municipios); return ( } layout={{ card: true }} sorting={[{ id: 'id', desc: false }]} From fa4be57a8bc90e5684db6cbfbdbed3cd5a047b8b Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Fri, 28 Feb 2025 22:21:06 +0700 Subject: [PATCH 29/29] update api config --- src/config/api.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/api.config.ts b/src/config/api.config.ts index 3d321e3..3087034 100644 --- a/src/config/api.config.ts +++ b/src/config/api.config.ts @@ -4,11 +4,11 @@ interface apiConfigProps { } const API_URL = import.meta.env.VITE_APP_API_URL; -console.log(API_URL); const apiConfig: apiConfigProps = { // service_dashboard: `${API_URL}${import.meta.env.VITE_ENV != 'development' ? '/d' : ''}`, service_dashboard: `${API_URL}/d`, - service_master_data: `${API_URL}/m` + // service_master_data: `${API_URL}/m` + service_master_data: `${API_URL}/t` }; export { apiConfig };