diff --git a/src/pages/access/access-type/AccessType.tsx b/src/pages/access/access-type/AccessType.tsx
new file mode 100644
index 0000000..eaa656d
--- /dev/null
+++ b/src/pages/access/access-type/AccessType.tsx
@@ -0,0 +1,21 @@
+import { Container, DataGridInner } from '@/components';
+import {
+ ManageAccessTypeContext,
+ ManageAccessTypeContextProvider
+} from './hooks/ManageAccessTypeContext';
+import AddDialog from './blocks/AddDialog';
+
+const AccessType = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default AccessType;
diff --git a/src/pages/access/access-type/blocks/AddDialog.tsx b/src/pages/access/access-type/blocks/AddDialog.tsx
new file mode 100644
index 0000000..609640c
--- /dev/null
+++ b/src/pages/access/access-type/blocks/AddDialog.tsx
@@ -0,0 +1,141 @@
+import { apiConfig } from '@/config/api.config';
+import { useRef, useState } from 'react';
+import { useManageAccessTypeContext } from '../hooks/useManageAccessTypeContext';
+import { Alert, KeenIcon, useDataGrid } from '@/components';
+import { useCallApi } from '@/hooks';
+import { Dialog, DialogBody, DialogContent, DialogHeader } from '@/components/ui/dialog';
+import { Input } from '@/components/ui/input';
+import { Button } from '@/components/ui/button';
+
+const API_URL = apiConfig.service_dashboard;
+
+const AddDialog = () => {
+ const parentRef = useRef
(null);
+ const { showAddDialog, handleAddDialog, accessTypes } = useManageAccessTypeContext();
+ const { reload } = useDataGrid();
+ const { PostData, PutData } = useCallApi();
+ const [alert, setAlert] = useState({
+ show: false,
+ message: ''
+ });
+
+ const initialState = {
+ name: '',
+ description: '',
+ internal_name: ''
+ };
+
+ const [formField, setFormField] = useState(initialState);
+ const resetForm = () => {
+ setFormField(initialState);
+ };
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ // setIsSubmitting(true);
+ console.log(formField);
+ };
+
+ const handleReset = () => {
+ setFormField(initialState);
+ };
+
+ return (
+
+ );
+};
+
+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..546d226
--- /dev/null
+++ b/src/pages/access/access-type/hooks/ManageAccessTypeContext.tsx
@@ -0,0 +1,162 @@
+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;
+ internal_name: string;
+ description: string;
+}
+
+interface AccessTypeProps {
+ id: string;
+ name: string;
+ internal_name: string;
+ description: string;
+}
+
+interface ContextProps {
+ showEditDialog: boolean;
+ handleEditDialog: (show: boolean, selected_user: string | null) => void;
+ showAddDialog: boolean;
+ handleAddDialog: (show: boolean) => void;
+ selectedUser: string | null;
+ accessTypes: AccessTypeProps[];
+}
+
+const initialProps: ContextProps = {
+ showEditDialog: false,
+ handleEditDialog: () => {},
+ showAddDialog: false,
+ handleAddDialog: () => {},
+ selectedUser: null,
+ accessTypes: []
+};
+
+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 [accessTypes, setAccessTypes] = 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.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/access/member-credentials/MemberCredentials.tsx b/src/pages/access/member-credentials/MemberCredentials.tsx
new file mode 100644
index 0000000..2ef4cfc
--- /dev/null
+++ b/src/pages/access/member-credentials/MemberCredentials.tsx
@@ -0,0 +1,21 @@
+import MemberCredentialsForm from './blocks/MemberCredentialsForm';
+import { useMemberCredentials } from './hooks';
+
+const MemberCredentials = () => {
+ const { error, memberCredentials, handleChange, handleSubmit } = useMemberCredentials();
+ return (
+
+
+
Member Credential
+
+
+
+ );
+};
+
+export default MemberCredentials;
diff --git a/src/pages/access/member-credentials/blocks/MemberCredentialsForm.tsx b/src/pages/access/member-credentials/blocks/MemberCredentialsForm.tsx
new file mode 100644
index 0000000..1f066f3
--- /dev/null
+++ b/src/pages/access/member-credentials/blocks/MemberCredentialsForm.tsx
@@ -0,0 +1,97 @@
+import { Alert } from '@/components';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue
+} from '@/components/ui/select';
+
+interface MemberCredentials {
+ accessType: string | null;
+ username: string;
+ credential: string;
+ confirmCredential: string;
+}
+
+interface Props {
+ form: MemberCredentials;
+ error: string | null;
+ onChange: (key: keyof MemberCredentials, value: string) => void;
+ onSubmit: () => void;
+}
+
+const MemberCredentialsForm = ({ form, error, onChange, onSubmit }: Props) => {
+ return (
+
+
Create Member Credentials
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+ {/* Access Type */}
+
+
+
+
+
+ {/* Username */}
+
+
+ onChange('username', e.target.value)} />
+
+
+ {/* Credentials */}
+
+
+ onChange('credential', e.target.value)}
+ />
+
+
+ {/* Confirm Credentials */}
+
+
+ onChange('confirmCredential', e.target.value)}
+ />
+
+
+
+
+
+ );
+};
+
+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 };
+};
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/account/manage-account/ManageAccount.tsx b/src/pages/account/manage-account/ManageAccount.tsx
new file mode 100644
index 0000000..b2a5f31
--- /dev/null
+++ b/src/pages/account/manage-account/ManageAccount.tsx
@@ -0,0 +1,83 @@
+import { apiConfig } from '@/config/api.config';
+import { Account, columns } from './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 (
+
+ );
+};
+
+export default ManageAccount;
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/pages/account/manage-currency/ManageCurrency.tsx b/src/pages/account/manage-currency/ManageCurrency.tsx
new file mode 100644
index 0000000..a9b89e9
--- /dev/null
+++ b/src/pages/account/manage-currency/ManageCurrency.tsx
@@ -0,0 +1,18 @@
+import { Container, DataGridInner } from '@/components';
+import { ManageCurrencyContextProvider } from './hooks/ManageCurrencyContext';
+import AddDialog from './blocks/AddDialog';
+
+const ManageCurrency = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ManageCurrency;
diff --git a/src/pages/account/manage-currency/blocks/AddDialog.tsx b/src/pages/account/manage-currency/blocks/AddDialog.tsx
new file mode 100644
index 0000000..3394fe0
--- /dev/null
+++ b/src/pages/account/manage-currency/blocks/AddDialog.tsx
@@ -0,0 +1,240 @@
+import { apiConfig } from '@/config/api.config';
+import { useRef, useState } from 'react';
+import { useManageCurrencyContext } from '../hooks/useManageAccessTypeContext';
+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';
+
+const API_URL = apiConfig.service_dashboard;
+
+const AddDialog = () => {
+ const parentRef = useRef(null);
+ const {
+ showAddDialog,
+ handleAddDialog,
+ currencies,
+ showEditDialog,
+ handleEditDialog,
+ selectedUser
+ } = useManageCurrencyContext();
+
+ const { reload } = useDataGrid();
+ const { PostData, PutData } = useCallApi();
+ const [alert, setAlert] = useState({
+ show: false,
+ message: ''
+ });
+
+ const initialState = {
+ name: '',
+ code: '',
+ prefix: '',
+ trailer: '',
+ format: '',
+ grouping_separator: '',
+ decimal_separator: ''
+ };
+
+ 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.code === '' ||
+ formField.prefix === '' ||
+ formField.format === '' ||
+ formField.decimal_separator === '' ||
+ formField.grouping_separator === ''
+ ) {
+ setAlert({ show: true, message: 'Please fill in all required fields.' });
+ return;
+ }
+ console.log(formField);
+ setAlert({ show: false, message: '' });
+ };
+
+ const handleReset = () => {
+ setFormField(initialState);
+ };
+
+ return (
+
+ );
+};
+
+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..53af0d6
--- /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..c5cd102
--- /dev/null
+++ b/src/pages/account/manage-currency/hooks/ManageCurrencyContext.tsx
@@ -0,0 +1,259 @@
+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;
+ 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();
+
+ 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);
+ }, []);
+
+ 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]
+ );
+ console.log(currencies);
+ return (
+
+
+
Manage Currency
+
+
+
+
+ {currencies.length > 0 ? (
+ }
+ sorting={[{ id: 'id', desc: true }]}
+ serverSide={true}
+ >
+ {children}
+
+ ) : (
+ loading
+ )}
+
+
+ );
+};
+
+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 };
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..1c777f1
--- /dev/null
+++ b/src/pages/dashboards/home/staticChart.tsx
@@ -0,0 +1,56 @@
+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']
+ }
+};
diff --git a/src/pages/groups/Column.tsx b/src/pages/groups/Column.tsx
new file mode 100644
index 0000000..9809155
--- /dev/null
+++ b/src/pages/groups/Column.tsx
@@ -0,0 +1,37 @@
+import { ColumnDef } from '@tanstack/react-table';
+
+export type Group = {
+ id: number;
+ createdDate: Date;
+ name: string;
+ status: string;
+ description: string;
+};
+
+export const columns: ColumnDef[] = [
+ {
+ accessorKey: 'id',
+ header: 'ID'
+ },
+ {
+ accessorKey: 'createdDate',
+ header: 'Created Date',
+ cell: ({ row }) => new Date(row.original.createdDate).toLocaleDateString()
+ },
+ {
+ accessorKey: 'name',
+ header: 'Name'
+ },
+ {
+ accessorKey: 'status',
+ header: 'Status'
+ },
+ {
+ accessorKey: 'description',
+ header: 'Description'
+ },
+ // {
+ // id: 'actions',
+ // header: 'Actions'
+ // }
+];
diff --git a/src/pages/groups/ManageGroups.tsx b/src/pages/groups/ManageGroups.tsx
new file mode 100644
index 0000000..2ede523
--- /dev/null
+++ b/src/pages/groups/ManageGroups.tsx
@@ -0,0 +1,249 @@
+import { DataTable } from '@/components/ui/DataTable';
+import { columns, Group } from './Column';
+import { apiConfig } from '@/config/api.config';
+import axios, { AxiosResponse } from 'axios';
+import { DialogContent, MenuItem, Radio, RadioGroup, FormControlLabel, FormControl,
+ Dialog, DialogActions, DialogTitle, Typography, Button, Box } from '@mui/material';
+import { useState, useEffect } from 'react';
+// import IconButton from '@mui/material/IconButton';
+import CloseIcon from '@mui/icons-material/Close';
+import Divider from '@mui/material/Divider';
+import ConfirmDialog from '@/components/confirm';
+// import { DialogHeader } from '@/components/ui/dialog';
+// import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
+const BASE_URL = apiConfig.service_customer;
+
+let initGroup = {
+ id: '',
+ groupName: '',
+ status: '',
+ description: '',
+ pin_length: '',
+ max_pin_attempts: '',
+ default_notification: ''
+}
+
+const ManageGroups = () => {
+ const [isDialogOpen, setIsDialogOpen] = useState(false);
+ const [dataGroup, setDataGroup] = useState([]);
+ const [formData, setFormData] = useState(initGroup);
+ const [pageIndex, setPageIndex] = useState(0);
+ const [pageSize, setPageSize] = useState(10);
+ const [dialogType, setDialogType] = useState('');
+ const [dialogOpen, setDialogOpen] = useState(false);
+
+ useEffect(() => {
+ fetchGroups()
+ }, []);
+
+ async function fetchGroups() {
+ try {
+ let groups = await axios.get(`${BASE_URL}/groups/list`, {
+ params: {
+ limit: 10,
+ page: 1,
+ with_deleted: false,
+ order_field: 'name',
+ order_direction: 'ASC'
+ }
+ });
+ setDataGroup(groups.data.data.list)
+ } catch (error: any) {
+ alert(error.message)
+ console.log(error);
+ }
+ }
+
+ const openDialog = () => setIsDialogOpen(true);
+ const closeDialog = () => {
+ setIsDialogOpen(false)
+ setFormData(initGroup)
+ };
+
+ const handleChange = (e: React.ChangeEvent) => {
+ setFormData({
+ ...formData,
+ [e.target.name]: e.target.value
+ })
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setDialogOpen(true);
+ };
+
+ function createGroup() {
+ setDialogType('create');
+ openDialog();
+ }
+
+ const handleUpdate = (group: any) => {
+ setFormData({
+ ...formData,
+ id: group.id,
+ groupName: group.name,
+ status: group.status,
+ description: group.description
+ })
+ setDialogType('update');
+ setIsDialogOpen(true)
+ };
+
+ const handleDelete = (group: any) => {
+ setFormData({
+ ...formData,
+ id: group.id,
+ groupName: group.name,
+ status: group.status,
+ description: group.description
+ })
+ setDialogType('delete');
+ setDialogOpen(true)
+ };
+
+ const handleYes = async () => {
+ try {
+ if (dialogType === 'create') {
+ await axios.post(`${BASE_URL}/groups/create`, {
+ "name": formData.groupName,
+ "status": formData.status,
+ "created_at": new Date()
+ })
+ } else if (dialogType === 'update') {
+ await axios.put(`${BASE_URL}/groups/update/${formData.id}`, {
+ "name": formData.groupName,
+ "status": formData.status,
+ "updated_at": new Date()
+ })
+ } else if (dialogType === 'delete') {
+ await axios.delete(`${BASE_URL}/groups/delete/${formData.id}/true`)
+ }
+ await fetchGroups();
+ closeDialog();
+ setDialogOpen(false);
+ } catch (error) {
+ console.log(error);
+ closeDialog();
+ setDialogOpen(false);
+ }
+ };
+
+ const handleNo = () => {
+ setDialogOpen(false);
+ };
+
+ return (
+
+
+
setDialogOpen(false)}
+ title="Confirm Action"
+ content={`Are you sure you want to `+( dialogType === 'create' ? "create?" : ( dialogType === 'update' ? "update?" : "delete?"))}
+ onYes={handleYes}
+ onNo={handleNo}
+ />
+ Groups
+
+
+
+
+ );
+};
+
+export default ManageGroups;
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 (
+
+ );
+};
+
+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..0538fbd
--- /dev/null
+++ b/src/pages/master/municipios/Municipios.tsx
@@ -0,0 +1,21 @@
+import { Container, DataGridInner } from '@/components';
+import { ManageMunicipiosProvider } from './hooks/ManageMunicipiosContext';
+import AddDialog from './blocks/AddDialog';
+import SearchDialog from './blocks/SearchDialog';
+
+const Municipios = () => {
+ return (
+
+
+ MUNICIPIOS
+
+
+
+
+
+
+
+ );
+};
+
+export default Municipios;
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 (
+
+ );
+};
+
+export default AddDialog;
diff --git a/src/pages/master/municipios/blocks/ListToolbar.tsx b/src/pages/master/municipios/blocks/ListToolbar.tsx
new file mode 100644
index 0000000..0129c85
--- /dev/null
+++ b/src/pages/master/municipios/blocks/ListToolbar.tsx
@@ -0,0 +1,62 @@
+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, handleSearchDialog } = useManageMunicipiosContext();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ListToolbar;
diff --git a/src/pages/master/municipios/blocks/SearchDialog.tsx b/src/pages/master/municipios/blocks/SearchDialog.tsx
new file mode 100644
index 0000000..4ba1a62
--- /dev/null
+++ b/src/pages/master/municipios/blocks/SearchDialog.tsx
@@ -0,0 +1,177 @@
+import { useRef, useState } from 'react';
+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';
+import { useManageMunicipiosContext } from '../hooks/useManageMunicipiosContext';
+import { apiConfig } from '@/config/api.config';
+import axios from 'axios';
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue
+} from '@/components/ui/select';
+
+interface PostoAdms {
+ id: number;
+ name: string;
+}
+
+const API_URL = apiConfig.service_master_data;
+
+const SearchDialog = () => {
+ const parentRef = useRef(null);
+ const { showSearchDialog, handleSearchDialog, municipios } = useManageMunicipiosContext();
+ const [alert, setAlert] = useState({
+ show: false,
+ message: ''
+ });
+ const initialState = {
+ id: 0,
+ name: ''
+ };
+
+ const [formField, setFormField] = useState(initialState);
+ const resetForm = () => {
+ setFormField(initialState);
+ };
+ const [postoadms, setPostoadms] = useState([]);
+ const [isFound, setIsFound] = useState(false);
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ const id = Number(formField.id);
+
+ if (formField.id === 0) {
+ setAlert({ show: true, message: 'Please fill name field.' });
+ return;
+ }
+
+ try {
+ const response = await axios.get(`${API_URL}/municipios/postoadms/${id}`);
+
+ if (response.data.status) {
+ setPostoadms(response.data.data);
+ setIsFound(true);
+ console.log('Found postoadms: ', response.data.data);
+ } else {
+ setPostoadms([]);
+ setIsFound(false);
+ setAlert({ show: true, message: 'No postoadms found.' });
+ }
+ } catch (error) {
+ console.error('Error fetching postoadms', error);
+ setAlert({ show: true, message: 'Failed to fetch postoadms. Please try again.' });
+ }
+ setAlert({ show: false, message: '' });
+ };
+
+ const handleReset = () => {
+ setFormField(initialState);
+ setIsFound(false);
+ setPostoadms([]);
+ };
+ // console.log(municipios);
+ return (
+
+ );
+};
+
+export default SearchDialog;
diff --git a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx
new file mode 100644
index 0000000..808f57e
--- /dev/null
+++ b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx
@@ -0,0 +1,250 @@
+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, 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;
+ name: string;
+}
+
+interface ContextProps {
+ municipios: MunicipiosProps[];
+ showSearchDialog: boolean;
+ handleSearchDialog: (show: boolean) => void;
+ 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 = {
+ municipios: [],
+ showSearchDialog: false,
+ handleSearchDialog: (show: boolean) => {},
+ showEditDialog: false,
+ handleEditDialog: (show: boolean, selected_user: string | null) => {},
+ showAddDialog: false,
+ handleAddDialog: (show: boolean) => {},
+ showDeleteDialog: false,
+ 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;
+// }
+
+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);
+ }, []);
+
+ 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 handleNavigate = (path: string) => {
+ const url = navigate(`${API_URL}/municipios/postoadms/${path}`);
+ console.log(url);
+ };
+
+ 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 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 + 1,
+ with_deleted: false,
+ order_field: sorting[0].id,
+ order_direction: sorting[0].desc == false ? 'ASC' : 'DESC'
+ }
+ });
+ 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);
+ }
+ };
+
+ const getPostoadmsByMunicipio = 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);
+ }
+ };
+ console.log(municipios);
+ return (
+
+
+
+ }
+ layout={{ card: true }}
+ sorting={[{ id: 'id', desc: false }]}
+ serverSide={true}
+ onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) =>
+ getMunicipiosLists(pageIndex, pageSize, sorting, columnFilters)
+ }
+ >
+ {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 };
diff --git a/src/pages/master/postoadms/PostoAdmsMaster.tsx b/src/pages/master/postoadms/PostoAdmsMaster.tsx
new file mode 100644
index 0000000..a8e00d4
--- /dev/null
+++ b/src/pages/master/postoadms/PostoAdmsMaster.tsx
@@ -0,0 +1,17 @@
+import { ManagePostoAdmsContextProvider } from './hooks/ManagePostoAdmsContext';
+import { Container, DataGridInner } from '@/components';
+
+const PostoAdmsMaster = () => {
+ return (
+
+
+ Postu Administrativo
+
+
+
+
+
+ );
+};
+
+export default PostoAdmsMaster;
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 };
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/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/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/blocks/ListToolBar.tsx b/src/pages/members/kyc/blocks/ListToolBar.tsx
new file mode 100644
index 0000000..8d99350
--- /dev/null
+++ b/src/pages/members/kyc/blocks/ListToolBar.tsx
@@ -0,0 +1,48 @@
+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..246dfa8
--- /dev/null
+++ b/src/pages/members/kyc/hooks/index.ts
@@ -0,0 +1,2 @@
+export * from './ManageKycContext';
+export * from './useKycContext';
diff --git a/src/pages/members/kyc/hooks/useKycContext.tsx b/src/pages/members/kyc/hooks/useKycContext.tsx
new file mode 100644
index 0000000..1043f87
--- /dev/null
+++ b/src/pages/members/kyc/hooks/useKycContext.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/members/manage-members/Columns.tsx b/src/pages/members/manage-members/Columns.tsx
new file mode 100644
index 0000000..c217e7f
--- /dev/null
+++ b/src/pages/members/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/members/manage-members/ManageMembers.tsx b/src/pages/members/manage-members/ManageMembers.tsx
new file mode 100644
index 0000000..3a099a3
--- /dev/null
+++ b/src/pages/members/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 (
+
+ );
+};
+
+export default ManageMembers;
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 (
+
+ );
+};
+
+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 (
+
+ );
+};
+
+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 (
+
+ );
+};
+
+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 (
+
+ );
+};
+
+export default Inbox;
diff --git a/src/pages/notification/ManageNotification.tsx b/src/pages/notification/ManageNotification.tsx
new file mode 100644
index 0000000..3f26388
--- /dev/null
+++ b/src/pages/notification/ManageNotification.tsx
@@ -0,0 +1,18 @@
+import { Container, DataGridInner } from '@/components';
+import { ManageNotifContextProvider } from './hooks/ManageNotificationContext';
+import AddDialog from './blocks/AddDialog';
+
+const ManageNotification = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ManageNotification;
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 (
+
+ );
+};
+
+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 };
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 = () => {