From f0eb8803b2abeca9fb93310d2c0d42eb8008999f Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 3 Mar 2025 08:57:36 +0700 Subject: [PATCH 01/15] fetch get data municipio, postoadms, sucos on table --- .../master/postoadms/PostoAdmsMaster.tsx | 2 + .../master/postoadms/blocks/ListToolbar.tsx | 2 +- .../master/postoadms/blocks/SearchDialog.tsx | 176 ++++++++++++++++++ .../hooks/ManagePostoAdmsContext.tsx | 18 +- src/pages/master/sucos/blocks/ListToolbar.tsx | 0 src/pages/master/sucos/hooks/ManageSucos.tsx | 66 +++++++ 6 files changed, 259 insertions(+), 5 deletions(-) create mode 100644 src/pages/master/postoadms/blocks/SearchDialog.tsx create mode 100644 src/pages/master/sucos/blocks/ListToolbar.tsx create mode 100644 src/pages/master/sucos/hooks/ManageSucos.tsx diff --git a/src/pages/master/postoadms/PostoAdmsMaster.tsx b/src/pages/master/postoadms/PostoAdmsMaster.tsx index a8e00d4..829f5dd 100644 --- a/src/pages/master/postoadms/PostoAdmsMaster.tsx +++ b/src/pages/master/postoadms/PostoAdmsMaster.tsx @@ -1,3 +1,4 @@ +import SearchDialog from './blocks/SearchDialog'; import { ManagePostoAdmsContextProvider } from './hooks/ManagePostoAdmsContext'; import { Container, DataGridInner } from '@/components'; @@ -9,6 +10,7 @@ const PostoAdmsMaster = () => {
+ ); diff --git a/src/pages/master/postoadms/blocks/ListToolbar.tsx b/src/pages/master/postoadms/blocks/ListToolbar.tsx index a05e53c..ee55545 100644 --- a/src/pages/master/postoadms/blocks/ListToolbar.tsx +++ b/src/pages/master/postoadms/blocks/ListToolbar.tsx @@ -37,7 +37,7 @@ const ListToolbar = () => { className="h-7.5 text-[0.8rem]" onClick={() => handleSearchDialog(true)} > - Search Postu Administrativo + Search Sucos
diff --git a/src/pages/master/postoadms/blocks/SearchDialog.tsx b/src/pages/master/postoadms/blocks/SearchDialog.tsx new file mode 100644 index 0000000..6644165 --- /dev/null +++ b/src/pages/master/postoadms/blocks/SearchDialog.tsx @@ -0,0 +1,176 @@ +import { useRef, useState } from 'react'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Alert, KeenIcon } from '@/components'; +import { Button } from '@/components/ui/button'; +import { apiConfig } from '@/config/api.config'; +import axios from 'axios'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { useManagePostoAdmsContext } from '../hooks/useManagePostoAdmsContext'; + +interface SucosProps { + id: number; + name: string; +} + +const API_URL = apiConfig.service_master_data; + +const SearchDialog = () => { + const parentRef = useRef(null); + const { showSearchDialog, handleSearchDialog, postoAdms } = useManagePostoAdmsContext(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + id: 0, + name: '' + }; + + const [formField, setFormField] = useState(initialState); + const resetForm = () => { + setFormField(initialState); + }; + const [sucos, setSucos] = 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}/postoadms/sucos/${id}`); + + if (response.data.status) { + setSucos(response.data.data); + setIsFound(true); + console.log('Found postoadms: ', response.data.data); + } else { + setSucos([]); + 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); + setSucos([]); + }; + // console.log(municipios); + return ( + handleSearchDialog(open)}> + + + + +
+
+

+ Search Sucos +

+
+
+
{ + handleSearchDialog(false); + resetForm(); + }} + > + +
+
+
+ +
+ {alert.show && ( + + {alert.message} + + )} +
+
+
+ + + +
+ + {isFound && sucos.length > 0 && ( +
+

Postu Administravo:

+
+
+ + {sucos.map((suco) => suco.name).join(', ')} + +
+
+ )} + +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default SearchDialog; diff --git a/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx b/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx index 2b8858f..973817c 100644 --- a/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx +++ b/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx @@ -14,6 +14,7 @@ interface PostoAdmsProps { } interface ContextProps { + postoAdms: PostoAdmsProps[]; showSearchDialog: boolean; handleSearchDialog: (show: boolean) => void; showEditDialog: boolean; @@ -33,6 +34,7 @@ interface ContextProps { } const initialProps: ContextProps = { + postoAdms: [], showSearchDialog: false, handleSearchDialog: (show: boolean) => {}, showEditDialog: false, @@ -49,6 +51,7 @@ const ManagePostoAdmsContext = createContext(initialProps); const API_URL = apiConfig.service_master_data; const ManagePostoAdmsContextProvider = ({ children }: { children: React.ReactNode }) => { + const [postoAdms, setPostoAdms] = useState([]); const [showSearchDialog, setShowSearchDialog] = useState(false); const [showAddDialog, setShowAddDialog] = useState(false); const [showEditDialog, setShowEditDialog] = useState(false); @@ -121,10 +124,10 @@ const ManagePostoAdmsContextProvider = ({ children }: { children: React.ReactNod ); 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}`, { + 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}/postoadms/list`, { params: { limit, page: page + 1, @@ -134,7 +137,13 @@ const ManagePostoAdmsContextProvider = ({ children }: { children: React.ReactNod } }); console.log(response.data); - return { data: response.data.data, totalCount: response.data.data.total_count }; + // const sortedList = response.data.data.list.sort((a: PostoAdmsProps, b: PostoAdmsProps) => { + // if (a.name < b.name) return -1; + // if (a.name > b.name) return 1; + // return 0; + // }); + setPostoAdms(response.data.data.list); + return { data: response.data.data.list, totalCount: response.data.data.total_count }; } catch (error) { console.error('Error fetching Postu Administrativo', error); } @@ -143,6 +152,7 @@ const ManagePostoAdmsContextProvider = ({ children }: { children: React.ReactNod return ( void; + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_sucos: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + showDeleteDialog: boolean; + handleDeleteDialog: (show: boolean, selected_sucos: string | null) => void; + selectedSucos: string | null; + getSucosLists: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: any, + order_direction: any + ) => Promise<{ data: SucosProps[]; totalCount: number } | undefined>; +} + +const initialProps: ContextProps = { + sucos: [], + showSearchDialog: false, + handleSearchDialog: () => {}, + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + showDeleteDialog: false, + handleDeleteDialog: () => {}, + selectedSucos: null, + getSucosLists: async () => undefined +}; + +const ManageSucosContext = createContext(initialProps); +const API_URL = apiConfig.service_master_data; + +const ManageSucosContextProvider = ({ children }: { children: React.ReactNode }) => { + const [sucos, setSucos] = useState([]); + const [showSearchDialog, setShowSearchDialog] = useState(false); + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [selectedSucos, setSelectedSucos] = useState(null); + + const handleSearchDialog = useCallback((show: boolean) => { + setShowSearchDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const hanldeEditDialog = useCallback((show: boolean, selected_sucos: string | null) => { + setSelectedSucos(show ? selected_sucos : null); + setShowEditDialog(show); + }, []) +}; From a8a270ba7fcf2d398e2619cb2d95ea5bbf238c1d Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 3 Mar 2025 11:59:32 +0700 Subject: [PATCH 02/15] add crud municipio --- .../master/aldeias/blocks/ListToolbar.tsx | 0 src/pages/master/municipios/Municipios.tsx | 4 + .../master/municipios/blocks/AddDialog.tsx | 68 +++++++- .../master/municipios/blocks/DeleteDialog.tsx | 87 ++++++++++ .../master/municipios/blocks/EditDialog.tsx | 152 ++++++++++++++++++ .../master/municipios/blocks/SearchDialog.tsx | 8 +- .../hooks/ManageMunicipiosContext.tsx | 41 +++-- 7 files changed, 338 insertions(+), 22 deletions(-) create mode 100644 src/pages/master/aldeias/blocks/ListToolbar.tsx create mode 100644 src/pages/master/municipios/blocks/DeleteDialog.tsx create mode 100644 src/pages/master/municipios/blocks/EditDialog.tsx diff --git a/src/pages/master/aldeias/blocks/ListToolbar.tsx b/src/pages/master/aldeias/blocks/ListToolbar.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/master/municipios/Municipios.tsx b/src/pages/master/municipios/Municipios.tsx index 0538fbd..820900c 100644 --- a/src/pages/master/municipios/Municipios.tsx +++ b/src/pages/master/municipios/Municipios.tsx @@ -2,6 +2,8 @@ import { Container, DataGridInner } from '@/components'; import { ManageMunicipiosProvider } from './hooks/ManageMunicipiosContext'; import AddDialog from './blocks/AddDialog'; import SearchDialog from './blocks/SearchDialog'; +import EditDialog from './blocks/EditDialog'; +import DeleteDialog from './blocks/DeleteDialog'; const Municipios = () => { return ( @@ -12,6 +14,8 @@ const Municipios = () => {
+ + diff --git a/src/pages/master/municipios/blocks/AddDialog.tsx b/src/pages/master/municipios/blocks/AddDialog.tsx index 2916f94..9a9a342 100644 --- a/src/pages/master/municipios/blocks/AddDialog.tsx +++ b/src/pages/master/municipios/blocks/AddDialog.tsx @@ -1,4 +1,4 @@ -import React, { useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useManageMunicipiosContext } from '../hooks/useManageMunicipiosContext'; import { Dialog, @@ -8,19 +8,32 @@ import { DialogHeader, DialogTitle } from '@/components/ui/dialog'; -import { Alert, KeenIcon } from '@/components'; +import { Alert, KeenIcon, useDataGrid } from '@/components'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; +import axios from 'axios'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +import { getAuth, useAuthContext } from '@/auth'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; + +const API_URL = apiConfig.service_master_data; const AddDialog = () => { const parentRef = useRef(null); - const { showAddDialog, handleAddDialog } = useManageMunicipiosContext(); + const { reload } = useDataGrid(); + const { PostData } = useCallApi(); + const parsedUser = getAuth()?.user; + const { showAddDialog, handleAddDialog, selectedMunicipios } = useManageMunicipiosContext(); const [alert, setAlert] = useState({ show: false, message: '' }); const initialState = { - name: '' + name: '', + created_by: '', + created_at: '' }; const [formField, setFormField] = useState(initialState); @@ -28,6 +41,31 @@ const AddDialog = () => { setFormField(initialState); }; + const doCreateMunicipio = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + const response = await PostData(`${API_URL}/municipios/create`, formField); + + if (response?.status) { + handleAddDialog(false); + resetForm(); + toast.success('Municipio created successfully!'); + reload(); + // const createActivity = { + // module: 'Manage Municipio', + // description: `Create Municipio => ${selectedMunicipios}`, + // action: 'C' + // }; + + // doSaveLogActivity(createActivity); + } else { + toast.error('Failed to create municipio.'); + setAlert({ show: true, message: 'Failed to create municipio. Please try again.' }); + } + }, + [formField] + ); + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); @@ -36,6 +74,14 @@ const AddDialog = () => { return; } + // setFormField({ + // name: formField.name, + // created_by: parsedUser.email, + // created_at: formattedTime + // }); + + // doCreateMunicipio(e); + console.log(parsedUser.email); console.log(formField); setAlert({ show: false, message: '' }); }; @@ -44,6 +90,18 @@ const AddDialog = () => { setFormField(initialState); }; + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + if (showAddDialog) { + setFormField({ + name: formField.name, + created_by: parsedUser.email, + created_at: formattedTime + }); + } + }, [showAddDialog]); + return ( handleAddDialog(open)}> @@ -96,7 +154,7 @@ const AddDialog = () => { Reset diff --git a/src/pages/master/municipios/blocks/DeleteDialog.tsx b/src/pages/master/municipios/blocks/DeleteDialog.tsx new file mode 100644 index 0000000..0605ab5 --- /dev/null +++ b/src/pages/master/municipios/blocks/DeleteDialog.tsx @@ -0,0 +1,87 @@ +import { Alert, useDataGrid } from '@/components'; +import { useManageMunicipiosContext } from '../hooks/useManageMunicipiosContext'; +import { ChangeEvent, useCallback, useState } from 'react'; +import axios from 'axios'; +import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { toast } from 'sonner'; +import { Dialog, DialogContent, DialogFooter, DialogHeader } from '@/components/ui/dialog'; +import { EnforceSwitch } from '@/components/switch'; +import { Button } from '@/components/ui/button'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; + +const API_URL = apiConfig.service_master_data; + +const DeleteDialog = () => { + const { showDeleteDialog, handleDeleteDialog, selectedMunicipios, municipios } = + useManageMunicipiosContext(); + const { reload } = useDataGrid(); + const { DeleteData } = useCallApi(); + const [enforce, setEnforce] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const doDeleteMunicipio = useCallback(async () => { + const response = await DeleteData( + `${API_URL}/municipios/delete/${selectedMunicipios}/${enforce}`, + { + id: selectedMunicipios + } + ); + + if (response?.status) { + setAlert((prev) => ({ ...prev, show: false, message: '' })); + handleDeleteDialog(false, null); + toast.success('Success Delete Municipio'); + reload(); + // const createActivity = { + // module: 'Manage Municipio', + // description: `Delete Municipio => ${selectedMunicipios}`, + // action: 'D' + // }; + + // doSaveLogActivity(createActivity); + } else { + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + }, [selectedMunicipios, enforce]); + + return ( + handleDeleteDialog(open, null)}> + + + +

Are you sure?

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

{alert.message}

+
+ )} +
+ + + + +
+
+ ); +}; + +export default DeleteDialog; diff --git a/src/pages/master/municipios/blocks/EditDialog.tsx b/src/pages/master/municipios/blocks/EditDialog.tsx new file mode 100644 index 0000000..afb9c3c --- /dev/null +++ b/src/pages/master/municipios/blocks/EditDialog.tsx @@ -0,0 +1,152 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useManageMunicipiosContext } from '../hooks/useManageMunicipiosContext'; +import { Alert, useDataGrid } from '@/components'; +import axios from 'axios'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import { getAuth, useAuthContext } from '@/auth'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; + +const API_URL = apiConfig.service_master_data; + +const EditDialog = () => { + const parentRef = useRef(null); + const { showEditDialog, handleEditDialog, selectedMunicipios, municipios } = + useManageMunicipiosContext(); + const { reload } = useDataGrid(); + const { PutData } = useCallApi(); + const parsedUser = getAuth()?.user; + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const initialState = { + name: '', + updated_by: '', + updated_at: '' + }; + + const [formField, setFormField] = useState(initialState); + + const resetForm = () => { + setFormField(initialState); + }; + + const doUpdateMunicipios = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + const response = await PutData( + `${API_URL}/municipios/update/${selectedMunicipios}`, + formField + ); + + if (response?.status) { + handleEditDialog(false, null); + resetForm(); + toast.success('Success update municipio'); + reload(); + // const createActivity = { + // module: 'Manage Municipio', + // description: `Edit Municipio => ${selectedMunicipios}`, + // action: 'U' + // }; + + // doSaveLogActivity(createActivity); + } else { + toast.error('Failed update user'); + setAlert({ show: true, message: 'Failed to update municipio. Please try again.' }); + } + }, + [selectedMunicipios, formField] + ); + + const handleUpdate = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '') { + setAlert({ show: true, message: 'Please fill name field.' }); + return; + } + + // setFormField({ + // name: formField.name, + // created_by: parsedUser.email, + // created_at: formattedTime + // }); + + doUpdateMunicipios(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + // const doFetchMunicipios = useCallback(async (id: string) => { + // const response = await axios.get(`${API_URL}/municipios/${id}`); + // }, []); + + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + if (selectedMunicipios) { + setFormField({ + name: formField.name, + updated_by: parsedUser.email, + updated_at: formattedTime + }); + } + }, [selectedMunicipios]); + + // console.log(selectedMunicipios); + return ( + handleEditDialog(open, null)}> + + + Municipios - Update + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+ +
+
+
+
+
+
+
+ ); +}; + +export default EditDialog; diff --git a/src/pages/master/municipios/blocks/SearchDialog.tsx b/src/pages/master/municipios/blocks/SearchDialog.tsx index 4ba1a62..42c1ddf 100644 --- a/src/pages/master/municipios/blocks/SearchDialog.tsx +++ b/src/pages/master/municipios/blocks/SearchDialog.tsx @@ -21,7 +21,7 @@ import { SelectValue } from '@/components/ui/select'; -interface PostoAdms { +interface PostoAdmsProps { id: number; name: string; } @@ -44,7 +44,7 @@ const SearchDialog = () => { const resetForm = () => { setFormField(initialState); }; - const [postoadms, setPostoadms] = useState([]); + const [postoadms, setPostoadms] = useState([]); const [isFound, setIsFound] = useState(false); const handleSubmit = async (e: React.FormEvent) => { @@ -62,7 +62,7 @@ const SearchDialog = () => { if (response.data.status) { setPostoadms(response.data.data); setIsFound(true); - console.log('Found postoadms: ', response.data.data); + // console.log('Found postoadms: ', response.data.data); } else { setPostoadms([]); setIsFound(false); @@ -147,7 +147,7 @@ const SearchDialog = () => { {isFound && postoadms.length > 0 && (
-

Postu Administravo:

+

Sucos:


diff --git a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx index 808f57e..4d95cf4 100644 --- a/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx +++ b/src/pages/master/municipios/hooks/ManageMunicipiosContext.tsx @@ -1,4 +1,4 @@ -import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; import { Toaster } from '@/components/ui/sonner'; import { apiConfig } from '@/config/api.config'; import { ColumnDef } from '@tanstack/react-table'; @@ -127,18 +127,29 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = header: ({ column }) => , enableSorting: false, enableHiding: false, - meta: { - headerClassName: 'w-[100px], text-center', - cellClassName: 'text-center' + cell: (data) => { + const row = data.row.original; + return ( + <> + + + + ); }, - cell: (info) => ( - - ) + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } } ], [handleEditDialog, handleDeleteDialog] @@ -158,6 +169,11 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = } }); console.log(response.data); + // const sortedList = response.data.data.list.sort((a: MunicipiosProps, b: MunicipiosProps) => { + // if (a.name < b.name) return -1; + // if (a.name > b.name) return 1; + // return 0; + // }); setMunicipios(response.data.data.list); return { data: response?.data.data.list, totalCount: response?.data.data.total_count }; } catch (error) { @@ -210,7 +226,6 @@ const ManageMunicipiosProvider = ({ children }: { children: React.ReactNode }) = console.error('Error restoring municipios', error); } }; - console.log(municipios); return ( Date: Sat, 1 Mar 2025 16:17:29 +0700 Subject: [PATCH 03/15] env --- .env.development | 2 +- package-lock.json | 135 +++++++++++++++++++++++--- src/auth/providers/JWTProvider.tsx | 2 +- src/pages/currency/ManageCurrency.tsx | 53 ++++++++++ src/pages/currency/index.ts | 1 + src/pages/group/ManageGroup.tsx | 53 ++++++++++ src/pages/group/index.ts | 1 + yarn.lock | 67 ++++++------- 8 files changed, 263 insertions(+), 51 deletions(-) create mode 100644 src/pages/currency/ManageCurrency.tsx create mode 100644 src/pages/currency/index.ts create mode 100644 src/pages/group/ManageGroup.tsx create mode 100644 src/pages/group/index.ts diff --git a/.env.development b/.env.development index 58a088c..0eeb323 100644 --- a/.env.development +++ b/.env.development @@ -2,6 +2,6 @@ VITE_APP_NAME=tpay-dashboard-tl VITE_APP_VERSION=1=9.1.1 GENERATE_SOURCEMAP=false -VITE_APP_API_URL=https://tpay.shiblysolution.id/api +VITE_APP_API_URL=https://tpay.shiblysolution.id/api/d # VITE_APP_API_URL=http://127.0.0.1:4003/api VITE_ENV=development diff --git a/package-lock.json b/package-lock.json index 4757023..f1ffce0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -103,6 +103,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, "engines": { "node": ">=10" }, @@ -1586,6 +1587,7 @@ "cpu": [ "ppc64" ], + "dev": true, "optional": true, "os": [ "aix" @@ -1601,6 +1603,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "android" @@ -1616,6 +1619,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "android" @@ -1631,6 +1635,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "android" @@ -1646,6 +1651,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -1661,6 +1667,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -1676,6 +1683,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "freebsd" @@ -1691,6 +1699,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "freebsd" @@ -1706,6 +1715,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1721,6 +1731,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1736,6 +1747,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1751,6 +1763,7 @@ "cpu": [ "loong64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1766,6 +1779,7 @@ "cpu": [ "mips64el" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1781,6 +1795,7 @@ "cpu": [ "ppc64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1796,6 +1811,7 @@ "cpu": [ "riscv64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1811,6 +1827,7 @@ "cpu": [ "s390x" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1826,6 +1843,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -1841,6 +1859,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "netbsd" @@ -1856,6 +1875,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "openbsd" @@ -1871,6 +1891,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "sunos" @@ -1886,6 +1907,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -1901,6 +1923,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "win32" @@ -1916,6 +1939,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -2418,6 +2442,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -2434,6 +2459,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, "engines": { "node": ">=12" }, @@ -2445,6 +2471,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "engines": { "node": ">=12" }, @@ -2455,12 +2482,14 @@ "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2477,6 +2506,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2491,6 +2521,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2839,6 +2870,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "optional": true, "engines": { "node": ">=14" @@ -3857,6 +3889,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "android" @@ -3869,6 +3902,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "android" @@ -3881,6 +3915,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -3893,6 +3928,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "darwin" @@ -3905,6 +3941,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "freebsd" @@ -3917,6 +3954,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "freebsd" @@ -3929,6 +3967,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -3941,6 +3980,7 @@ "cpu": [ "arm" ], + "dev": true, "optional": true, "os": [ "linux" @@ -3953,6 +3993,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -3965,6 +4006,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -3977,6 +4019,7 @@ "cpu": [ "ppc64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -3989,6 +4032,7 @@ "cpu": [ "riscv64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4001,6 +4045,7 @@ "cpu": [ "s390x" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4013,6 +4058,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4025,6 +4071,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4037,6 +4084,7 @@ "cpu": [ "arm64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -4049,6 +4097,7 @@ "cpu": [ "ia32" ], + "dev": true, "optional": true, "os": [ "win32" @@ -4061,6 +4110,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -4165,7 +4215,8 @@ "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true }, "node_modules/@types/geojson": { "version": "7946.0.14", @@ -4228,7 +4279,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", - "devOptional": true, + "dev": true, "dependencies": { "@types/react": "*" } @@ -4565,12 +4616,14 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -4596,7 +4649,8 @@ "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true }, "node_modules/argparse": { "version": "2.0.1", @@ -4697,6 +4751,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, "engines": { "node": ">=8" }, @@ -4708,6 +4763,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -4799,6 +4855,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, "engines": { "node": ">= 6" } @@ -4850,6 +4907,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4873,6 +4931,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4966,6 +5025,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, "engines": { "node": ">= 6" } @@ -4999,6 +5059,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -5213,12 +5274,14 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true }, "node_modules/dom-helpers": { "version": "5.2.1", @@ -5232,7 +5295,8 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true }, "node_modules/electron-to-chromium": { "version": "1.5.48", @@ -5275,6 +5339,7 @@ "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -5736,6 +5801,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -5805,6 +5871,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -5889,6 +5956,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -6101,6 +6169,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -6160,12 +6229,14 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -6288,6 +6359,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, "engines": { "node": ">=10" } @@ -6439,6 +6511,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6453,6 +6526,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -6475,6 +6549,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -6531,6 +6606,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -6584,6 +6660,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, "engines": { "node": ">= 6" } @@ -6662,7 +6739,8 @@ "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true }, "node_modules/parent-module": { "version": "1.0.1", @@ -6713,6 +6791,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "engines": { "node": ">=8" } @@ -6726,6 +6805,7 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -6740,7 +6820,8 @@ "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -6770,6 +6851,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -6778,6 +6860,7 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, "engines": { "node": ">= 6" } @@ -6786,6 +6869,7 @@ "version": "8.4.49", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7163,6 +7247,7 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -7179,6 +7264,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, "dependencies": { "camelcase-css": "^2.0.1" }, @@ -7225,6 +7311,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7259,6 +7346,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, "engines": { "node": ">=14" }, @@ -7270,6 +7358,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "dev": true, "bin": { "yaml": "bin.mjs" }, @@ -7305,6 +7394,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7329,6 +7419,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -8036,6 +8127,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, "dependencies": { "pify": "^2.3.0" } @@ -8044,6 +8136,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -8121,6 +8214,7 @@ "version": "4.24.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.2.tgz", "integrity": "sha512-do/DFGq5g6rdDhdpPq5qb2ecoczeK6y+2UAjdJ5trjQJj5f1AiVdLRWRc9A9/fFukfvJRgM0UXzxBIYMovm5ww==", + "dev": true, "dependencies": { "@types/estree": "1.0.6" }, @@ -8220,6 +8314,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -8231,6 +8326,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "engines": { "node": ">=8" } @@ -8256,6 +8352,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "engines": { "node": ">=14" }, @@ -8306,6 +8403,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8331,6 +8429,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -8457,6 +8556,7 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -8478,6 +8578,7 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -8628,6 +8729,7 @@ "version": "3.4.14", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", + "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -8672,6 +8774,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -8690,6 +8793,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, "dependencies": { "any-promise": "^1.0.0" } @@ -8698,6 +8802,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -8746,7 +8851,8 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true }, "node_modules/tslib": { "version": "2.8.0", @@ -8780,7 +8886,7 @@ "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "devOptional": true, + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8922,6 +9028,7 @@ "version": "5.4.11", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -8997,6 +9104,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -9048,6 +9156,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", diff --git a/src/auth/providers/JWTProvider.tsx b/src/auth/providers/JWTProvider.tsx index 79e7153..1bb944e 100644 --- a/src/auth/providers/JWTProvider.tsx +++ b/src/auth/providers/JWTProvider.tsx @@ -73,7 +73,7 @@ const AuthProvider = ({ children }: PropsWithChildren) => { const login = async (username: string, password: string) => { try { const { data: auth } = await axios - .post(LOGIN_URL, { username, password }) + .post(LOGIN_URL, { username, password }) // , { headers: { 'Access-Control-Allow-Origin': "*" }} .then((response) => response.data); saveAuth({ ...auth.token, id: auth.user.id, role_name: auth.role_name, user: auth.user }); diff --git a/src/pages/currency/ManageCurrency.tsx b/src/pages/currency/ManageCurrency.tsx new file mode 100644 index 0000000..40f10eb --- /dev/null +++ b/src/pages/currency/ManageCurrency.tsx @@ -0,0 +1,53 @@ +import { useState, useEffect, useCallback } from 'react'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import Paper from '@mui/material/Paper'; + +function createData(name: string, calories: number, fat: number, carbs: number, protein: number) { + return { name, calories, fat, carbs, protein }; +} + +const rows = [ + createData('Frozen yoghurt', 159, 6.0, 24, 4.0), + createData('Ice cream sandwich', 237, 9.0, 37, 4.3), + createData('Eclair', 262, 16.0, 24, 6.0), + createData('Cupcake', 305, 3.7, 67, 4.3), + createData('Gingerbread', 356, 16.0, 49, 3.9) +]; + +const ManageCurrencyPage = () => { + return ( + + + + + Dessert (100g serving) + Calories + Fat (g) + Carbs (g) + Protein (g) + + + + {rows.map((row) => ( + + + {row.name} + + {row.calories} + {row.fat} + {row.carbs} + {row.protein} + + ))} + +
+
+ ); +}; + +export { ManageCurrencyPage }; diff --git a/src/pages/currency/index.ts b/src/pages/currency/index.ts new file mode 100644 index 0000000..b6f3fc5 --- /dev/null +++ b/src/pages/currency/index.ts @@ -0,0 +1 @@ +export * from './ManageCurrency'; diff --git a/src/pages/group/ManageGroup.tsx b/src/pages/group/ManageGroup.tsx new file mode 100644 index 0000000..337bd02 --- /dev/null +++ b/src/pages/group/ManageGroup.tsx @@ -0,0 +1,53 @@ +import { useState, useEffect, useCallback } from 'react'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import Paper from '@mui/material/Paper'; + +function createData(name: string, calories: number, fat: number, carbs: number, protein: number) { + return { name, calories, fat, carbs, protein }; +} + +const rows = [ + createData('Frozen yoghurt', 159, 6.0, 24, 4.0), + createData('Ice cream sandwich', 237, 9.0, 37, 4.3), + createData('Eclair', 262, 16.0, 24, 6.0), + createData('Cupcake', 305, 3.7, 67, 4.3), + createData('Gingerbread', 356, 16.0, 49, 3.9) +]; + +const ManageGroupPage = () => { + return ( + + + + + Dessert (100g serving) + Calories + Fat (g) + Carbs (g) + Protein (g) + + + + {rows.map((row) => ( + + + {row.name} + + {row.calories} + {row.fat} + {row.carbs} + {row.protein} + + ))} + +
+
+ ); +}; + +export { ManageGroupPage }; diff --git a/src/pages/group/index.ts b/src/pages/group/index.ts new file mode 100644 index 0000000..5625013 --- /dev/null +++ b/src/pages/group/index.ts @@ -0,0 +1 @@ +export * from './ManageGroup'; diff --git a/yarn.lock b/yarn.lock index a0396a9..4ff4d38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,7 +39,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz" integrity sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.25.2": +"@babel/core@^7.25.2": version "7.26.0" resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz" integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== @@ -564,7 +564,7 @@ resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz" integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== -"@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.13.3", "@emotion/react@^11.4.1", "@emotion/react@^11.5.0": +"@emotion/react@^11.13.3": version "11.13.3" resolved "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz" integrity sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg== @@ -594,7 +594,7 @@ resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz" integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== -"@emotion/styled@^11.13.0", "@emotion/styled@^11.3.0": +"@emotion/styled@^11.13.0": version "11.13.0" resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz" integrity sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA== @@ -631,10 +631,10 @@ resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz" integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== -"@esbuild/darwin-arm64@0.21.5": +"@esbuild/win32-x64@0.21.5": version "0.21.5" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.1" @@ -704,7 +704,7 @@ resolved "https://registry.npmjs.org/@faker-js/faker/-/faker-9.1.0.tgz" integrity sha512-GJvX9iM9PBtKScJVlXQ0tWpihK3i0pha/XAhzQa1hPK/ILLa1Wq3I63Ij7lRtqTwmdTxRCyrUhLC5Sly9SLbug== -"@firebase/app@^0.10.15", "@firebase/app@0.x": +"@firebase/app@^0.10.15": version "0.10.15" resolved "https://registry.npmjs.org/@firebase/app/-/app-0.10.15.tgz" integrity sha512-he6qlG3pmwL+LHdG/BrSMBQeJzzutciq4fpXN3lGa1uSwYSijJ24VtakS/bP2X9SiDf8jGywJ4u+OgXAenJsNg== @@ -1573,10 +1573,10 @@ resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz" integrity sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA== -"@rollup/rollup-darwin-arm64@4.24.2": +"@rollup/rollup-win32-x64-msvc@4.24.2": version "4.24.2" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.2.tgz" - integrity sha512-/UhrIxobHYCBfhi5paTkUDQ0w+jckjRZDZ1kcBL132WeHZQ6+S5v9jQPVGLVrLbNUebdIRpIt00lQ+4Z7ys4Rg== + resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.2.tgz" + integrity sha512-2mLH46K1u3r6uwc95hU+OR9q/ggYMpnS7pSp83Ece1HUQgF9Nh/QwTK5rcgbFnV9j+08yBrU5sA/P0RK2MSBNA== "@tanstack/query-core@5.59.20": version "5.59.20" @@ -1665,7 +1665,7 @@ dependencies: "@types/geojson" "*" -"@types/node@^18.0.0 || >=20.0.0", "@types/node@^22.9.0", "@types/node@>=12.12.47", "@types/node@>=13.7.0": +"@types/node@^22.9.0", "@types/node@>=12.12.47", "@types/node@>=13.7.0": version "22.9.0" resolved "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz" integrity sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ== @@ -1682,7 +1682,7 @@ resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz" integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== -"@types/react-dom@*", "@types/react-dom@^18.3.1": +"@types/react-dom@^18.3.1": version "18.3.1" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ== @@ -1703,7 +1703,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0", "@types/react@^17.0.0 || ^18.0.0", "@types/react@^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react@^18.3.12", "@types/react@16 || 17 || 18": +"@types/react@*", "@types/react@^18.3.12", "@types/react@16 || 17 || 18": version "18.3.12" resolved "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz" integrity sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw== @@ -1745,7 +1745,7 @@ natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@^8.0.0 || ^8.0.0-alpha.0", "@typescript-eslint/parser@^8.14.0", "@typescript-eslint/parser@8.14.0": +"@typescript-eslint/parser@^8.14.0", "@typescript-eslint/parser@8.14.0": version "8.14.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz" integrity sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA== @@ -1854,7 +1854,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.12.0: +acorn@^8.12.0: version "8.14.0" resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== @@ -1904,7 +1904,7 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -apexcharts@^3.41.0, apexcharts@3.52.0: +apexcharts@3.52.0: version "3.52.0" resolved "https://registry.npmjs.org/apexcharts/-/apexcharts-3.52.0.tgz" integrity sha512-7dg0ADKs8AA89iYMZMe2sFDG0XK5PfqllKV9N+i3hKHm3vEtdhwz8AlXGm+/b0nJ6jKiaXsqci5LfVxNhtB+dA== @@ -2020,7 +2020,7 @@ broadcast-channel@^3.4.1: rimraf "3.0.2" unload "2.2.0" -browserslist@^4.23.1, browserslist@^4.23.3, browserslist@^4.24.0, "browserslist@>= 4.21.0": +browserslist@^4.23.1, browserslist@^4.23.3, browserslist@^4.24.0: version "4.24.2" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz" integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== @@ -2234,12 +2234,12 @@ cssjanus@^2.0.1: resolved "https://registry.npmjs.org/cssjanus/-/cssjanus-2.3.0.tgz" integrity sha512-ZZXXn51SnxRxAZ6fdY7mBDPmA4OZd83q/J9Gdqz3YmE9TUq+9tZl+tdOnCi7PpNygI6PEkehj9rgifv5+W8a5A== -csstype@^3.0.10, csstype@^3.0.2, csstype@^3.1.3, csstype@3.1.3: +csstype@^3.0.2, csstype@^3.1.3, csstype@3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -"date-fns@^2.28.0 || ^3.0.0", date-fns@^3.0.0: +date-fns@^3.0.0: version "3.6.0" resolved "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz" integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== @@ -2381,7 +2381,7 @@ escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-prettier@*, eslint-config-prettier@^9.1.0: +eslint-config-prettier@^9.1.0: version "9.1.0" resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz" integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== @@ -2422,7 +2422,7 @@ eslint-visitor-keys@^4.1.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz" integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== -"eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.13.0, eslint@>=7, eslint@>=7.0.0, eslint@>=8.0.0: +eslint@^9.13.0: version "9.13.0" resolved "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz" integrity sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA== @@ -2620,11 +2620,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -2877,7 +2872,7 @@ jackspeak@^3.1.2: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" -jiti@*, jiti@^1.18.2, jiti@^1.21.0: +jiti@^1.18.2, jiti@^1.21.0: version "1.21.6" resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz" integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== @@ -2941,7 +2936,7 @@ kolorist@^1.8.0: resolved "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz" integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== -leaflet@^1.9.0, leaflet@^1.9.4: +leaflet@^1.9.4: version "1.9.4" resolved "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz" integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA== @@ -3612,7 +3607,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^ resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8, postcss@^8.0.0, postcss@^8.0.3, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.4, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.43, postcss@^8.4.49, postcss@^8.4.6, postcss@>=8.0.9: +postcss@^8.4.23, postcss@^8.4.43, postcss@^8.4.49: version "8.4.49" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz" integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== @@ -3642,7 +3637,7 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^3.3.3, prettier@>=3.0.0: +prettier@^3.3.3: version "3.3.3" resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz" integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== @@ -3713,7 +3708,7 @@ react-day-picker@^8.10.1: resolved "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz" integrity sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA== -"react-dom@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^18 || ^19 || ^19.0.0-rc", react-dom@^18.0.0, "react-dom@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react-dom@^18.3.1, "react-dom@>= 16.8.0", react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.0: +react-dom@^18.3.1: version "18.3.1" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -3877,7 +3872,7 @@ react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -"react@^16.3.0 || ^17.0.0 || ^18.0.0", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc", "react@^16.6.0 || ^17.0.0 || ^18.0.0", "react@^16.6.0 || 17 || 18", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^17.0.0 || ^18.0.0", "react@^17.0.0 || ^18.0.0 || ^19.0.0", "react@^18 || ^19", "react@^18 || ^19 || ^19.0.0-rc", react@^18.0.0, "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^18.3.1, "react@>= 16.8.0", react@>=0.13, react@>=16.3.0, react@>=16.6.0, react@>=16.8, react@>=16.8.0, "react@16.8 - 18": +react@^18.3.1: version "18.3.1" resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -4124,7 +4119,7 @@ stylis-plugin-rtl@^2.1.1: dependencies: cssjanus "^2.0.1" -stylis@^4.3.4, stylis@4.x: +stylis@^4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz" integrity sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now== @@ -4237,7 +4232,7 @@ tailwindcss-animate@^1.0.7: resolved "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz" integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA== -tailwindcss@^3.4.14, "tailwindcss@>=3.0.0 || insiders": +tailwindcss@^3.4.14: version "3.4.14" resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz" integrity sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA== @@ -4347,7 +4342,7 @@ typescript-eslint@^8.14.0: "@typescript-eslint/parser" "8.14.0" "@typescript-eslint/utils" "8.14.0" -"typescript@^4.7 || 5", typescript@^5.6.3, typescript@>=4.2.0: +typescript@^5.6.3: version "5.6.3" resolved "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz" integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== @@ -4415,7 +4410,7 @@ vite-plugin-windicss@^1.9.3: kolorist "^1.8.0" windicss "^3.5.6" -"vite@^2.0.1 || ^3.0.0 || ^4.0.0 || ^5.0.0", "vite@^4.2.0 || ^5.0.0", vite@^5.4.11: +vite@^5.4.11: version "5.4.11" resolved "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz" integrity sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q== From 7a67f04f19e91717d2abaf29755d3d8082c027d8 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 3 Mar 2025 16:42:36 +0700 Subject: [PATCH 04/15] update api --- .env.development | 2 +- src/pages/master/municipios/blocks/AddDialog.tsx | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.env.development b/.env.development index 0eeb323..58a088c 100644 --- a/.env.development +++ b/.env.development @@ -2,6 +2,6 @@ VITE_APP_NAME=tpay-dashboard-tl VITE_APP_VERSION=1=9.1.1 GENERATE_SOURCEMAP=false -VITE_APP_API_URL=https://tpay.shiblysolution.id/api/d +VITE_APP_API_URL=https://tpay.shiblysolution.id/api # VITE_APP_API_URL=http://127.0.0.1:4003/api VITE_ENV=development diff --git a/src/pages/master/municipios/blocks/AddDialog.tsx b/src/pages/master/municipios/blocks/AddDialog.tsx index 9a9a342..0db792b 100644 --- a/src/pages/master/municipios/blocks/AddDialog.tsx +++ b/src/pages/master/municipios/blocks/AddDialog.tsx @@ -49,8 +49,8 @@ const AddDialog = () => { if (response?.status) { handleAddDialog(false); resetForm(); - toast.success('Municipio created successfully!'); reload(); + toast.success('Municipio created successfully!'); // const createActivity = { // module: 'Manage Municipio', // description: `Create Municipio => ${selectedMunicipios}`, @@ -80,14 +80,15 @@ const AddDialog = () => { // created_at: formattedTime // }); - // doCreateMunicipio(e); + doCreateMunicipio(e); console.log(parsedUser.email); console.log(formField); setAlert({ show: false, message: '' }); }; const handleReset = () => { - setFormField(initialState); + resetForm(); + setAlert({ show: false, message: '' }); }; useEffect(() => { @@ -96,7 +97,7 @@ const AddDialog = () => { if (showAddDialog) { setFormField({ name: formField.name, - created_by: parsedUser.email, + created_by: parsedUser?.username, created_at: formattedTime }); } From 82daf90c8058f03d5d235f8a3463e96075dde3be Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 3 Mar 2025 21:38:20 +0700 Subject: [PATCH 05/15] update yarn lock set gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4e80c27..5ba73fa 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ lerna-debug.log* node_modules dist dist-ssr +yarn.lock *.local # Editor directories and files From 8758472b99ff281f2f463ddc9199295ccbeec1dc Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 4 Mar 2025 08:44:49 +0700 Subject: [PATCH 06/15] add crud postoadm --- .../master/postoadms/PostoAdmsMaster.tsx | 10 +- .../master/postoadms/blocks/AddDialog.tsx | 160 ++++++++++++++++++ .../master/postoadms/blocks/DeleteDialog.tsx | 77 +++++++++ .../master/postoadms/blocks/EditDialog.tsx | 149 ++++++++++++++++ .../hooks/ManagePostoAdmsContext.tsx | 35 ++-- 5 files changed, 418 insertions(+), 13 deletions(-) create mode 100644 src/pages/master/postoadms/blocks/AddDialog.tsx create mode 100644 src/pages/master/postoadms/blocks/DeleteDialog.tsx create mode 100644 src/pages/master/postoadms/blocks/EditDialog.tsx diff --git a/src/pages/master/postoadms/PostoAdmsMaster.tsx b/src/pages/master/postoadms/PostoAdmsMaster.tsx index 829f5dd..3ff1138 100644 --- a/src/pages/master/postoadms/PostoAdmsMaster.tsx +++ b/src/pages/master/postoadms/PostoAdmsMaster.tsx @@ -1,3 +1,6 @@ +import AddDialog from './blocks/AddDialog'; +import DeleteDialog from './blocks/DeleteDialog'; +import EditDialog from './blocks/EditDialog'; import SearchDialog from './blocks/SearchDialog'; import { ManagePostoAdmsContextProvider } from './hooks/ManagePostoAdmsContext'; import { Container, DataGridInner } from '@/components'; @@ -6,10 +9,15 @@ const PostoAdmsMaster = () => { return ( -

Postu Administrativo

+

+ Postu Administrativo +

+ + +
diff --git a/src/pages/master/postoadms/blocks/AddDialog.tsx b/src/pages/master/postoadms/blocks/AddDialog.tsx new file mode 100644 index 0000000..3849e1c --- /dev/null +++ b/src/pages/master/postoadms/blocks/AddDialog.tsx @@ -0,0 +1,160 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useManagePostoAdmsContext } from '../hooks/useManagePostoAdmsContext'; +import { Alert, KeenIcon, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { getAuth, useAuthContext } from '@/auth'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +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_master_data; + +const AddDialog = () => { + const parentRef = useRef(null); + const { showAddDialog, handleAddDialog } = useManagePostoAdmsContext(); + const { reload } = useDataGrid(); + const { PostData } = useCallApi(); + const parsedUser = getAuth()?.user; + + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const initialState = { + name: '', + municipio_id: 0, + created_by: '', + created_at: '' + }; + + const [formField, setFormField] = useState(initialState); + + const resetForm = () => { + setFormField(initialState); + setAlert({ show: false, message: '' }); + }; + + const doCreatePostoAdm = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + const response = await PostData(`${API_URL}/postoadms/create`, formField); + + if (response?.status) { + handleAddDialog(false); + resetForm(); + reload(); + toast.success('Posto Adm created successfully!'); + } else { + toast.error('Failed to create Posto Adm. Please try again.'); + setAlert({ show: true, message: 'Failed to create Posto Adm. Please try again.' }); + } + }, + [formField] + ); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '' || formField.municipio_id === 0) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + doCreatePostoAdm(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + // const handleReset = () => { + // resetForm(); + // setAlert({ show: false, message: '' }); + // }; + + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + if (showAddDialog) { + setFormField({ + ...formField, + created_by: parsedUser?.username, + created_at: formattedTime + }); + } + }, [showAddDialog]); + + return ( + handleAddDialog(open)}> + + + Postu Administrativo - Create + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + { + const value = parseInt(e.target.value, 10); + setFormField({ ...formField, municipio_id: isNaN(value) ? 0 : value }); + }} + /> +
+
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/master/postoadms/blocks/DeleteDialog.tsx b/src/pages/master/postoadms/blocks/DeleteDialog.tsx new file mode 100644 index 0000000..f969485 --- /dev/null +++ b/src/pages/master/postoadms/blocks/DeleteDialog.tsx @@ -0,0 +1,77 @@ +import { Alert, useDataGrid } from '@/components'; +import { useManagePostoAdmsContext } from '../hooks/useManagePostoAdmsContext'; +import { useCallApi } from '@/hooks'; +import { ChangeEvent, useCallback, useState } from 'react'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +import { Dialog, DialogContent, DialogFooter, DialogHeader } from '@/components/ui/dialog'; +import { EnforceSwitch } from '@/components/switch'; +import { Button } from '@/components/ui/button'; + +const API_URL = apiConfig.service_master_data; + +const DeleteDialog = () => { + const { showDeleteDialog, handleDeleteDialog, selectedPostoAdms } = useManagePostoAdmsContext(); + const { reload } = useDataGrid(); + const { DeleteData } = useCallApi(); + const [enforce, setEnforce] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const doDeletePostoAdm = useCallback(async () => { + const response = await DeleteData( + `${API_URL}/postoadms/delete/${selectedPostoAdms}/${enforce}`, + { + id: selectedPostoAdms + } + ); + + if (response?.status) { + setAlert((prev) => ({ ...prev, show: false, message: '' })); + handleDeleteDialog(false, null); + toast.success('Success Delete Posto Adm'); + reload(); + } else { + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + }, [selectedPostoAdms, enforce]); + + return ( + handleDeleteDialog(open, null)}> + + + +

Are you sure?

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

{alert.message}

+
+ )} +
+ + + + +
+
+ ); +}; + +export default DeleteDialog; diff --git a/src/pages/master/postoadms/blocks/EditDialog.tsx b/src/pages/master/postoadms/blocks/EditDialog.tsx new file mode 100644 index 0000000..05dc645 --- /dev/null +++ b/src/pages/master/postoadms/blocks/EditDialog.tsx @@ -0,0 +1,149 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useManagePostoAdmsContext } from '../hooks/useManagePostoAdmsContext'; +import { Alert, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { getAuth } from '@/auth'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +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_master_data; + +const EditDialog = () => { + const parentRef = useRef(null); + const { showEditDialog, handleEditDialog, selectedPostoAdms } = useManagePostoAdmsContext(); + const { reload } = useDataGrid(); + const { PutData } = useCallApi(); + const parsedUser = getAuth()?.user; + + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + name: '', + municipio_id: 0, + updated_by: '', + updated_at: '' + }; + const [formField, setFormField] = useState(initialState); + + const resetForm = () => { + setFormField(initialState); + setAlert({ show: false, message: '' }); + }; + + const doUpdatePostoAdm = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + const response = await PutData(`${API_URL}/postoadms/update/${selectedPostoAdms}`, formField); + + if (response?.status) { + handleEditDialog(false, null); + resetForm(); + toast.success('Success Update Posto Adm'); + reload(); + } else { + toast.error('Error Update Posto Adm'); + setAlert({ show: true, message: 'Failed to update posto adm. Please try again.' }); + } + }, + [selectedPostoAdms, formField] + ); + + const handleUpdate = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '' || formField.municipio_id === 0) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + doUpdatePostoAdm(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + + if (selectedPostoAdms) { + setFormField({ + ...formField, + updated_by: parsedUser?.username, + updated_at: formattedTime + }); + } + }, [selectedPostoAdms]); + + return ( + handleEditDialog(open, null)}> + + + Municipios - Update + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + { + const value = parseInt(e.target.value, 10); + setFormField({ ...formField, municipio_id: isNaN(value) ? 0 : value }); + }} + /> +
+
+ +
+ +
+
+
+
+
+
+
+ ); +}; + +export default EditDialog; diff --git a/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx b/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx index 973817c..971470b 100644 --- a/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx +++ b/src/pages/master/postoadms/hooks/ManagePostoAdmsContext.tsx @@ -1,4 +1,4 @@ -import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; import { Button } from '@/components/ui/button'; import { Toaster } from '@/components/ui/sonner'; import { apiConfig } from '@/config/api.config'; @@ -106,18 +106,29 @@ const ManagePostoAdmsContextProvider = ({ children }: { children: React.ReactNod header: ({ column }) => , enableSorting: false, enableHiding: false, - meta: { - headerClassName: 'w-[100px], text-center', - cellClassName: 'text-center' + cell: (data) => { + const row = data.row.original; + return ( + <> + + + + ); }, - cell: (info) => ( - - ) + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } } ], [handleEditDialog, handleDeleteDialog] From e34ee32d5a5cdab8bc8aa60caabb87c9377953f8 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 4 Mar 2025 11:16:52 +0700 Subject: [PATCH 07/15] update title edit form postoadm --- src/pages/master/postoadms/blocks/EditDialog.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/master/postoadms/blocks/EditDialog.tsx b/src/pages/master/postoadms/blocks/EditDialog.tsx index 05dc645..ff8bab4 100644 --- a/src/pages/master/postoadms/blocks/EditDialog.tsx +++ b/src/pages/master/postoadms/blocks/EditDialog.tsx @@ -91,7 +91,7 @@ const EditDialog = () => { handleEditDialog(open, null)}> - Municipios - Update + Posto Adm - Update @@ -106,7 +106,9 @@ const EditDialog = () => {
- + Date: Tue, 4 Mar 2025 13:23:27 +0700 Subject: [PATCH 08/15] add crud sucos --- src/pages/master/sucos/SucosMaster.tsx | 20 +- src/pages/master/sucos/blocks/AddDialog.tsx | 148 +++++++++++++ .../master/sucos/blocks/DeleteDialog.tsx | 74 +++++++ src/pages/master/sucos/blocks/EditDialog.tsx | 152 +++++++++++++ src/pages/master/sucos/blocks/ListToolbar.tsx | 64 ++++++ src/pages/master/sucos/hooks/ManageSucos.tsx | 66 ------ .../master/sucos/hooks/ManageSucosContext.tsx | 200 ++++++++++++++++++ .../sucos/hooks/useManageSucosContext.tsx | 12 ++ 8 files changed, 665 insertions(+), 71 deletions(-) create mode 100644 src/pages/master/sucos/blocks/AddDialog.tsx create mode 100644 src/pages/master/sucos/blocks/DeleteDialog.tsx create mode 100644 src/pages/master/sucos/blocks/EditDialog.tsx delete mode 100644 src/pages/master/sucos/hooks/ManageSucos.tsx create mode 100644 src/pages/master/sucos/hooks/ManageSucosContext.tsx create mode 100644 src/pages/master/sucos/hooks/useManageSucosContext.tsx diff --git a/src/pages/master/sucos/SucosMaster.tsx b/src/pages/master/sucos/SucosMaster.tsx index 6feede3..62911a4 100644 --- a/src/pages/master/sucos/SucosMaster.tsx +++ b/src/pages/master/sucos/SucosMaster.tsx @@ -1,10 +1,20 @@ +import { Container, DataGridInner } from '@/components'; +import { ManageSucosContextProvider } from './hooks/ManageSucosContext'; +import AddDialog from './blocks/AddDialog'; +import EditDialog from './blocks/EditDialog'; + const SucosMaster = () => { return ( -
-
-

Sucos Master Data

-
-
+ + +

Sucos

+
+ +
+ + +
+
); }; diff --git a/src/pages/master/sucos/blocks/AddDialog.tsx b/src/pages/master/sucos/blocks/AddDialog.tsx new file mode 100644 index 0000000..eed5cd9 --- /dev/null +++ b/src/pages/master/sucos/blocks/AddDialog.tsx @@ -0,0 +1,148 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useManageSucosContext } from '../hooks/useManageSucosContext'; +import { Alert, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { getAuth } from '@/auth'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +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_master_data; + +const AddDialog = () => { + const parentRef = useRef(null); + const { showAddDialog, handleAddDialog } = useManageSucosContext(); + const { reload } = useDataGrid(); + const { PostData } = useCallApi(); + const parsedUser = getAuth()?.user; + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + name: '', + posto_adm_id: 0, + created_by: '', + created_at: '' + }; + const [formField, setFormField] = useState(initialState); + + const resetForm = () => { + setFormField(initialState); + setAlert({ show: false, message: '' }); + }; + + const doCreateSucos = useCallback(async (e: React.FormEvent) => { + e.preventDefault(); + const response = await PostData(`${API_URL}/sucos/create`, formField); + + if (response?.status) { + resetForm(); + handleAddDialog(false); + reload(); + toast.success('Success Create Sucos'); + } else { + toast.error('Failed Create Sucos'); + setAlert({ show: true, message: response?.message }); + } + }, []); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '' || formField.posto_adm_id === 0) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + // doCreateSucos(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + if (showAddDialog) { + setFormField({ + ...formField, + created_by: parsedUser.username, + created_at: formattedTime + }); + } + }, [showAddDialog]); + + return ( + handleAddDialog(open)}> + + + Sucos - Create + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + { + const value = parseInt(e.target.value, 10); + setFormField({ ...formField, posto_adm_id: isNaN(value) ? 0 : value }); + }} + /> +
+
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/master/sucos/blocks/DeleteDialog.tsx b/src/pages/master/sucos/blocks/DeleteDialog.tsx new file mode 100644 index 0000000..d5aa4ce --- /dev/null +++ b/src/pages/master/sucos/blocks/DeleteDialog.tsx @@ -0,0 +1,74 @@ +import { apiConfig } from '@/config/api.config'; +import { useManageSucosContext } from '../hooks/useManageSucosContext'; +import { ChangeEvent, useCallback, useState } from 'react'; +import { useCallApi } from '@/hooks'; +import { Alert, useDataGrid } from '@/components'; +import { toast } from 'sonner'; +import { Dialog, DialogContent, DialogFooter, DialogHeader } from '@/components/ui/dialog'; +import { EnforceSwitch } from '@/components/switch'; +import { Button } from '@/components/ui/button'; + +const API_URL = apiConfig.service_master_data; + +const DeleteDialog = () => { + const { showDeleteDialog, handleDeleteDialog, selectedSucos } = useManageSucosContext(); + const { reload } = useDataGrid(); + const { DeleteData } = useCallApi(); + const [enforce, setEnforce] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const doDeleteSucos = useCallback(async () => { + const response = await DeleteData(`${API_URL}/sucos/delete/${selectedSucos}/${enforce}`, { + id: selectedSucos + }); + + if (response?.status) { + setAlert((prev) => ({ ...prev, show: false, message: '' })); + handleDeleteDialog(false, null); + toast.success('Success Delete Sucos'); + reload(); + } else { + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + }, [selectedSucos, enforce]); + + return ( + handleDeleteDialog(open, null)}> + + + +

Are you sure?

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

{alert.message}

+
+ )} +
+ + + + +
+
+ ); +}; + +export default DeleteDialog; diff --git a/src/pages/master/sucos/blocks/EditDialog.tsx b/src/pages/master/sucos/blocks/EditDialog.tsx new file mode 100644 index 0000000..342c621 --- /dev/null +++ b/src/pages/master/sucos/blocks/EditDialog.tsx @@ -0,0 +1,152 @@ +import { Alert, useDataGrid } from '@/components'; +import { useManageSucosContext } from '../hooks/useManageSucosContext'; +import { useCallApi } from '@/hooks'; +import { getAuth } from '@/auth'; +import React, { useCallback, useEffect, useState } from 'react'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +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_master_data; + +const EditDialog = () => { + const { showEditDialog, handleEditDialog, selectedSucos } = useManageSucosContext(); + const { reload } = useDataGrid(); + const { PutData } = useCallApi(); + const parsedUser = getAuth()?.user; + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + name: '', + posto_adm_id: 0, + updated_by: '', + updated_at: '' + }; + const [formField, setFormField] = useState(initialState); + + const resetForm = () => { + setFormField(initialState); + setAlert({ + show: false, + message: '' + }); + }; + + const doUpdateSucos = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + const response = await PutData(`${API_URL}/sucos/update/${selectedSucos}`, formField); + + if (response?.status) { + resetForm(); + handleEditDialog(false, null); + toast.success('Success Update Sucos'); + reload(); + } else { + toast.error('Failed Update Sucos'); + setAlert({ show: true, message: 'Failed Update Sucos. Please try again' }); + } + }, + [selectedSucos, formField] + ); + + const handleUpdate = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '' || formField.posto_adm_id === 0) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + // doUpdateSucos(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + if (showEditDialog) { + setFormField({ + ...formField, + updated_by: parsedUser.username, + updated_at: formattedTime + }); + } + }, [showEditDialog]); + + return ( + handleEditDialog(open, null)}> + + + Sucos - Update + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + { + const value = parseInt(e.target.value, 10); + setFormField({ ...formField, posto_adm_id: isNaN(value) ? 0 : value }); + }} + /> +
+
+ +
+ +
+
+
+
+
+
+
+ ); +}; + +export default EditDialog; diff --git a/src/pages/master/sucos/blocks/ListToolbar.tsx b/src/pages/master/sucos/blocks/ListToolbar.tsx index e69de29..f0a23b8 100644 --- a/src/pages/master/sucos/blocks/ListToolbar.tsx +++ b/src/pages/master/sucos/blocks/ListToolbar.tsx @@ -0,0 +1,64 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useManageSucosContext } from '../hooks/useManageSucosContext'; +import { Button } from '@/components/ui/button'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog, handleSearchDialog } = useManageSucosContext(); + + return ( +
+
+
+
+ + + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/master/sucos/hooks/ManageSucos.tsx b/src/pages/master/sucos/hooks/ManageSucos.tsx deleted file mode 100644 index cf878fa..0000000 --- a/src/pages/master/sucos/hooks/ManageSucos.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { apiConfig } from '@/config/api.config'; -import React, { createContext, useCallback, useState } from 'react'; - -interface SucosProps { - id: number; - name: string; -} - -interface ContextProps { - sucos: SucosProps[]; - showSearchDialog: boolean; - handleSearchDialog: (show: boolean) => void; - showEditDialog: boolean; - handleEditDialog: (show: boolean, selected_sucos: string | null) => void; - showAddDialog: boolean; - handleAddDialog: (show: boolean) => void; - showDeleteDialog: boolean; - handleDeleteDialog: (show: boolean, selected_sucos: string | null) => void; - selectedSucos: string | null; - getSucosLists: ( - limit: number, - page: number, - with_deleted: boolean, - order_field: any, - order_direction: any - ) => Promise<{ data: SucosProps[]; totalCount: number } | undefined>; -} - -const initialProps: ContextProps = { - sucos: [], - showSearchDialog: false, - handleSearchDialog: () => {}, - showEditDialog: false, - handleEditDialog: () => {}, - showAddDialog: false, - handleAddDialog: () => {}, - showDeleteDialog: false, - handleDeleteDialog: () => {}, - selectedSucos: null, - getSucosLists: async () => undefined -}; - -const ManageSucosContext = createContext(initialProps); -const API_URL = apiConfig.service_master_data; - -const ManageSucosContextProvider = ({ children }: { children: React.ReactNode }) => { - const [sucos, setSucos] = useState([]); - const [showSearchDialog, setShowSearchDialog] = useState(false); - const [showEditDialog, setShowEditDialog] = useState(false); - const [showAddDialog, setShowAddDialog] = useState(false); - const [showDeleteDialog, setShowDeleteDialog] = useState(false); - const [selectedSucos, setSelectedSucos] = useState(null); - - const handleSearchDialog = useCallback((show: boolean) => { - setShowSearchDialog(show); - }, []); - - const handleAddDialog = useCallback((show: boolean) => { - setShowAddDialog(show); - }, []); - - const hanldeEditDialog = useCallback((show: boolean, selected_sucos: string | null) => { - setSelectedSucos(show ? selected_sucos : null); - setShowEditDialog(show); - }, []) -}; diff --git a/src/pages/master/sucos/hooks/ManageSucosContext.tsx b/src/pages/master/sucos/hooks/ManageSucosContext.tsx new file mode 100644 index 0000000..4e8628b --- /dev/null +++ b/src/pages/master/sucos/hooks/ManageSucosContext.tsx @@ -0,0 +1,200 @@ +import { DataGridColumnHeader, DataGridProvider, KeenIcon } 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 React, { createContext, useCallback, useMemo, useState } from 'react'; +import ListToolbar from '../blocks/ListToolbar'; + +interface SucosProps { + id: number; + name: string; +} + +interface ContextProps { + sucos: SucosProps[]; + showSearchDialog: boolean; + handleSearchDialog: (show: boolean) => void; + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_sucos: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + showDeleteDialog: boolean; + handleDeleteDialog: (show: boolean, selected_sucos: string | null) => void; + selectedSucos: string | null; + getSucosLists: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: any, + order_direction: any + ) => Promise<{ data: SucosProps[]; totalCount: number } | undefined>; +} + +const initialProps: ContextProps = { + sucos: [], + showSearchDialog: false, + handleSearchDialog: () => {}, + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + showDeleteDialog: false, + handleDeleteDialog: () => {}, + selectedSucos: null, + getSucosLists: async () => undefined +}; + +const ManageSucosContext = createContext(initialProps); +const API_URL = apiConfig.service_master_data; + +const ManageSucosContextProvider = ({ children }: { children: React.ReactNode }) => { + const [sucos, setSucos] = useState([]); + const [showSearchDialog, setShowSearchDialog] = useState(false); + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [selectedSucos, setSelectedSucos] = useState(null); + const { GetData } = useCallApi(); + + const handleSearchDialog = useCallback((show: boolean) => { + setShowSearchDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_sucos: string | null) => { + setSelectedSucos(show ? selected_sucos : null); + setShowEditDialog(show); + }, []); + + const handleDeleteDialog = useCallback((show: boolean, selected_sucos: string | null) => { + setSelectedSucos(show ? selected_sucos : null); + setShowDeleteDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.sucos_id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + } + }, + { + accessorFn: (row) => row.sucos_name, + id: 'sucos_name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => row.posto_name, + id: 'posto_name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + id: 'actions', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + cell: (data) => { + const row = data.row.original; + return ( + <> + + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleEditDialog, handleDeleteDialog] + ); + + const getSucosLists = 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 GetData(`${API_URL}/sucos/list`, { + limit, + page: page + 1, + with_deleted: true, + order_field: sorting[0].id, + order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', + filter: JSON.stringify(filter) + }); + console.log(response?.data); + setSucos(response?.data.list); + // console.log(sucos); + return { data: response?.data.list, totalCount: response?.data.total_count }; + } catch (error) { + console.error('Error fetching Sucos', error); + } + }; + + return ( + + + + } + layout={{ card: true }} + sorting={[{ id: 'id', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + getSucosLists(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + + + ); +}; + +export { ManageSucosContextProvider, ManageSucosContext }; +export type { SucosProps }; diff --git a/src/pages/master/sucos/hooks/useManageSucosContext.tsx b/src/pages/master/sucos/hooks/useManageSucosContext.tsx new file mode 100644 index 0000000..194575a --- /dev/null +++ b/src/pages/master/sucos/hooks/useManageSucosContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageSucosContext } from './ManageSucosContext'; + +const useManageSucosContext = () => { + const context = useContext(ManageSucosContext); + + if (!context) throw new Error('useManageSucosContext must be used within AuthProvider'); + + return context; +}; + +export { useManageSucosContext }; From 141bad71e78eabc6d39b3f74490098962836d980 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 4 Mar 2025 13:23:42 +0700 Subject: [PATCH 09/15] add required field --- src/pages/master/postoadms/blocks/EditDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/master/postoadms/blocks/EditDialog.tsx b/src/pages/master/postoadms/blocks/EditDialog.tsx index ff8bab4..2407e1d 100644 --- a/src/pages/master/postoadms/blocks/EditDialog.tsx +++ b/src/pages/master/postoadms/blocks/EditDialog.tsx @@ -121,7 +121,7 @@ const EditDialog = () => {
Date: Tue, 4 Mar 2025 13:47:10 +0700 Subject: [PATCH 10/15] add crud aldeias --- src/pages/master/aldeias/AldeiasMaster.tsx | 22 +- src/pages/master/aldeias/blocks/AddDialog.tsx | 152 ++++++++++++++ .../master/aldeias/blocks/DeleteDialog.tsx | 74 +++++++ .../master/aldeias/blocks/EditDialog.tsx | 148 +++++++++++++ .../master/aldeias/blocks/ListToolbar.tsx | 62 ++++++ .../aldeias/hooks/ManageAldeiasContext.tsx | 196 ++++++++++++++++++ .../aldeias/hooks/useManageAldeiasContext.tsx | 12 ++ 7 files changed, 661 insertions(+), 5 deletions(-) create mode 100644 src/pages/master/aldeias/blocks/AddDialog.tsx create mode 100644 src/pages/master/aldeias/blocks/DeleteDialog.tsx create mode 100644 src/pages/master/aldeias/blocks/EditDialog.tsx create mode 100644 src/pages/master/aldeias/hooks/ManageAldeiasContext.tsx create mode 100644 src/pages/master/aldeias/hooks/useManageAldeiasContext.tsx diff --git a/src/pages/master/aldeias/AldeiasMaster.tsx b/src/pages/master/aldeias/AldeiasMaster.tsx index 851f5f1..7ec7c77 100644 --- a/src/pages/master/aldeias/AldeiasMaster.tsx +++ b/src/pages/master/aldeias/AldeiasMaster.tsx @@ -1,10 +1,22 @@ +import { Container, DataGridInner } from '@/components'; +import { ManageAldeiasContextProvider } from './hooks/ManageAldeiasContext'; +import AddDialog from './blocks/AddDialog'; +import EditDialog from './blocks/EditDialog'; +import DeleteDialog from './blocks/DeleteDialog'; + const AldeiasMaster = () => { return ( -
-
-

Aldeias Master Data

-
-
+ + +

Aldeias

+
+ +
+ + + +
+
); }; diff --git a/src/pages/master/aldeias/blocks/AddDialog.tsx b/src/pages/master/aldeias/blocks/AddDialog.tsx new file mode 100644 index 0000000..66286dd --- /dev/null +++ b/src/pages/master/aldeias/blocks/AddDialog.tsx @@ -0,0 +1,152 @@ +import { apiConfig } from '@/config/api.config'; +import { useManageAldeiasContext } from '../hooks/useManageAldeiasContext'; +import { Alert, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { getAuth } from '@/auth'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { toast } from 'sonner'; +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_master_data; + +const AddDialog = () => { + const parentRef = useRef(null); + const { showAddDialog, handleAddDialog } = useManageAldeiasContext(); + const { reload } = useDataGrid(); + const { PostData } = useCallApi(); + const parsedUser = getAuth()?.user; + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + name: '', + sucos: 0, + created_by: '', + created_at: '' + }; + const [formField, setFormField] = useState(initialState); + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + + const resetForm = () => { + setFormField(initialState); + setAlert({ show: false, message: '' }); + }; + + const doCreateAldeias = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + const response = await PostData(`${API_URL}/aldeias/create`, formField); + + if (response?.status) { + resetForm(); + handleAddDialog(false); + toast.success('Success Create Aldeias'); + reload(); + } else { + toast.error('Error Create Aldeias'); + setAlert({ show: true, message: 'Failed to create Aldeias. Please try again.' }); + } + }, + [formField] + ); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '' || formField.sucos === 0) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + // doCreateAldeias(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + useEffect(() => { + if (showAddDialog) { + setFormField({ + ...formField, + created_by: parsedUser.username, + created_at: formattedTime + }); + } + }, [formattedTime]); + + return ( + handleAddDialog(open)}> + + + Aldeias - Create + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + { + const value = parseInt(e.target.value, 10); + setFormField({ ...formField, sucos: isNaN(value) ? 0 : value }); + }} + /> +
+
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/master/aldeias/blocks/DeleteDialog.tsx b/src/pages/master/aldeias/blocks/DeleteDialog.tsx new file mode 100644 index 0000000..44fc4c1 --- /dev/null +++ b/src/pages/master/aldeias/blocks/DeleteDialog.tsx @@ -0,0 +1,74 @@ +import { apiConfig } from '@/config/api.config'; +import { useManageAldeiasContext } from '../hooks/useManageAldeiasContext'; +import { Alert, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { ChangeEvent, useCallback, useState } from 'react'; +import { toast } from 'sonner'; +import { Dialog, DialogContent, DialogFooter, DialogHeader } from '@/components/ui/dialog'; +import { EnforceSwitch } from '@/components/switch'; +import { Button } from '@/components/ui/button'; + +const API_URL = apiConfig.service_master_data; +const DeleteDialog = () => { + const { showDeleteDialog, handleDeleteDialog, selectedAldeias } = useManageAldeiasContext(); + const { reload } = useDataGrid(); + const { DeleteData } = useCallApi(); + const [enforce, setEnforce] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }) + + const doDeleteAldeias = useCallback(async () => { + const response = await DeleteData(`${API_URL}/aldeias/delete/${selectedAldeias}/${enforce}`, { + id: selectedAldeias + }); + + if (response?.status) { + setAlert((prev) => ({ ...prev, show: false, message: '' })); + handleDeleteDialog(false, null); + toast.success('Success Delete Aldeias'); + reload(); + } else { + toast.error('Failed Delete Aldeias'); + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + }, [selectedAldeias, enforce]); + + return ( + handleDeleteDialog(open, null)}> + + + +

Are you sure?

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

{alert.message}

+
+ )} +
+ + + + +
+
+ ); +}; + +export default DeleteDialog; diff --git a/src/pages/master/aldeias/blocks/EditDialog.tsx b/src/pages/master/aldeias/blocks/EditDialog.tsx new file mode 100644 index 0000000..d34e30c --- /dev/null +++ b/src/pages/master/aldeias/blocks/EditDialog.tsx @@ -0,0 +1,148 @@ +import { apiConfig } from '@/config/api.config'; +import { useManageAldeiasContext } from '../hooks/useManageAldeiasContext'; +import { Alert, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { getAuth } from '@/auth'; +import React, { useCallback, useEffect, useState } from 'react'; +import { toast } from 'sonner'; +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_master_data; + +const EditDialog = () => { + const { showEditDialog, handleEditDialog, selectedAldeias } = useManageAldeiasContext(); + const { reload } = useDataGrid(); + const { PutData } = useCallApi(); + const parsedUser = getAuth()?.user; + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + name: '', + sucos: 0, + updated_by: '', + updated_at: '' + }; + const [formField, setFormField] = useState(initialState); + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + + const resetForm = () => { + setFormField(initialState); + setAlert({ show: false, message: '' }); + }; + + const doUpdateAldeias = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + const response = await PutData(`${API_URL}/aldeias/update/${selectedAldeias}`, formField); + + if (response?.status) { + resetForm(); + handleEditDialog(false, null); + toast.success('Success Update Aldeias'); + reload(); + } else { + toast.error('Error Update Aldeias'); + setAlert({ show: true, message: 'Error Update Aldeias' }); + } + }, + [selectedAldeias, formField] + ); + + const handleUpdate = (e: React.FormEvent) => { + e.preventDefault(); + + if (formField.name === '' || formField.sucos === 0) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + // doUpdateAldeias(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + useEffect(() => { + if (showEditDialog) { + setFormField({ + ...formField, + updated_by: parsedUser?.username, + updated_at: formattedTime + }); + } + }, [formattedTime]); + + return ( + handleEditDialog(open, null)}> + + + Aldeias - Update + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + { + const value = parseInt(e.target.value, 10); + setFormField({ ...formField, sucos: isNaN(value) ? 0 : value }); + }} + /> +
+
+ +
+ +
+
+
+
+
+
+
+ ); +}; + +export default EditDialog; diff --git a/src/pages/master/aldeias/blocks/ListToolbar.tsx b/src/pages/master/aldeias/blocks/ListToolbar.tsx index e69de29..7cc5369 100644 --- a/src/pages/master/aldeias/blocks/ListToolbar.tsx +++ b/src/pages/master/aldeias/blocks/ListToolbar.tsx @@ -0,0 +1,62 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { Button } from '@/components/ui/button'; +import { useManageAldeiasContext } from '../hooks/useManageAldeiasContext'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog, handleSearchDialog } = useManageAldeiasContext(); + + return ( +
+
+
+
+ + + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/master/aldeias/hooks/ManageAldeiasContext.tsx b/src/pages/master/aldeias/hooks/ManageAldeiasContext.tsx new file mode 100644 index 0000000..d4cf6d3 --- /dev/null +++ b/src/pages/master/aldeias/hooks/ManageAldeiasContext.tsx @@ -0,0 +1,196 @@ +import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; +import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { ColumnDef } from '@tanstack/react-table'; +import React, { createContext, useCallback, useMemo, useState } from 'react'; +import { Toaster } from 'sonner'; +import ListToolbar from '../blocks/ListToolbar'; + +interface AldeiasProps { + id: number; + name: string; +} + +interface ContextProps { + aldeias: AldeiasProps[]; + 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; + selectedAldeias: string | null; + getAldeiasLists: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: any, + order_direction: any + ) => Promise<{ data: AldeiasProps[]; totalCount: number } | undefined>; +} + +const initialProps: ContextProps = { + aldeias: [], + showSearchDialog: false, + handleSearchDialog: () => {}, + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + showDeleteDialog: false, + handleDeleteDialog: () => {}, + selectedAldeias: null, + getAldeiasLists: async () => undefined +}; + +const ManageAldeiasContext = createContext(initialProps); +const API_URL = apiConfig.service_master_data; + +const ManageAldeiasContextProvider = ({ children }: { children: React.ReactNode }) => { + const [aldeias, setAldeias] = useState([]); + const [showSearchDialog, setShowSearchDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showEditDialog, setShowEditDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [selectedAldeias, setSelectedAldeias] = useState(null); + const { GetData } = useCallApi(); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_aldeias: string | null) => { + setSelectedAldeias(show ? selected_aldeias : null); + setShowEditDialog(show); + }, []); + + const handleDeleteDialog = useCallback((show: boolean, selected_aldeias: string | null) => { + setSelectedAldeias(show ? selected_aldeias : null); + setShowDeleteDialog(show); + }, []); + + const handleSearchDialog = useCallback((show: boolean) => { + setShowSearchDialog(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.sucos.name, + id: 'sucos', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + id: 'actions', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + cell: (data) => { + const row = data.row.original; + return ( + <> + + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [] + ); + + const getAldeiasLists = async (page: number, limit: number, sorting: any, filter: any) => { + try { + const response = await GetData(`${API_URL}/aldeias/list`, { + limit, + page: page + 1, + with_deleted: true, + order_field: sorting[0].id, + order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', + filter: JSON.stringify(filter) + }); + console.log(response?.data); + setAldeias(response?.data.list); + return { data: response?.data.list, totalCount: response?.data.total_count }; + } catch (error) { + console.error('Error fetching Aldeias', error); + } + }; + + return ( + + + } + layout={{ card: true }} + sorting={[{ id: 'id', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + getAldeiasLists(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + + + ); +}; + +export { ManageAldeiasContext, ManageAldeiasContextProvider }; +export type { AldeiasProps }; diff --git a/src/pages/master/aldeias/hooks/useManageAldeiasContext.tsx b/src/pages/master/aldeias/hooks/useManageAldeiasContext.tsx new file mode 100644 index 0000000..c042a04 --- /dev/null +++ b/src/pages/master/aldeias/hooks/useManageAldeiasContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageAldeiasContext } from './ManageAldeiasContext'; + +const useManageAldeiasContext = () => { + const context = useContext(ManageAldeiasContext); + + if (!context) throw new Error('useManageAldeiasContext must be used within AuthProvider'); + + return context; +}; + +export { useManageAldeiasContext }; From ea21966453ec3763af173ac6f166ad2360e5aec9 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 4 Mar 2025 13:50:43 +0700 Subject: [PATCH 11/15] update date time --- src/pages/master/municipios/blocks/AddDialog.tsx | 7 ++++--- src/pages/master/municipios/blocks/EditDialog.tsx | 6 +++--- src/pages/master/postoadms/blocks/AddDialog.tsx | 11 +++-------- src/pages/master/postoadms/blocks/EditDialog.tsx | 8 ++++---- src/pages/master/sucos/blocks/AddDialog.tsx | 7 ++++--- src/pages/master/sucos/blocks/EditDialog.tsx | 7 ++++--- 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/pages/master/municipios/blocks/AddDialog.tsx b/src/pages/master/municipios/blocks/AddDialog.tsx index 0db792b..234bd0c 100644 --- a/src/pages/master/municipios/blocks/AddDialog.tsx +++ b/src/pages/master/municipios/blocks/AddDialog.tsx @@ -37,6 +37,9 @@ const AddDialog = () => { }; const [formField, setFormField] = useState(initialState); + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + const resetForm = () => { setFormField(initialState); }; @@ -92,8 +95,6 @@ const AddDialog = () => { }; useEffect(() => { - const created_time = new Date(); - const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); if (showAddDialog) { setFormField({ name: formField.name, @@ -101,7 +102,7 @@ const AddDialog = () => { created_at: formattedTime }); } - }, [showAddDialog]); + }, [formattedTime]); return ( handleAddDialog(open)}> diff --git a/src/pages/master/municipios/blocks/EditDialog.tsx b/src/pages/master/municipios/blocks/EditDialog.tsx index afb9c3c..0579d28 100644 --- a/src/pages/master/municipios/blocks/EditDialog.tsx +++ b/src/pages/master/municipios/blocks/EditDialog.tsx @@ -39,6 +39,8 @@ const EditDialog = () => { }; const [formField, setFormField] = useState(initialState); + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); const resetForm = () => { setFormField(initialState); @@ -96,8 +98,6 @@ const EditDialog = () => { // }, []); useEffect(() => { - const created_time = new Date(); - const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); if (selectedMunicipios) { setFormField({ name: formField.name, @@ -105,7 +105,7 @@ const EditDialog = () => { updated_at: formattedTime }); } - }, [selectedMunicipios]); + }, [formattedTime]); // console.log(selectedMunicipios); return ( diff --git a/src/pages/master/postoadms/blocks/AddDialog.tsx b/src/pages/master/postoadms/blocks/AddDialog.tsx index 3849e1c..6e47f25 100644 --- a/src/pages/master/postoadms/blocks/AddDialog.tsx +++ b/src/pages/master/postoadms/blocks/AddDialog.tsx @@ -38,6 +38,8 @@ const AddDialog = () => { }; const [formField, setFormField] = useState(initialState); + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); const resetForm = () => { setFormField(initialState); @@ -76,14 +78,7 @@ const AddDialog = () => { setAlert({ show: false, message: '' }); }; - // const handleReset = () => { - // resetForm(); - // setAlert({ show: false, message: '' }); - // }; - useEffect(() => { - const created_time = new Date(); - const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); if (showAddDialog) { setFormField({ ...formField, @@ -91,7 +86,7 @@ const AddDialog = () => { created_at: formattedTime }); } - }, [showAddDialog]); + }, [formattedTime]); return ( handleAddDialog(open)}> diff --git a/src/pages/master/postoadms/blocks/EditDialog.tsx b/src/pages/master/postoadms/blocks/EditDialog.tsx index 2407e1d..8513d83 100644 --- a/src/pages/master/postoadms/blocks/EditDialog.tsx +++ b/src/pages/master/postoadms/blocks/EditDialog.tsx @@ -35,7 +35,10 @@ const EditDialog = () => { updated_by: '', updated_at: '' }; + const [formField, setFormField] = useState(initialState); + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); const resetForm = () => { setFormField(initialState); @@ -75,9 +78,6 @@ const EditDialog = () => { }; useEffect(() => { - const created_time = new Date(); - const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); - if (selectedPostoAdms) { setFormField({ ...formField, @@ -85,7 +85,7 @@ const EditDialog = () => { updated_at: formattedTime }); } - }, [selectedPostoAdms]); + }, [formattedTime]); return ( handleEditDialog(open, null)}> diff --git a/src/pages/master/sucos/blocks/AddDialog.tsx b/src/pages/master/sucos/blocks/AddDialog.tsx index eed5cd9..51909e6 100644 --- a/src/pages/master/sucos/blocks/AddDialog.tsx +++ b/src/pages/master/sucos/blocks/AddDialog.tsx @@ -34,7 +34,10 @@ const AddDialog = () => { created_by: '', created_at: '' }; + const [formField, setFormField] = useState(initialState); + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); const resetForm = () => { setFormField(initialState); @@ -70,8 +73,6 @@ const AddDialog = () => { }; useEffect(() => { - const created_time = new Date(); - const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); if (showAddDialog) { setFormField({ ...formField, @@ -79,7 +80,7 @@ const AddDialog = () => { created_at: formattedTime }); } - }, [showAddDialog]); + }, [formattedTime]); return ( handleAddDialog(open)}> diff --git a/src/pages/master/sucos/blocks/EditDialog.tsx b/src/pages/master/sucos/blocks/EditDialog.tsx index 342c621..f655658 100644 --- a/src/pages/master/sucos/blocks/EditDialog.tsx +++ b/src/pages/master/sucos/blocks/EditDialog.tsx @@ -33,7 +33,10 @@ const EditDialog = () => { updated_by: '', updated_at: '' }; + const [formField, setFormField] = useState(initialState); + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); const resetForm = () => { setFormField(initialState); @@ -76,8 +79,6 @@ const EditDialog = () => { }; useEffect(() => { - const created_time = new Date(); - const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); if (showEditDialog) { setFormField({ ...formField, @@ -85,7 +86,7 @@ const EditDialog = () => { updated_at: formattedTime }); } - }, [showEditDialog]); + }, [formattedTime]); return ( handleEditDialog(open, null)}> From 7906aebc022cdd6652df42b816cae0721ae26a9f Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Wed, 5 Mar 2025 12:02:47 +0700 Subject: [PATCH 12/15] update --- src/pages/currency/ManageCurrency.tsx | 53 --------------------------- src/pages/currency/index.ts | 1 - 2 files changed, 54 deletions(-) delete mode 100644 src/pages/currency/ManageCurrency.tsx delete mode 100644 src/pages/currency/index.ts diff --git a/src/pages/currency/ManageCurrency.tsx b/src/pages/currency/ManageCurrency.tsx deleted file mode 100644 index 40f10eb..0000000 --- a/src/pages/currency/ManageCurrency.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useState, useEffect, useCallback } from 'react'; -import Table from '@mui/material/Table'; -import TableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; -import TableContainer from '@mui/material/TableContainer'; -import TableHead from '@mui/material/TableHead'; -import TableRow from '@mui/material/TableRow'; -import Paper from '@mui/material/Paper'; - -function createData(name: string, calories: number, fat: number, carbs: number, protein: number) { - return { name, calories, fat, carbs, protein }; -} - -const rows = [ - createData('Frozen yoghurt', 159, 6.0, 24, 4.0), - createData('Ice cream sandwich', 237, 9.0, 37, 4.3), - createData('Eclair', 262, 16.0, 24, 6.0), - createData('Cupcake', 305, 3.7, 67, 4.3), - createData('Gingerbread', 356, 16.0, 49, 3.9) -]; - -const ManageCurrencyPage = () => { - return ( - - - - - Dessert (100g serving) - Calories - Fat (g) - Carbs (g) - Protein (g) - - - - {rows.map((row) => ( - - - {row.name} - - {row.calories} - {row.fat} - {row.carbs} - {row.protein} - - ))} - -
-
- ); -}; - -export { ManageCurrencyPage }; diff --git a/src/pages/currency/index.ts b/src/pages/currency/index.ts deleted file mode 100644 index b6f3fc5..0000000 --- a/src/pages/currency/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ManageCurrency'; From f84bf7dde1ebe4ec7c971b1c5077fa6ddf8f0b77 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Wed, 5 Mar 2025 13:25:47 +0700 Subject: [PATCH 13/15] add crud manage menus --- src/pages/menu/manage-menu/ManageMenu.tsx | 22 +- .../menu/manage-menu/blocks/AddDIalog.tsx | 228 ++++++++++++++++ .../menu/manage-menu/blocks/DeleteDialog.tsx | 74 ++++++ .../menu/manage-menu/blocks/EditDialog.tsx | 221 +++++++++++++++ .../menu/manage-menu/blocks/ListToolbar.tsx | 55 ++++ .../manage-menu/hooks/ManageMenusContext.tsx | 251 ++++++++++++++++++ .../hooks/useManageMenusContext.tsx | 12 + 7 files changed, 858 insertions(+), 5 deletions(-) create mode 100644 src/pages/menu/manage-menu/blocks/AddDIalog.tsx create mode 100644 src/pages/menu/manage-menu/blocks/DeleteDialog.tsx create mode 100644 src/pages/menu/manage-menu/blocks/EditDialog.tsx create mode 100644 src/pages/menu/manage-menu/blocks/ListToolbar.tsx create mode 100644 src/pages/menu/manage-menu/hooks/ManageMenusContext.tsx create mode 100644 src/pages/menu/manage-menu/hooks/useManageMenusContext.tsx diff --git a/src/pages/menu/manage-menu/ManageMenu.tsx b/src/pages/menu/manage-menu/ManageMenu.tsx index e9febec..75e0925 100644 --- a/src/pages/menu/manage-menu/ManageMenu.tsx +++ b/src/pages/menu/manage-menu/ManageMenu.tsx @@ -1,10 +1,22 @@ +import { Container, DataGridInner } from '@/components'; +import { ManageMenusContextProvider } from './hooks/ManageMenusContext'; +import AddDialog from './blocks/AddDIalog'; +import EditDialog from './blocks/EditDialog'; +import DeleteDialog from './blocks/DeleteDialog'; + const ManageMenu = () => { return ( -
-
-

Manage Menu

-
-
+ + +

Manage Menus

+
+ +
+ + + +
+
); }; diff --git a/src/pages/menu/manage-menu/blocks/AddDIalog.tsx b/src/pages/menu/manage-menu/blocks/AddDIalog.tsx new file mode 100644 index 0000000..bc5f118 --- /dev/null +++ b/src/pages/menu/manage-menu/blocks/AddDIalog.tsx @@ -0,0 +1,228 @@ +import { apiConfig } from '@/config/api.config'; +import React, { useCallback, useRef, useState } from 'react'; +import { useManageMenusContext } from '../hooks/useManageMenusContext'; +import { Alert, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import { toast } from 'sonner'; +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 } = useManageMenusContext(); + const { reload } = useDataGrid(); + const { PostData } = useCallApi(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + module: '', + name: '', + link: '', + id_parent: '', + order_number: 0, + icon: '', + application: '', + status: '' + }; + const [formField, setFormField] = useState(initialState); + + const doCreateMenu = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + const response = await PostData(`${API_URL}/menus/create`, formField); + + if (response?.status) { + handleAddDialog(false); + resetForm(); + toast.success('Success Create Menu'); + reload(); + } else { + toast.error('Failed Create Menu'); + setAlert({ show: true, message: 'Failed Create Menu' }); + } + }, + [formField] + ); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if ( + formField.module === '' || + formField.name === '' || + formField.link === '' || + formField.order_number === 0 || + formField.application === '' || + formField.status === '' + ) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + // doCreateMenu(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + const resetForm = () => { + setFormField(initialState); + setAlert({ show: false, message: '' }); + }; + + return ( + handleAddDialog(open)}> + + + Menu - Create + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, module: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, link: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, id_parent: e.target.value })} + /> +
+
+ +
+
+ + { + const value = parseInt(e.target.value, 10); + setFormField({ ...formField, order_number: isNaN(value) ? 0 : value }); + }} + /> +
+
+ +
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, application: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, status: e.target.value })} + /> +
+
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/menu/manage-menu/blocks/DeleteDialog.tsx b/src/pages/menu/manage-menu/blocks/DeleteDialog.tsx new file mode 100644 index 0000000..6d07093 --- /dev/null +++ b/src/pages/menu/manage-menu/blocks/DeleteDialog.tsx @@ -0,0 +1,74 @@ +import { apiConfig } from '@/config/api.config'; +import { useManageMenusContext } from '../hooks/useManageMenusContext'; +import { Alert, useDataGrid } from '@/components'; +import { useCallApi } from '@/hooks'; +import React, { ChangeEvent, useCallback, useState } from 'react'; +import { toast } from 'sonner'; +import { Dialog, DialogContent, DialogFooter, DialogHeader } from '@/components/ui/dialog'; +import { EnforceSwitch } from '@/components/switch'; +import { Button } from '@/components/ui/button'; + +const API_URL = apiConfig.service_dashboard; +const DeleteDialog = () => { + const { showDeleteDialog, handleDeleteDialog, selectedMenu } = useManageMenusContext(); + const { reload } = useDataGrid(); + const { DeleteData } = useCallApi(); + const [enforce, setEnforce] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const doDeleteMenu = useCallback(async () => { + const response = await DeleteData(`${API_URL}/menus/delete/${selectedMenu}/${enforce}`, { + id: selectedMenu + }); + + if (response?.status) { + setAlert((prev) => ({ ...prev, show: false, message: '' })); + handleDeleteDialog(false, null); + toast.success('Success Delete Menu'); + reload(); + } else { + toast.error('Failed Delete Menu'); + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + }, [selectedMenu, enforce]); + + return ( + handleDeleteDialog(open, null)}> + + + +

Are you sure?

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

{alert.message}

+
+ )} +
+ + + + +
+
+ ); +}; + +export default DeleteDialog; diff --git a/src/pages/menu/manage-menu/blocks/EditDialog.tsx b/src/pages/menu/manage-menu/blocks/EditDialog.tsx new file mode 100644 index 0000000..6674b95 --- /dev/null +++ b/src/pages/menu/manage-menu/blocks/EditDialog.tsx @@ -0,0 +1,221 @@ +import { Alert, useDataGrid } from '@/components'; +import { useManageMenusContext } from '../hooks/useManageMenusContext'; +import { useCallApi } from '@/hooks'; +import { apiConfig } from '@/config/api.config'; +import React, { useCallback, useState } from 'react'; +import { toast } from 'sonner'; +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 EditDialog = () => { + const { showEditDialog, handleEditDialog, selectedMenu } = useManageMenusContext(); + const { reload } = useDataGrid(); + const { PutData } = useCallApi(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + module: '', + name: '', + link: '', + id_parent: '', + order_number: 0, + icon: '', + application: '', + status: '' + }; + const [formField, setFormField] = useState(initialState); + + const doUpdateMenu = useCallback(async (e: React.FormEvent) => { + e.preventDefault(); + + const response = await PutData(`${API_URL}/menus/update/${selectedMenu}`, formField); + + if (response?.status) { + handleEditDialog(false, null); + resetForm(); + toast.success('Success Update Menu'); + reload(); + } else { + toast.error('Failed Update Menu'); + setAlert({ show: true, message: 'Failed Update Menu' }); + } + }, []); + + const handleUpdate = (e: React.FormEvent) => { + e.preventDefault(); + + if ( + formField.module === '' || + formField.name === '' || + formField.link === '' || + formField.order_number === 0 || + formField.application === '' || + formField.status === '' + ) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + // doUpdateMenu(e); + console.log(formField); + setAlert({ show: false, message: '' }); + }; + + const resetForm = () => { + setFormField(initialState); + setAlert({ show: false, message: '' }); + }; + + return ( + handleEditDialog(open, null)}> + + + Menu - Update + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+
+ + setFormField({ ...formField, module: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, link: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, id_parent: e.target.value })} + /> +
+
+ +
+
+ + { + const value = parseInt(e.target.value, 10); + setFormField({ ...formField, order_number: isNaN(value) ? 0 : value }); + }} + /> +
+
+ +
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, application: e.target.value })} + /> +
+
+ +
+
+ + setFormField({ ...formField, status: e.target.value })} + /> +
+
+ +
+ +
+
+
+
+
+
+
+ ); +}; + +export default EditDialog; diff --git a/src/pages/menu/manage-menu/blocks/ListToolbar.tsx b/src/pages/menu/manage-menu/blocks/ListToolbar.tsx new file mode 100644 index 0000000..784c705 --- /dev/null +++ b/src/pages/menu/manage-menu/blocks/ListToolbar.tsx @@ -0,0 +1,55 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useManageMenusContext } from '../hooks/useManageMenusContext'; +import { Button } from '@/components/ui/button'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog } = useManageMenusContext(); + + return ( +
+
+
+
+ + + + +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/menu/manage-menu/hooks/ManageMenusContext.tsx b/src/pages/menu/manage-menu/hooks/ManageMenusContext.tsx new file mode 100644 index 0000000..86aaf5d --- /dev/null +++ b/src/pages/menu/manage-menu/hooks/ManageMenusContext.tsx @@ -0,0 +1,251 @@ +// interface SelectedMenu { +// id: string; +// module: string; +// name: string; +// id_parent: string; +// order_number: number; +// icon: string; +// application: string; +// status: string; +// } + +import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; +import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { ColumnDef } from '@tanstack/react-table'; +import React, { createContext, useCallback, useMemo, useState } from 'react'; +import { Toaster } from 'sonner'; +import ListToolbar from '../blocks/ListToolbar'; + +interface MenuProps { + id: string; + module: string; + name: string; + id_parent: string; + order_number: number; + icon: string; + application: string; + status: string; +} + +interface ContextProps { + menus: MenuProps[]; + 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; + selectedMenu: string | null; + getMenusLists: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: any, + order_direction: any + ) => Promise<{ data: MenuProps[]; totalCount: number } | undefined>; +} + +const initialProps: ContextProps = { + menus: [], + showAddDialog: false, + handleAddDialog: (show: boolean) => {}, + showEditDialog: false, + handleEditDialog: (show: boolean, selected_menu: string | null) => {}, + showDeleteDialog: false, + handleDeleteDialog: (show: boolean, selected_menu: string | null) => {}, + selectedMenu: null, + getMenusLists: async () => ({ data: [], totalCount: 0 }) +}; + +const ManageMenusContext = createContext(initialProps); +const API_URL = apiConfig.service_dashboard; + +const ManageMenusContextProvider = ({ children }: { children: React.ReactNode }) => { + const [menus, setMenus] = useState([]); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showEditDialog, setShowEditDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [selectedMenu, setSelectedMenu] = useState(null); + const { GetData } = useCallApi(); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleEditDialog = useCallback((show: boolean, selected_menu: string | null) => { + setShowEditDialog(show); + setSelectedMenu(selected_menu); + }, []); + + const handleDeleteDialog = useCallback((show: boolean, selected_menu: string | null) => { + setShowDeleteDialog(show); + setSelectedMenu(selected_menu); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.module, + id: 'module', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[200px]' } + }, + { + accessorFn: (row) => row.parentName, + id: 'menu', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[200px]' } + }, + { + accessorFn: (row) => row.name, + id: 'subMenu', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[200px]' } + }, + { + accessorFn: (row) => row.link, + id: 'link', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.status, + id: 'status', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { headerClassName: 'w-[100px]', cellClassName: 'text-center' } + }, + { + id: 'actions', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + cell: (data) => { + const row = data.row.original; + return ( + <> + + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleEditDialog, handleDeleteDialog] + ); + + const flattenChildren = (parent: any, parentIdx: number, depth = 0, parentName = '') => { + if (!parent.children || parent.children.length === 0) { + return []; // Jika tidak ada children, kembalikan array kosong + } + + return parent.children.flatMap((child: any, childIdx: number) => { + // Jika child masih punya children, lakukan rekursi lebih dalam + if (child.children && child.children.length > 0) { + return flattenChildren(child, parentIdx * 100 + childIdx, depth + 1, child.name); + } + + // Jika ini adalah child terakhir (leaf node), masukkan ke array hasil + return { + id: parentIdx * 100 + childIdx + 1, + module: parent.module, + parentName: parentName || parent.name, + name: child.name, + link: child.link, + id_parent: parent.id_parent, + status: parent.status + }; + }); + }; + + const getMenusLists = 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 GetData(`${API_URL}/menus/list`, { + limit, + page: page + 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'DESC' : 'ASC' + }); + + console.log(response?.data); + if (!response?.data.list) return { data: [], totalCount: 0 }; + + // Gunakan rekursi untuk mencari children paling dalam + const transformedData = response.data.list.flatMap((row: any, parentIdx: number) => + flattenChildren(row, parentIdx) + ); + + const total_count = transformedData.length; + + setMenus(transformedData); + console.log(menus); + return { data: transformedData, totalCount: total_count }; + } catch (error) { + console.error('Error fetching Menus', error); + return { data: [], totalCount: 0 }; + } + }; + + return ( + + + + } + layout={{ card: true }} + sorting={[{ id: 'id', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + getMenusLists(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + + + ); +}; + +export { ManageMenusContextProvider, ManageMenusContext }; +export type { MenuProps }; diff --git a/src/pages/menu/manage-menu/hooks/useManageMenusContext.tsx b/src/pages/menu/manage-menu/hooks/useManageMenusContext.tsx new file mode 100644 index 0000000..1cf8f87 --- /dev/null +++ b/src/pages/menu/manage-menu/hooks/useManageMenusContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageMenusContext } from './ManageMenusContext'; + +const useManageMenusContext = () => { + const context = useContext(ManageMenusContext); + if (!context) { + throw new Error('useManageMenusContext must be used within a ManageMenusContextProvider'); + } + return context; +}; + +export { useManageMenusContext }; From eb338915da73752fb7802b3ec355271fb09ffa48 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Thu, 6 Mar 2025 09:15:17 +0700 Subject: [PATCH 14/15] add crud manage menus --- .../menu/manage-menu/blocks/AddDIalog.tsx | 18 +----------------- .../menu/manage-menu/blocks/DeleteDialog.tsx | 6 ++++-- .../menu/manage-menu/blocks/EditDialog.tsx | 18 +----------------- .../manage-menu/hooks/ManageMenusContext.tsx | 1 - 4 files changed, 6 insertions(+), 37 deletions(-) diff --git a/src/pages/menu/manage-menu/blocks/AddDIalog.tsx b/src/pages/menu/manage-menu/blocks/AddDIalog.tsx index bc5f118..72e4209 100644 --- a/src/pages/menu/manage-menu/blocks/AddDIalog.tsx +++ b/src/pages/menu/manage-menu/blocks/AddDIalog.tsx @@ -32,7 +32,6 @@ const AddDialog = () => { id_parent: '', order_number: 0, icon: '', - application: '', status: '' }; const [formField, setFormField] = useState(initialState); @@ -64,14 +63,13 @@ const AddDialog = () => { formField.name === '' || formField.link === '' || formField.order_number === 0 || - formField.application === '' || formField.status === '' ) { setAlert({ show: true, message: 'Please fill in all required fields.' }); return; } - // doCreateMenu(e); + doCreateMenu(e); console.log(formField); setAlert({ show: false, message: '' }); }; @@ -182,20 +180,6 @@ const AddDialog = () => {
-
-
- - setFormField({ ...formField, application: e.target.value })} - /> -
-
-
-
-
- - setFormField({ ...formField, application: e.target.value })} - /> -
-
-