From 643dd15252cbf33d7be147aecdb1d7bc4106f76c Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Wed, 8 Jul 2026 11:26:25 +0700 Subject: [PATCH] update sites crud done --- src/layouts/demo2/navbar/NavbarMenu.tsx | 5 + .../user/manage-user/ManageUserPage.tsx | 2 +- .../sites/manage-sites/ManageSitesPage.tsx | 45 +++ .../sites/manage-sites/blocks/AddDialog.tsx | 245 ++++++++++++++++ .../manage-sites/blocks/DeleteDialog.tsx | 92 ++++++ .../sites/manage-sites/blocks/EditDialog.tsx | 261 ++++++++++++++++++ .../sites/manage-sites/blocks/ListToolBar.tsx | 76 +++++ src/pages/sites/manage-sites/blocks/Types.ts | 69 +++++ src/pages/sites/manage-sites/blocks/index.ts | 2 + .../manage-sites/hooks/ManageSitesContext.tsx | 246 +++++++++++++++++ src/pages/sites/manage-sites/hooks/index.ts | 2 + .../hooks/useManageSitesContext.tsx | 12 + src/pages/sites/manage-sites/index.ts | 1 + src/routing/AppRoutingSetup.tsx | 4 + 14 files changed, 1061 insertions(+), 1 deletion(-) create mode 100644 src/pages/sites/manage-sites/ManageSitesPage.tsx create mode 100644 src/pages/sites/manage-sites/blocks/AddDialog.tsx create mode 100644 src/pages/sites/manage-sites/blocks/DeleteDialog.tsx create mode 100644 src/pages/sites/manage-sites/blocks/EditDialog.tsx create mode 100644 src/pages/sites/manage-sites/blocks/ListToolBar.tsx create mode 100644 src/pages/sites/manage-sites/blocks/Types.ts create mode 100644 src/pages/sites/manage-sites/blocks/index.ts create mode 100644 src/pages/sites/manage-sites/hooks/ManageSitesContext.tsx create mode 100644 src/pages/sites/manage-sites/hooks/index.ts create mode 100644 src/pages/sites/manage-sites/hooks/useManageSitesContext.tsx create mode 100644 src/pages/sites/manage-sites/index.ts diff --git a/src/layouts/demo2/navbar/NavbarMenu.tsx b/src/layouts/demo2/navbar/NavbarMenu.tsx index b051fcf..6c5512c 100644 --- a/src/layouts/demo2/navbar/NavbarMenu.tsx +++ b/src/layouts/demo2/navbar/NavbarMenu.tsx @@ -29,6 +29,11 @@ const STATIC_MENU: MappedMenu[] = [ path: '-', children: [{ title: 'Dashboard', path: '/' }] }, + { + title: 'Manage Sites', + path: '-', + children: [{ title: 'Manage Sites', path: '/sites/manage-sites' }] + }, { title: 'Revenue', path: '-', diff --git a/src/pages/settings/user/manage-user/ManageUserPage.tsx b/src/pages/settings/user/manage-user/ManageUserPage.tsx index 6c8786c..c22da28 100644 --- a/src/pages/settings/user/manage-user/ManageUserPage.tsx +++ b/src/pages/settings/user/manage-user/ManageUserPage.tsx @@ -10,7 +10,7 @@ export default function ManageUserPage() { return ( <> - TPAY | Manage User + REVENUE | Manage User diff --git a/src/pages/sites/manage-sites/ManageSitesPage.tsx b/src/pages/sites/manage-sites/ManageSitesPage.tsx new file mode 100644 index 0000000..8678783 --- /dev/null +++ b/src/pages/sites/manage-sites/ManageSitesPage.tsx @@ -0,0 +1,45 @@ +import { Container, DataGridInner } from '@/components'; +import { EditDialog } from './blocks'; +import { ManageSitesContextProvider } from './hooks'; +import { AddDialog } from './blocks/AddDialog'; +import { DeleteDialog } from './blocks/DeleteDialog'; +import { Breadcrumbs, Link } from '@mui/material'; +import { Helmet } from 'react-helmet'; + +export default function ManageSitesPage() { + return ( + <> + + REVENUE | Manage Sites + + + +

Manage Sites

+ + + Dashboard + + + {/* + Settings + */} + + {/* + User Management + */} + + + Manage Sites + + +
+ +
+ + + +
+
+ + ); +} diff --git a/src/pages/sites/manage-sites/blocks/AddDialog.tsx b/src/pages/sites/manage-sites/blocks/AddDialog.tsx new file mode 100644 index 0000000..0aba134 --- /dev/null +++ b/src/pages/sites/manage-sites/blocks/AddDialog.tsx @@ -0,0 +1,245 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { useSitesContext } from '../hooks'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import { apiConfig } from '@/config/api.config'; +import { KeenIcon, useDataGrid } from '@/components'; +import { toast } from 'sonner'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { + initialStateCreateSites, + validateFormCreateSites +} from './Types'; + +const API_URL = apiConfig.service_master_data; + +const AddDialog = () => { + const parentRef = useRef(null); + const { showAddDialog, handleAddDialog } = useSitesContext(); + const { reload } = useDataGrid(); + const { PostData } = useCallApi(); + const [errors, setErrors] = useState>({}); + + const [formField, setFormField] = useState(initialStateCreateSites); + const [isSubmitting, setIsSubmitting] = useState(false); + + const resetForm = () => { + setFormField(initialStateCreateSites); + setErrors({}); + }; + + /* actions */ + const doCreateSites = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + + try { + const response = await PostData(`${API_URL}/site-points/create`, formField); + + if (response?.status) { + handleAddDialog(false); + resetForm(); + reload(); + const createActivity = { + module: 'Manage Sites', + description: `Create New Sites => ${formField.location}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); + toast.success('Success Create Site'); + } else { + toast.error(response?.message); + } + } catch (err) { + toast.error('Something went wrong'); + console.log(err); + } finally { + setIsSubmitting(false); + } + }, + [formField] + ); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (isSubmitting) return; + + if (!validateFormCreateSites(formField, setErrors, 'create')) { + return; + } + + doCreateSites(e); + }; + + useEffect(() => { + if (showAddDialog === false) { + resetForm(); + } + }, [showAddDialog]); + + return ( + handleAddDialog(open)}> + + + + +
+
+

Site - Create

+
+
{ + handleAddDialog(false); + resetForm(); + }} + > + +
+
+
+ + +
+ {/* Cell */} +
+ +
+ { + setFormField((prev) => ({ ...prev, cell: target.value })); + setErrors((prev) => ({ ...prev, cell: '' })); + }} + /> + {errors.cell && {errors.cell}} +
+
+ + {/* Sector */} +
+ +
+ { + setFormField((prev) => ({ ...prev, sector: target.value })); + setErrors((prev) => ({ ...prev, sector: '' })); + }} + /> + {errors.sector && ( + {errors.sector} + )} +
+
+ + {/* Site */} +
+ +
+ { + setFormField((prev) => ({ ...prev, site: target.value })); + setErrors((prev) => ({ ...prev, site: '' })); + }} + /> + {errors.site && {errors.site}} +
+
+ + {/* Latitude */} +
+ +
+ { + const value = target.value === '' ? 0 : Number(target.value); + setFormField((prev) => ({ ...prev, lat: value })); + setErrors((prev) => ({ ...prev, lat: '' })); + }} + /> + {errors.lat && {errors.lat}} +
+
+ + {/* Longitude */} +
+ +
+ { + const value = target.value === '' ? 0 : Number(target.value); + setFormField((prev) => ({ ...prev, lng: value })); + setErrors((prev) => ({ ...prev, lng: '' })); + }} + /> + {errors.lng && {errors.lng}} +
+
+ + {/* Location */} +
+ +
+ { + setFormField((prev) => ({ ...prev, location: target.value })); + setErrors((prev) => ({ ...prev, location: '' })); + }} + /> + {errors.location && ( + {errors.location} + )} +
+
+ + {/* Submit Button */} +
+ +
+
+
+
+
+ ); +}; + +export { AddDialog }; \ No newline at end of file diff --git a/src/pages/sites/manage-sites/blocks/DeleteDialog.tsx b/src/pages/sites/manage-sites/blocks/DeleteDialog.tsx new file mode 100644 index 0000000..1004d86 --- /dev/null +++ b/src/pages/sites/manage-sites/blocks/DeleteDialog.tsx @@ -0,0 +1,92 @@ +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogDescription +} from '@/components/ui/dialog'; +import { useSitesContext } from '../hooks'; +import { Button } from '@/components/ui/button'; +import { Alert, useDataGrid } from '@/components'; +import { ChangeEvent, useCallback, useState } from 'react'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { EnforceSwitch } from '@/components/switch'; + +const API_URL = apiConfig.service_master_data; + +const DeleteDialog = () => { + const { showDeleteDialog, handleDeleteDialog, selectedSites } = useSitesContext(); + const { reload } = useDataGrid(); + const [enforce, setEnforce] = useState(false); + + const { DeleteData } = useCallApi(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + /* actions */ + const doDeleteData = useCallback(async () => { + const response = await DeleteData(`${API_URL}/site-points/delete/${selectedSites?.id}/false`, { + id: selectedSites?.id + }); + if (response?.status) { + setAlert((prev) => ({ ...prev, show: false, message: '' })); + handleDeleteDialog(false, null); + toast.success('Success Delete Sites'); + reload(); + const createActivity = { + module: 'Manage Sites', + description: `Delete Sites => ${selectedSites}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); + } else { + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + }, [selectedSites, DeleteData, handleDeleteDialog, reload, enforce]); + + return ( + handleDeleteDialog(open, null)}> + + + + + +

Are you sure?

+ you will delete this data! + {/*
+ + ) => { + setEnforce(e.target.checked); + }} + /> +
*/} +
+ {alert.show && ( + +

{alert.message}

+
+ )} +
+ + + + +
+
+ ); +}; + +export { DeleteDialog }; diff --git a/src/pages/sites/manage-sites/blocks/EditDialog.tsx b/src/pages/sites/manage-sites/blocks/EditDialog.tsx new file mode 100644 index 0000000..2ed3d93 --- /dev/null +++ b/src/pages/sites/manage-sites/blocks/EditDialog.tsx @@ -0,0 +1,261 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { useSitesContext } from '../hooks'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import { apiConfig } from '@/config/api.config'; +import { KeenIcon, useDataGrid } from '@/components'; +import { toast } from 'sonner'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { + initialStateCreateSites, + validateFormCreateSites +} from './Types'; + +const API_URL = apiConfig.service_master_data; + +const EditDialog = () => { + const parentRef = useRef(null); + const { showEditDialog, selectedSites, handleEditDialog } = useSitesContext(); + const { reload } = useDataGrid(); + const { PutData } = useCallApi(); + const [isSubmitting, setIsSubmitting] = useState(false); + + const [errors, setErrors] = useState>({}); + const [formField, setFormField] = useState(initialStateCreateSites); + + const resetForm = () => { + setFormField(initialStateCreateSites); + setErrors({}); + }; + + /* actions */ + const doUpdateSites = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + + if (!validateFormCreateSites(formField, setErrors, 'update')) { + setIsSubmitting(false); + return; + } + + try { + const response = await PutData(`${API_URL}/site-points/update/${selectedSites?.id}`, { + ...formField + }); + + if (response?.status) { + resetForm(); + handleEditDialog(false, null); + toast.success('Success Update Site'); + reload(); + const createActivity = { + module: 'Manage Sites', + description: `Edit Site => ${formField.location}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); + } else { + toast.error(response?.message); + } + } catch (error) { + toast.error('Something went wrong, please try again.'); + } finally { + setIsSubmitting(false); + } + }, + [selectedSites, formField] + ); + + useEffect(() => { + if (showEditDialog === false) { + resetForm(); + } + }, [showEditDialog]); + + useEffect(() => { + if (selectedSites) { + setFormField((prev) => ({ + ...prev, + cell: selectedSites.cell ?? '', + sector: selectedSites.sector ?? '', + site: selectedSites.site ?? '', + lat: selectedSites.lat ?? 0, + lng: selectedSites.lng ?? 0, + location: selectedSites.location ?? '' + })); + } + }, [selectedSites]); + + return ( + handleEditDialog(open, null)}> + + + + +
+
+

Site - Update

+
+
+
handleEditDialog(false, null)} + > + +
+
+
+ +
+
+
+ {/* Cell */} +
+ +
+ { + setFormField((prev) => ({ ...prev, cell: target.value })); + setErrors((prev) => ({ ...prev, cell: '' })); + }} + /> + {errors.cell && ( + {errors.cell} + )} +
+
+ + {/* Sector */} +
+ +
+ { + setFormField((prev) => ({ ...prev, sector: target.value })); + setErrors((prev) => ({ ...prev, sector: '' })); + }} + /> + {errors.sector && ( + {errors.sector} + )} +
+
+ + {/* Site */} +
+ +
+ { + setFormField((prev) => ({ ...prev, site: target.value })); + setErrors((prev) => ({ ...prev, site: '' })); + }} + /> + {errors.site && ( + {errors.site} + )} +
+
+ + {/* Latitude */} +
+ +
+ { + const value = target.value === '' ? 0 : Number(target.value); + setFormField((prev) => ({ ...prev, lat: value })); + setErrors((prev) => ({ ...prev, lat: '' })); + }} + /> + {errors.lat && ( + {errors.lat} + )} +
+
+ + {/* Longitude */} +
+ +
+ { + const value = target.value === '' ? 0 : Number(target.value); + setFormField((prev) => ({ ...prev, lng: value })); + setErrors((prev) => ({ ...prev, lng: '' })); + }} + /> + {errors.lng && ( + {errors.lng} + )} +
+
+ + {/* Location */} +
+ +
+ { + setFormField((prev) => ({ ...prev, location: target.value })); + setErrors((prev) => ({ ...prev, location: '' })); + }} + /> + {errors.location && ( + {errors.location} + )} +
+
+ +
+ +
+
+
+
+
+
+
+ ); +}; + +export { EditDialog }; \ No newline at end of file diff --git a/src/pages/sites/manage-sites/blocks/ListToolBar.tsx b/src/pages/sites/manage-sites/blocks/ListToolBar.tsx new file mode 100644 index 0000000..c7b436b --- /dev/null +++ b/src/pages/sites/manage-sites/blocks/ListToolBar.tsx @@ -0,0 +1,76 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useSitesContext } from '../hooks'; +import { Button } from '@/components/ui/button'; +import { useEffect, useState } from 'react'; + +const ListToolBar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog } = useSitesContext(); + const [searchValue, setSearchValue] = useState( + (table.getColumn('cell')?.getFilterValue() as string) ?? '' + ); + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + handleSearch(); + } + }; + + const handleSearch = () => { + table.getColumn('cell')?.setFilterValue(searchValue); + table.setPageIndex(0); + }; + + useEffect(() => { + const timer = setTimeout(() => { + table.getColumn('cell')?.setFilterValue(searchValue); + table.setPageIndex(0); + }, 200); + return () => clearTimeout(timer); + }, [searchValue, table]); + + return ( +
+
+
+
+ + {/* + + */} +
+
+ + + + +
+
+
+
+ ); +}; + +export { ListToolBar }; diff --git a/src/pages/sites/manage-sites/blocks/Types.ts b/src/pages/sites/manage-sites/blocks/Types.ts new file mode 100644 index 0000000..d97cfe2 --- /dev/null +++ b/src/pages/sites/manage-sites/blocks/Types.ts @@ -0,0 +1,69 @@ +import { toast } from 'sonner'; + +export interface CreateSitesrParams { + cell: string; + sector: string; + site: string; + lat: number; + lng: number; + location: string; +} + +export const initialStateCreateSites: { + cell: string; + sector: string; + site: string; + lat: number; + lng: number; + location: string; +} = { + cell: '', + sector: '', + site: '', + lat: 0, + lng: 0, + location: '', +}; + +export const validateFormCreateSites = ( + formField: typeof initialStateCreateSites, + setErrors: React.Dispatch>>, + mode: 'create' | 'update' = 'create' +) => { + const requiredFields = + mode === 'create' + ? [ + { key: 'cell', label: 'Cell' }, + { key: 'sector', label: 'Sector' }, + { key: 'site', label: 'Site' }, + { key: 'lat', label: 'Lat' }, + { key: 'lng', label: 'Longitude' }, + { key: 'lat', label: 'Latitude' } + ] + : [ + { key: 'cell', label: 'Cell' }, + { key: 'sector', label: 'Sector' }, + { key: 'site', label: 'Site' }, + { key: 'lat', label: 'Lat' }, + { key: 'lng', label: 'Longitude' }, + { key: 'lat', label: 'Latitude' } + ]; + + const newErrors: Record = {}; + let isValid = true; + + requiredFields.forEach(({ key, label }) => { + if ( + formField[key as keyof typeof formField] === '' || + formField[key as keyof typeof formField] === null || + formField[key as keyof typeof formField] === undefined + ) { + newErrors[key] = `${label} is required`; + toast.error(`${label} is required`); + isValid = false; + } + }); + + setErrors(newErrors); + return isValid; +}; diff --git a/src/pages/sites/manage-sites/blocks/index.ts b/src/pages/sites/manage-sites/blocks/index.ts new file mode 100644 index 0000000..b95c907 --- /dev/null +++ b/src/pages/sites/manage-sites/blocks/index.ts @@ -0,0 +1,2 @@ +export * from './ListToolBar'; +export * from './EditDialog'; diff --git a/src/pages/sites/manage-sites/hooks/ManageSitesContext.tsx b/src/pages/sites/manage-sites/hooks/ManageSitesContext.tsx new file mode 100644 index 0000000..5040455 --- /dev/null +++ b/src/pages/sites/manage-sites/hooks/ManageSitesContext.tsx @@ -0,0 +1,246 @@ +import React, { createContext, useCallback, useEffect, useMemo, useState } from 'react'; +import { apiConfig } from '@/config/api.config'; +import { Toaster } from '@/components/ui/sonner'; +import { ColumnDef } from '@tanstack/react-table'; +import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; +import { EnforceSwitch } from '@/components/switch'; +import { ListToolBar } from '../blocks'; +import { useCallApi } from '@/hooks'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu'; +import { MoreHorizontal, MoreVertical, Pencil, QrCode, Trash } from 'lucide-react'; +import GenerateQr from '@/pages/account/home/user-profile/blocks/GenerateQr'; +import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog'; + +// Objek data lengkap satu site (dipakai untuk Edit, Delete, dan QR) +interface SelectedSites { + id: string; + cell: string; + sector: string; + site: string; + lat: number; + lng: number; + location: string; +} + +interface ContextProps { + showSearchDialog: boolean; + handleSearchDialog: (show: boolean) => void; + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_sites: SelectedSites | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + showDeleteDialog: boolean; + handleDeleteDialog: (show: boolean, selected_sites: SelectedSites | null) => void; + selectedSites: SelectedSites | null; + showQr: boolean; + setShowQr: React.Dispatch>; +} + +const initialProps: ContextProps = { + showSearchDialog: false, + handleSearchDialog: (show: boolean) => { }, + showEditDialog: false, + handleEditDialog: () => { }, + showAddDialog: false, + handleAddDialog: () => { }, + showDeleteDialog: false, + handleDeleteDialog: () => { }, + selectedSites: null, + showQr: false, + setShowQr: () => { } +}; + +const ManageSitesContext = createContext(initialProps); + +const API_URL = apiConfig.service_master_data; + +const ManageSitesContextProvider = ({ children }: { children: React.ReactNode }) => { + /* state */ + const [showEditDialog, setShowEditDialog] = useState(false); + const [showSearchDialog, setShowSearchDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [showQr, setShowQr] = useState(false); + const [selectedSites, setselectedSites] = useState(null); + const { GetData } = useCallApi(); + + /* action */ + const handleSearchDialog = useCallback((show: boolean) => { + setShowSearchDialog(show); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_sites: SelectedSites | null) => { + setselectedSites(show ? selected_sites : null); + setShowEditDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleDeleteDialog = useCallback((show: boolean, selected_sites: SelectedSites | null) => { + setselectedSites(show ? selected_sites : null); + setShowDeleteDialog(show); + }, []); + + /* Data Grid Options */ + const columns = useMemo[]>( + () => [ + { + accessorKey: 'cell', + id: 'cell', + header: ({ column }) => , + enableSorting: true, + enableHiding: false + }, + { + accessorKey: 'sector', + id: 'sector', + header: ({ column }) => , + enableSorting: true, + enableHiding: false + }, + { + accessorKey: 'site', + id: 'site', + header: ({ column }) => , + enableSorting: true, + enableHiding: false + }, + { + accessorKey: 'lat', + id: 'lat', + header: ({ column }) => , + enableSorting: true, + enableHiding: false + }, + { + accessorKey: 'lng', + id: 'lng', + header: ({ column }) => , + enableSorting: true, + enableHiding: false + }, + { + accessorKey: 'location', + id: 'location', + header: ({ column }) => , + enableSorting: true, + enableHiding: false + }, + { + id: 'actions', + enableSorting: false, + enableHiding: false, + header: ({ column }) => , + cell: (data: any) => { + const row = data.row.original; + + return ( + <> + + + + + + { + setShowQr(true); + setselectedSites(row); + }} + > + + + handleEditDialog(true, row)}> + + Edit + + handleDeleteDialog(true, row)}> + + Delete + + + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleEditDialog, handleDeleteDialog] + ); + + const doGetListData = async (page: number, limit: number, sorting: any, filter: any) => { + const USER_TABLE_COLUMNS = ['cell', 'sector', 'site', 'lat', 'long', 'location']; + + // ➕ Tambahkan prefix ke field dari tabel Users + const mappedSorting = sorting.map((sort: any) => ({ + ...sort, + id: USER_TABLE_COLUMNS.includes(sort.id) ? `${sort.id}` : sort.id + })); + + const orderField = mappedSorting[0]?.id ?? 'location'; + const orderDirection = mappedSorting[0]?.desc === false ? 'DESC' : 'ASC'; + + filter = + filter.length == 0 + ? {} + : { 'cell': { like: `%${filter[0].value?.toLowerCase()}%` } }; + const response = await GetData(`${API_URL}/site-points/list`, { + limit: limit, + page: page + 1, + with_deleted: false, + order_field: orderField, + order_direction: orderDirection, + filter: JSON.stringify(filter) + }); + // console.log('response api:', response); + + return { data: response?.data.list, totalCount: response?.data.total_count }; + }; + + return ( + + } + layout={{ card: true }} + sorting={[{ id: 'created_at', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + doGetListData(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + + + ); +}; + +export { ManageSitesContextProvider, ManageSitesContext }; +export type { SelectedSites }; \ No newline at end of file diff --git a/src/pages/sites/manage-sites/hooks/index.ts b/src/pages/sites/manage-sites/hooks/index.ts new file mode 100644 index 0000000..16b9747 --- /dev/null +++ b/src/pages/sites/manage-sites/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './ManageSitesContext'; +export * from './useManageSitesContext'; diff --git a/src/pages/sites/manage-sites/hooks/useManageSitesContext.tsx b/src/pages/sites/manage-sites/hooks/useManageSitesContext.tsx new file mode 100644 index 0000000..3fd42d4 --- /dev/null +++ b/src/pages/sites/manage-sites/hooks/useManageSitesContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageSitesContext } from './ManageSitesContext'; + +const useSitesContext = () => { + const context = useContext(ManageSitesContext); + + if (!context) throw new Error('useSitesContext must be used within AuthProvider'); + + return context; +}; + +export { useSitesContext }; diff --git a/src/pages/sites/manage-sites/index.ts b/src/pages/sites/manage-sites/index.ts new file mode 100644 index 0000000..4dda4a3 --- /dev/null +++ b/src/pages/sites/manage-sites/index.ts @@ -0,0 +1 @@ +export * from './ManageSitesPage'; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index d5d08fc..2947f12 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -8,6 +8,8 @@ import { ErrorsRouting } from '@/errors'; import DashboardHomePage from '@/pages/dashboards/home/DashboardHomePage'; import ManageUserPage from '@/pages/settings/user/manage-user/ManageUserPage'; +import ManageSitesPage from '@/pages/sites/manage-sites/ManageSitesPage'; + import Transaction from '@/pages/transaction/history-transaction/Transaction'; import ApprovalTransaction from '@/pages/transaction/approval-transaction/ApprovalTransaction'; import TransactionTopup from '@/pages/transaction/topup/TransactionTopup'; @@ -66,6 +68,8 @@ const AppRoutingSetup = (): ReactElement => { } /> } /> + } /> + {/* } /> } /> } />