From 84408ac869a4a8d538b2d98061469570fbb8fc13 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 3 Mar 2025 08:57:36 +0700 Subject: [PATCH 1/2] 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 e6cf8106c896ac58765f8a65d67a94b911ffa88d Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 3 Mar 2025 11:59:32 +0700 Subject: [PATCH 2/2] 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 (