diff --git a/.gitignore b/.gitignore index cff2732..a93a63a 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ yarn.lock .env package-lock.json +package.json +yarn.lock +package-lock.json diff --git a/package-lock.json b/package-lock.json index 87756c1..3e4da0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "https": "^1.0.0", "leaflet": "^1.9.4", "lucide-react": "^0.456.0", + "metronic-tailwind-react": "file:", "mini-svg-data-uri": "^1.4.4", "moment": "^2.30.1", "next-themes": "^0.4.3", @@ -6454,6 +6455,10 @@ "node": ">= 8" } }, + "node_modules/metronic-tailwind-react": { + "resolved": "", + "link": true + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", diff --git a/package.json b/package.json index 2e30fa9..7745b80 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "https": "^1.0.0", "leaflet": "^1.9.4", "lucide-react": "^0.456.0", + "metronic-tailwind-react": "file:", "mini-svg-data-uri": "^1.4.4", "moment": "^2.30.1", "next-themes": "^0.4.3", diff --git a/src/layouts/demo2/header/HeaderLogo.tsx b/src/layouts/demo2/header/HeaderLogo.tsx index 443be9e..03fb815 100644 --- a/src/layouts/demo2/header/HeaderLogo.tsx +++ b/src/layouts/demo2/header/HeaderLogo.tsx @@ -19,6 +19,16 @@ const HeaderLogo = () => { const { pathname } = useLocation(); const { isRTL } = useLanguage(); const [selectedMenuItem, setSelectedMenuItem] = useState(MENU_ROOT[0]); + const [isSticky, setIsSticky] = useState(false); + + useEffect(() => { + const handleScroll = () => { + setIsSticky(window.scrollY > 100); + }; + + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll); + }, []); useEffect(() => { MENU_ROOT.forEach((item) => { @@ -55,7 +65,9 @@ const HeaderLogo = () => {
-

TPAY Dashboard Portal

+
); diff --git a/src/pages/groups/Column.tsx b/src/pages/groups/Column.tsx index d796078..2f6fe7f 100644 --- a/src/pages/groups/Column.tsx +++ b/src/pages/groups/Column.tsx @@ -1,3 +1,4 @@ +import { KeenIcon } from '@/components'; import { ColumnDef } from '@tanstack/react-table'; export type Group = { @@ -8,7 +9,7 @@ export type Group = { description: string; }; -export const columns: ColumnDef[] = [ +export const getColumns = (handleUpdate: (data: any) => void): ColumnDef[] => [ { accessorKey: 'no', header: 'ID' @@ -30,8 +31,19 @@ export const columns: ColumnDef[] = [ accessorKey: 'description', header: 'Description' }, - // { - // id: 'actions', - // header: 'Actions' - // } + { + id: 'actions', + cell: ({ row }) => { + const dataMembers = row.original; + + return ( + + ); + } + } ]; diff --git a/src/pages/groups/ListToolbar.tsx b/src/pages/groups/ListToolbar.tsx new file mode 100644 index 0000000..793f4c9 --- /dev/null +++ b/src/pages/groups/ListToolbar.tsx @@ -0,0 +1,49 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { Button } from '@/components/ui/button'; + +const ListToolBar = ({ createGroup }: { createGroup: () => void }) => { + const { table, reload } = useDataGrid(); + + return ( +
+
+
+
+ + {/* + + */} +
+
+ + + + +
+
+
+
+ ); +}; + +export { ListToolBar }; diff --git a/src/pages/groups/ManageGroups.tsx b/src/pages/groups/ManageGroups.tsx index 55ae1eb..d03966f 100644 --- a/src/pages/groups/ManageGroups.tsx +++ b/src/pages/groups/ManageGroups.tsx @@ -1,5 +1,5 @@ import { DataTable } from '@/components/ui/DataTable'; -import { columns, Group } from './Column'; +import { getColumns, Group } from './Column'; import { apiConfig } from '@/config/api.config'; import axios, { AxiosResponse } from 'axios'; import { Helmet } from 'react-helmet'; @@ -24,6 +24,8 @@ import CloseIcon from '@mui/icons-material/Close'; import Divider from '@mui/material/Divider'; import ConfirmDialog from '@/components/confirm'; import { toast } from 'sonner'; +import { Container, DataGridProvider } from '@/components'; +import { ListToolBar } from './ListToolbar'; // import { DialogHeader } from '@/components/ui/dialog'; // import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; const BASE_URL = apiConfig.service_customer; @@ -66,7 +68,7 @@ const ManageGroups = () => { let resGroups = groups.data.data.list.map((el: any) => { el.no = temp++; return el; - }); + }) setDataGroup(resGroups); } catch (error: any) { alert(error.message); @@ -89,9 +91,9 @@ const ManageGroups = () => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!formData.groupName) return toast.warning(`Group name can not be empty!`) - if (!formData.status) return toast.warning(`Status can not be empty!`) - if (!formData.description) return toast.warning(`Description can not be empty!`) + if (!formData.groupName) return toast.warning(`Group name can not be empty!`); + if (!formData.status) return toast.warning(`Status can not be empty!`); + if (!formData.description) return toast.warning(`Description can not be empty!`); setIsDialogOpen(false); setDialogOpen(true); }; @@ -134,7 +136,7 @@ const ManageGroups = () => { description: formData.description, created_at: new Date() }); - toast.success(`Success create group`) + toast.success(`Success create group`); } else if (dialogType === 'update') { await axios.put(`${BASE_URL}/groups/update/${formData.id}`, { name: formData.groupName, @@ -142,14 +144,14 @@ const ManageGroups = () => { description: formData.description, updated_at: new Date() }); - toast.success(`Success update group`) + toast.success(`Success update group`); } else if (dialogType === 'delete') { await axios.delete(`${BASE_URL}/groups/delete/${formData.id}/true`); - toast.success(`Success delete group`) + toast.success(`Success delete group`); } } catch (error: any) { console.log(error); - toast.error(error.message) + toast.error(error.message); } finally { await fetchGroups(); setDialogOpen(false); @@ -162,19 +164,19 @@ const ManageGroups = () => { TPAY | Manage Group - setDialogOpen(false)} - title="Confirm Action" - content={ - `Are you sure you want to ` + - (dialogType === 'create' ? 'create?' : dialogType === 'update' ? 'update?' : 'delete?') - } - onYes={handleYes} - onNo={() => setDialogOpen(false)} - /> -

Groups

-
+ + setDialogOpen(false)} + title="Confirm Action" + content={ + `Are you sure you want to ` + + (dialogType === 'create' ? 'create?' : dialogType === 'update' ? 'update?' : 'delete?') + } + onYes={handleYes} + onNo={() => setDialogOpen(false)} + /> +

Groups

Dashboard @@ -188,84 +190,101 @@ const ManageGroups = () => { Manage Groups -
-
- */} +
+ {/* -
+ /> */} + } + layout={{ card: true }} + sorting={[{ id: 'created_at', desc: true }]} + serverSide={false} + onRowSelectionChange={(selected, table: any) => { + const selectedRow = table.getSelectedRowModel().rows[0]; + if (selectedRow) handleUpdate(selectedRow.original); + }} + /> +
+ {/* */} - - -
- {dialogType==='create'?"Create New Group":"Update Group"} - - - -
- -
-
-
- - -
-
- - - - } - label="Yes" - /> - } - label="No" - /> - - -
-
- - -
- -
-
-
-
+ + +
+ + {dialogType === 'create' ? 'Create New Group' : 'Update Group'} + + + + +
+ +
+
+
+ + +
+
+ + + + } + label="Yes" + /> + } + label="No" + /> + + +
+
+ + +
+ +
+
+
+
+ ); }; diff --git a/src/pages/master/aldeias/blocks/EditDialog.tsx b/src/pages/master/aldeias/blocks/EditDialog.tsx index 0eec124..76c7c10 100644 --- a/src/pages/master/aldeias/blocks/EditDialog.tsx +++ b/src/pages/master/aldeias/blocks/EditDialog.tsx @@ -27,8 +27,8 @@ import { import { doSaveLogActivity } from '@/actions/GlobalActions'; interface SucosProps { - sucos_id: number; - sucos_name: string; + id: number; + name: string; } const API_URL = apiConfig.service_master_data; @@ -40,6 +40,7 @@ const EditDialog = () => { const parsedUser = getAuth()?.user; const [sucos, setSucos] = useState([]); const [open, setOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); const [alert, setAlert] = useState({ show: false, message: '' @@ -96,8 +97,8 @@ const EditDialog = () => { order_direction: sorting[0].desc == false ? 'ASC' : 'DESC' }); - // console.log('SUCOS', response?.data); setSucos(response?.data.list); + console.log(sucos); } catch (error) { console.error('Error fetching Sucos', error); setAlert({ show: true, message: 'Failed to get Sucos. Please try again.' }); @@ -105,6 +106,7 @@ const EditDialog = () => { }; const doFetchData = useCallback(async (id: string) => { + setIsLoading(true); const response = await GetData(`${API_URL}/aldeias/getdata/${id}`, { id }); if (response?.status) { @@ -120,6 +122,7 @@ const EditDialog = () => { sucosId: 0 })); } + setIsLoading(false); }, []); const handleUpdate = (e: React.FormEvent) => { @@ -176,72 +179,87 @@ const EditDialog = () => { )} -
-
-
-
- - setFormField({ ...formField, name: e.target.value })} - /> + {isLoading ? ( +
+
+
+
+
+
+
+
- -
-
- - - - - - - - - - No Sucos found. - - {sucos.map((suco) => ( - { - setFormField({ - ...formField, - sucosId: suco.sucos_id - }); - setOpen(false); - }} - > - {suco.sucos_name} - - ))} - - - - - -
-
- -
- -
+

Loading Aldeia Details...

- + ) : ( +
+
+
+
+ + setFormField({ ...formField, name: e.target.value })} + /> +
+
+ +
+
+ + + + + + + + + + No Sucos found. + + {sucos.map((suco) => ( + { + setFormField({ + ...formField, + sucosId: suco.id + }); + setOpen(false); + }} + > + {suco.name} + + ))} + + + + + +
+
+ +
+ +
+
+
+ )}
diff --git a/src/pages/master/aldeias/blocks/ListToolbar.tsx b/src/pages/master/aldeias/blocks/ListToolbar.tsx index 2454a1c..26401b0 100644 --- a/src/pages/master/aldeias/blocks/ListToolbar.tsx +++ b/src/pages/master/aldeias/blocks/ListToolbar.tsx @@ -1,23 +1,47 @@ import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; import { Button } from '@/components/ui/button'; import { useManageAldeiasContext } from '../hooks/useManageAldeiasContext'; +import React, { useEffect, useState } from 'react'; const ListToolbar = () => { const { table, reload } = useDataGrid(); const { handleAddDialog, handleSearchDialog } = useManageAldeiasContext(); + const [searchValue, setSearchValue] = useState( + (table.getColumn('name')?.getFilterValue() as string) ?? '' + ); + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + handleSearch(); + } + }; + + const handleSearch = () => { + table.getColumn('name')?.setFilterValue(searchValue); + table.setPageIndex(0); + }; + + useEffect(() => { + const timer = setTimeout(() => { + table.getColumn('name')?.setFilterValue(searchValue); + table.setPageIndex(0); + }, 200); + + return () => clearTimeout(timer); + }, [searchValue, table]); return (
-