diff --git a/src/components/data-grid/DataGridContext.tsx b/src/components/data-grid/DataGridContext.tsx index 4b54947..000d41c 100644 --- a/src/components/data-grid/DataGridContext.tsx +++ b/src/components/data-grid/DataGridContext.tsx @@ -152,7 +152,7 @@ export const DataGridProvider = (props: TDataGridProps !loading && setSorting(newSorting), onColumnFiltersChange: (newFilters) => { - console.log('New Filters:', newFilters); // Debugging + // console.log('New Filters:', newFilters); // Debugging !loading && setColumnFilters(newFilters); }, onColumnVisibilityChange: setColumnVisibility, diff --git a/src/pages/master/aldeias/blocks/AddDialog.tsx b/src/pages/master/aldeias/blocks/AddDialog.tsx index f678f33..cc2619a 100644 --- a/src/pages/master/aldeias/blocks/AddDialog.tsx +++ b/src/pages/master/aldeias/blocks/AddDialog.tsx @@ -24,6 +24,7 @@ import { CommandItem, CommandList } from '@/components/ui/command'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface SucosProps { sucos_id: number; @@ -34,7 +35,7 @@ const API_URL = apiConfig.service_master_data; const AddDialog = () => { const parentRef = useRef(null); - const { showAddDialog, handleAddDialog } = useManageAldeiasContext(); + const { showAddDialog, handleAddDialog, selectedAldeias } = useManageAldeiasContext(); const { reload } = useDataGrid(); const { PostData, GetData } = useCallApi(); const parsedUser = getAuth()?.user; @@ -70,6 +71,13 @@ const AddDialog = () => { handleAddDialog(false); toast.success('Success Create Aldeias'); reload(); + const createActivity = { + module: 'Manage Aldeias', + description: `Create Aldeia => ${selectedAldeias}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Error Create Aldeias'); setAlert({ show: true, message: 'Failed to create Aldeias. Please try again.' }); diff --git a/src/pages/master/aldeias/blocks/DeleteDialog.tsx b/src/pages/master/aldeias/blocks/DeleteDialog.tsx index 17c4954..9293c89 100644 --- a/src/pages/master/aldeias/blocks/DeleteDialog.tsx +++ b/src/pages/master/aldeias/blocks/DeleteDialog.tsx @@ -6,6 +6,7 @@ import { useCallback, useState } from 'react'; import { toast } from 'sonner'; import { Dialog, DialogContent, DialogFooter, DialogHeader } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL = apiConfig.service_master_data; @@ -33,6 +34,14 @@ const DeleteDialog = () => { handleDeleteDialog(false, null); toast.success('Success Delete Aldeias'); reload(); + + const createActivity = { + module: 'Manage Aldeias', + description: `Edit Aldeia => ${selectedAldeias}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); } else { setAlert({ show: true, message: response?.message }); toast.error('Failed Delete Aldeias'); diff --git a/src/pages/master/aldeias/blocks/EditDialog.tsx b/src/pages/master/aldeias/blocks/EditDialog.tsx index 449197d..79eb0ce 100644 --- a/src/pages/master/aldeias/blocks/EditDialog.tsx +++ b/src/pages/master/aldeias/blocks/EditDialog.tsx @@ -24,6 +24,7 @@ import { CommandItem, CommandList } from '@/components/ui/command'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface SucosProps { sucos_id: number; @@ -69,6 +70,13 @@ const EditDialog = () => { handleEditDialog(false, null); toast.success('Success Update Aldeias'); reload(); + const createActivity = { + module: 'Manage Aldeias', + description: `Edit Aldeia => ${selectedAldeias}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Error Update Aldeias'); setAlert({ show: true, message: 'Error Update Aldeias' }); diff --git a/src/pages/master/aldeias/hooks/ManageAldeiasContext.tsx b/src/pages/master/aldeias/hooks/ManageAldeiasContext.tsx index 6dcce41..03519e9 100644 --- a/src/pages/master/aldeias/hooks/ManageAldeiasContext.tsx +++ b/src/pages/master/aldeias/hooks/ManageAldeiasContext.tsx @@ -89,7 +89,7 @@ const ManageAldeiasContextProvider = ({ children }: { children: React.ReactNode }, { accessorFn: (row) => row.sucos.name, - id: 'sucos', + id: 'sucos_name', header: ({ column }) => , enableSorting: true, enableHiding: false, diff --git a/src/pages/master/conversion/blocks/AddDialog.tsx b/src/pages/master/conversion/blocks/AddDialog.tsx index b9f0e60..f516f2a 100644 --- a/src/pages/master/conversion/blocks/AddDialog.tsx +++ b/src/pages/master/conversion/blocks/AddDialog.tsx @@ -33,6 +33,7 @@ import { SelectValue } from '@/components/ui/select'; import { useManageConversionContext } from '../hooks/useManageConversionContext'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface CurrencyProps { ID: string; name: string; @@ -80,6 +81,13 @@ const AddDialog = () => { resetForm(); handleAddDialog(false); toast.success('Success Create Conversion'); + const createActivity = { + module: 'Manage Conversion', + description: `Create Conversion => ${selectedConversion}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); reload(); } else { toast.error('Error Create Conversion'); @@ -121,7 +129,7 @@ const AddDialog = () => { } doCreateConversion(e); - console.log(formField); + // console.log(formField); setAlert({ show: false, message: '' }); }; diff --git a/src/pages/master/conversion/blocks/DeleteDialog.tsx b/src/pages/master/conversion/blocks/DeleteDialog.tsx index 1c84e02..8765966 100644 --- a/src/pages/master/conversion/blocks/DeleteDialog.tsx +++ b/src/pages/master/conversion/blocks/DeleteDialog.tsx @@ -13,6 +13,7 @@ import { } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { DialogDescription } from '@radix-ui/react-dialog'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL = apiConfig.service_wallet; @@ -30,7 +31,7 @@ const DeleteDialog = () => { toast.error('No Conversion selected'); return; } - console.log(selectedConversion); + // console.log(selectedConversion); const response = await DeleteData( `${API_URL}/dashboard/conversion/${selectedConversion}`, { id: selectedConversion } @@ -40,13 +41,20 @@ const DeleteDialog = () => { setAlert({ show: false, message: '' }); handleDeleteDialog(false, null); toast.success('Success Delete Conversion'); + const createActivity = { + module: 'Manage Conversion', + description: `Delete Conversion => ${selectedConversion}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); reload(); } else { setAlert({ show: true, message: response?.message }); toast.error('Failed Delete Conversion'); } }, [selectedConversion, DeleteData, handleDeleteDialog, reload]); - console.log(selectedConversion); + // console.log(selectedConversion); return ( handleDeleteDialog(open, null)}> diff --git a/src/pages/master/conversion/blocks/EditDialog.tsx b/src/pages/master/conversion/blocks/EditDialog.tsx index 05f4d68..396dedf 100644 --- a/src/pages/master/conversion/blocks/EditDialog.tsx +++ b/src/pages/master/conversion/blocks/EditDialog.tsx @@ -33,6 +33,7 @@ import { SelectValue } from '@/components/ui/select'; import { useManageConversionContext } from '../hooks/useManageConversionContext'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface CurrencyProps { ID: string; name: string; @@ -82,6 +83,13 @@ const EditDialog = () => { resetForm(); handleEditDialog(false, null); toast.success('Success Update Conversion'); + const createActivity = { + module: 'Manage Conversion', + description: `Update Conversion => ${selectedConversion}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); reload(); } else { toast.error('Error Create Conversion'); diff --git a/src/pages/master/conversion/hooks/ManageConversionContext.tsx b/src/pages/master/conversion/hooks/ManageConversionContext.tsx index 73af1fd..730bae1 100644 --- a/src/pages/master/conversion/hooks/ManageConversionContext.tsx +++ b/src/pages/master/conversion/hooks/ManageConversionContext.tsx @@ -159,7 +159,7 @@ const ManageConversionContextProvider = ({ children }: { children: React.ReactNo ) => { sorting = sorting.length == 0 ? [{ id: 'name', desc: true }] : sorting; filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; - console.log(sorting); + // console.log(sorting); const response = await GetData(`${API_URL}/dashboard/conversion/`, { limit: limit, page: page + 1, @@ -168,7 +168,7 @@ const ManageConversionContextProvider = ({ children }: { children: React.ReactNo order_direction: sorting[0].desc ? 'ASC' : 'DESC', filter: JSON.stringify(filter) }); - console.log(response?.data); + // console.log(response?.data); return { data: response?.data.list, totalCount: response?.data.total_count }; }; diff --git a/src/pages/master/currency/CurrencyMaster.tsx b/src/pages/master/currency/CurrencyMaster.tsx new file mode 100644 index 0000000..be439cd --- /dev/null +++ b/src/pages/master/currency/CurrencyMaster.tsx @@ -0,0 +1,44 @@ +import { Container, DataGridInner } from '@/components'; +import { ManageCurrencyContextProvider } from './hooks/ManageCurrencyContext'; +import { Breadcrumbs, Link } from '@mui/material'; +import { Delete } from 'lucide-react'; +import AddDialog from './blocks/AddDialog'; +import DeleteDialog from './blocks/DeleteDialog'; +import EditDialog from './blocks/EditDialog'; + +// import EditDialog from './blocks/EditDialog'; + +const CurrencyMaster = () => { + return ( + + +

Currency

+ + + Dashboard + + + + Master Data + + + + Manage Currency + + + +
+ +
+ + + + + {/* + */} +
+
+ ); +}; + +export default CurrencyMaster; diff --git a/src/pages/master/currency/blocks/AddDialog.tsx b/src/pages/master/currency/blocks/AddDialog.tsx new file mode 100644 index 0000000..996a616 --- /dev/null +++ b/src/pages/master/currency/blocks/AddDialog.tsx @@ -0,0 +1,234 @@ +import { apiConfig } from '@/config/api.config'; +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'; +import { NumericFormat } from 'react-number-format'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList +} from '@/components/ui/command'; +import { set } from 'date-fns'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { useManageCurrencyContext } from '../hooks/useManageCurrencyContext'; +import { prefix } from 'stylis'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +interface CurrencyProps { + ID: string; + name: string; +} + +const API_URL = apiConfig.service_wallet; + +const AddDialog = () => { + const parentRef = useRef(null); + const { showAddDialog, handleAddDialog, selectedCurrency } = useManageCurrencyContext(); + const { reload } = useDataGrid(); + const { PostData, GetData } = useCallApi(); + const parsedUser = getAuth()?.user; + const [currencies, setCurrencies] = useState([]); + const [open, setOpen] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + code: '', + name: '', + prefix: '', + status: '', + 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 doCreateCurrency = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + + const response = await PostData(`${API_URL}/dashboard/currency/`, formField); + + if (response?.status) { + resetForm(); + handleAddDialog(false); + toast.success('Success Create Currency'); + const createActivity = { + module: 'Manage Currency', + description: `Create Currency=> ${selectedCurrency}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); + reload(); + } else { + toast.error('Error Create Currency'); + setAlert({ show: true, message: 'Failed to create Currency. Please try again.' }); + } + }, + [formField] + ); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if ( + formField.code === '' || + formField.name === '' || + formField.prefix === '' || + formField.status === '' + ) { + setAlert({ show: true, message: 'Please fill in all required fields.' }); + return; + } + + doCreateCurrency(e); + // console.log(formField); + setAlert({ show: false, message: '' }); + }; + + useEffect(() => { + if (showAddDialog) { + setFormField({ + ...formField, + created_by: parsedUser.username, + created_at: formattedTime + }); + } + }, [formattedTime]); + + useEffect(() => { + if (showAddDialog === false) { + resetForm(); + } + }, [showAddDialog]); + + return ( + handleAddDialog(open)}> + + + Cuurency - Create + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+ + + + setFormField((prev) => ({ ...prev, code: target.value })) + } + /> +
+
+ + + + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> +
+
+ + + + setFormField((prev) => ({ ...prev, prefix: target.value })) + } + /> +
+ +
+ + +
+ +
+
+
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/master/wallet/blocks/DeleteDialog.tsx b/src/pages/master/currency/blocks/DeleteDialog.tsx similarity index 55% rename from src/pages/master/wallet/blocks/DeleteDialog.tsx rename to src/pages/master/currency/blocks/DeleteDialog.tsx index 9166356..34b6f49 100644 --- a/src/pages/master/wallet/blocks/DeleteDialog.tsx +++ b/src/pages/master/currency/blocks/DeleteDialog.tsx @@ -1,54 +1,62 @@ -import { useCallApi } from '@/hooks'; -import { useManageWalletContext } from '../hooks/useManageWalletContext'; import { Alert, useDataGrid } from '@/components'; +import { useManageCurrencyContext } from '../hooks/useManageCurrencyContext'; import { useCallback, useState } from 'react'; -import { toast } from 'sonner'; import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { toast } from 'sonner'; import { Dialog, DialogContent, - DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; +import { DialogDescription } from '@radix-ui/react-dialog'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; -const API_URL = apiConfig.service_master_data; +const API_URL = apiConfig.service_wallet; const DeleteDialog = () => { - const { showDeleteDialog, handleDeleteDialog, selectedWallet } = useManageWalletContext(); - const { DeleteData } = useCallApi(); + const { showDeleteDialog, handleDeleteDialog, selectedCurrency } = useManageCurrencyContext(); const { reload } = useDataGrid(); - const [alert, setAlert] = useState({ show: false, message: '' }); + const { DeleteData } = useCallApi(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); - const doDeleteWallet = useCallback(async () => { - if (!selectedWallet) { - toast.error('No wallet selected'); + const doDeleteCurrency = useCallback(async () => { + if (!selectedCurrency) { + toast.error('No Currency selected'); return; } - - const response = await DeleteData( - `${API_URL}/wallet/delete/${selectedWallet.Wallet_id}/false`, - { - id: selectedWallet.Wallet_id - } - ); + // console.log(selectedCurrency); + const response = await DeleteData(`${API_URL}/dashboard/currency/${selectedCurrency}`, { + id: selectedCurrency + }); if (response?.status) { setAlert({ show: false, message: '' }); handleDeleteDialog(false, null); - toast.success('Success Delete Wallet'); + toast.success('Success Delete Currency'); + const createActivity = { + module: 'Manage Currency', + description: `Delete Currency=> ${selectedCurrency}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); reload(); } else { setAlert({ show: true, message: response?.message }); - toast.error('Failed Delete Wallet'); + toast.error('Failed Delete Currency'); } - }, [selectedWallet, handleDeleteDialog, DeleteData, reload]); - + }, [selectedCurrency, DeleteData, handleDeleteDialog, reload]); + // console.log(selectedCurrency); return ( handleDeleteDialog(open, null)}> - + @@ -66,7 +74,7 @@ const DeleteDialog = () => { - diff --git a/src/pages/master/currency/blocks/EditDialog.tsx b/src/pages/master/currency/blocks/EditDialog.tsx new file mode 100644 index 0000000..57a4c07 --- /dev/null +++ b/src/pages/master/currency/blocks/EditDialog.tsx @@ -0,0 +1,228 @@ +import { apiConfig } from '@/config/api.config'; +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'; +import { NumericFormat } from 'react-number-format'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList +} from '@/components/ui/command'; +import { set } from 'date-fns'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { useManageCurrencyContext } from '../hooks/useManageCurrencyContext'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +interface CurrencyProps { + ID: string; + name: string; +} + +const API_URL = apiConfig.service_wallet; + +const EditDialog = () => { + const parentRef = useRef(null); + const { showEditDialog, handleEditDialog, selectedCurrency } = useManageCurrencyContext(); + const { reload } = useDataGrid(); + const { PostData, GetData, PutData } = useCallApi(); + const parsedUser = getAuth()?.user; + const [currencies, setCurrencies] = useState([]); + const [open, setOpen] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const initialState = { + code: '', + name: '', + prefix: '', + status: '', + created_by: '', + created_at: '' + }; + const [formField, setFormField] = useState(initialState); + const updated_time = new Date(); + const formattedTime = updated_time.toISOString().slice(0, 19).replace('T', ' '); + + const resetForm = () => { + setFormField(initialState); + setAlert({ show: false, message: '' }); + }; + + const doUpdateCurrency = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + if (!showEditDialog) return; + const response = await PutData(`${API_URL}/dashboard/currency/${selectedCurrency}`, { + ...formField + }); + + if (response?.status) { + resetForm(); + handleEditDialog(false, null); + toast.success('Success Update Currency'); + const createActivity = { + module: 'Manage Currency', + description: `Update Currency=> ${selectedCurrency}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); + reload(); + } else { + toast.error('Error Create Currency'); + setAlert({ show: true, message: 'Failed to Update Currency. Please try again.' }); + } + }, + [formField] + ); + + const doGetCurrencyById = useCallback(async (id: string) => { + const response = await GetData(`${API_URL}/dashboard/currency/${id}`, { id }); + // console.log('Transaction Type: ', response?.data); + if (response?.status) { + setFormField((prev) => ({ + ...prev, + status: response.data.status, + code: response.data.code, + name: response.data.name, + prefix: response.data.prefix + })); + } + // console.log('form fieldd Transaction Type: ', formField); + }, []); + + useEffect(() => { + if (selectedCurrency) { + doGetCurrencyById(selectedCurrency); + } + }, [selectedCurrency]); + + useEffect(() => { + if (showEditDialog) { + setFormField({ + ...formField, + created_by: parsedUser.username, + created_at: formattedTime + }); + } + }, [formattedTime]); + + useEffect(() => { + if (showEditDialog === false) { + resetForm(); + } + }, [showEditDialog]); + + return ( + handleEditDialog(open, null)}> + + + Currency - Update + + + +
+ {alert.show && ( + +

{alert.message}

+
+ )} + +
+
+
+ + setFormField((prev) => ({ ...prev, code: e.target.value }))} + /> +
+
+ + setFormField((prev) => ({ ...prev, name: e.target.value }))} + /> +
+ +
+ + setFormField((prev) => ({ ...prev, prefix: e.target.value }))} + /> +
+ +
+ + + +
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default EditDialog; diff --git a/src/pages/master/currency/blocks/ListToolbar.tsx b/src/pages/master/currency/blocks/ListToolbar.tsx new file mode 100644 index 0000000..9cf61a3 --- /dev/null +++ b/src/pages/master/currency/blocks/ListToolbar.tsx @@ -0,0 +1,55 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { Button } from '@/components/ui/button'; +import { useManageCurrencyContext } from '../hooks/useManageCurrencyContext'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog } = useManageCurrencyContext(); + + return ( +
+
+
+
+ {/* */} + {/* + + */} +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/master/currency/hooks/ManageCurrencyContext.tsx b/src/pages/master/currency/hooks/ManageCurrencyContext.tsx new file mode 100644 index 0000000..f025f87 --- /dev/null +++ b/src/pages/master/currency/hooks/ManageCurrencyContext.tsx @@ -0,0 +1,199 @@ +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 { createContext, useCallback, useEffect, useMemo, useState } from 'react'; +import ListToolbar from '../blocks/ListToolbar'; +import DeleteDialog from '../blocks/DeleteDialog'; + +interface Currency { + id: string; + code: string; + name: string; + prefix: string; + status: string; +} + +interface ContextProps { + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_currency: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + showDeleteDialog: boolean; + handleDeleteDialog: (show: boolean, selected_currency: string | null) => void; + selectedCurrency: string | null; + currency: string | null; +} + +const initialProps: ContextProps = { + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + showDeleteDialog: false, + handleDeleteDialog: () => {}, + selectedCurrency: null, + currency: null +}; + +const ManageCurrencyContext = createContext(initialProps); +const API_URL = apiConfig.service_wallet; + +const ManageCurrencyContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const { GetData } = useCallApi(); + const [selectedCurrency, setSelectedCurrency] = useState(null); + const [currency, setCurrency] = useState(null); + + const handleEditDialog = useCallback((show: boolean, selected_currency: string | null) => { + setSelectedCurrency(show ? selected_currency : null); + setShowEditDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleDeleteDialog = useCallback((show: boolean, selected_currency: string | null) => { + setShowDeleteDialog(show); + setSelectedCurrency(show ? selected_currency : null); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + accessorFn: (row) => row.code, + id: 'code', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + accessorFn: (row) => row.prefix, + id: 'prefix', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + accessorFn: (row) => row.status, + id: 'status', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' }, + cell: ({ row }) => { + const isActive = row.original.status === 'Y'; + + return ( + + {isActive ? 'Active' : 'Inactive'} + + ); + } + }, + { + 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 doGetCurrency = async ( + page: number, + limit: number, + sorting: any + // filter: any + ) => { + // sorting = sorting.length == 0 ? [{ id: 'name', desc: true }] : sorting; + // filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; + // console.log(sorting); + const response = await GetData(`${API_URL}/dashboard/currency/`, { + limit, + page: page + 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'ASC' : 'DESC' + // filter: JSON.stringify(filter) + }); + // console.log(response?.data); + return { data: response?.data.list, totalCount: response?.data.total_count }; + }; + + return ( +
+ + + +
+ } + sorting={[{ id: 'ID', desc: true }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting }) => + doGetCurrency(pageIndex, pageSize, sorting) + } + > + {children} + +
+
+
+ ); +}; + +export { ManageCurrencyContext, ManageCurrencyContextProvider }; +export type { Currency }; diff --git a/src/pages/master/currency/hooks/useManageCurrencyContext.tsx b/src/pages/master/currency/hooks/useManageCurrencyContext.tsx new file mode 100644 index 0000000..6a9c80b --- /dev/null +++ b/src/pages/master/currency/hooks/useManageCurrencyContext.tsx @@ -0,0 +1,13 @@ +import { useContext } from 'react'; +import {ManageCurrencyContextProvider } from './ManageCurrencyContext'; +import { ManageCurrencyContext } from '../hooks/ManageCurrencyContext'; + +const useManageCurrencyContext = () => { + const context = useContext(ManageCurrencyContext); + + if (!context) throw new Error('useManageCurrencyContext must be used within AuthProvider'); + + return context; +}; + +export { useManageCurrencyContext }; diff --git a/src/pages/master/municipios/blocks/AddDialog.tsx b/src/pages/master/municipios/blocks/AddDialog.tsx index d2dfda4..61a6b3a 100644 --- a/src/pages/master/municipios/blocks/AddDialog.tsx +++ b/src/pages/master/municipios/blocks/AddDialog.tsx @@ -55,13 +55,13 @@ const AddDialog = () => { resetForm(); reload(); toast.success('Municipio created successfully!'); - // const createActivity = { - // module: 'Manage Municipio', - // description: `Create Municipio => ${selectedMunicipios}`, - // action: 'C' - // }; + const createActivity = { + module: 'Manage Municipios', + description: `Create Municipio => ${selectedMunicipios}`, + action: 'C' + }; - // doSaveLogActivity(createActivity); + doSaveLogActivity(createActivity); } else { toast.error('Failed to create municipio.'); setAlert({ show: true, message: 'Failed to create municipio. Please try again.' }); diff --git a/src/pages/master/municipios/blocks/DeleteDialog.tsx b/src/pages/master/municipios/blocks/DeleteDialog.tsx index f7e6f5d..ee742f5 100644 --- a/src/pages/master/municipios/blocks/DeleteDialog.tsx +++ b/src/pages/master/municipios/blocks/DeleteDialog.tsx @@ -4,9 +4,16 @@ import { useCallback, useState } from 'react'; import { apiConfig } from '@/config/api.config'; import { useCallApi } from '@/hooks'; import { toast } from 'sonner'; -import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { DialogDescription } from '@radix-ui/react-dialog'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL = apiConfig.service_master_data; @@ -25,16 +32,23 @@ const DeleteDialog = () => { return; } - const response = await DeleteData( - `${API_URL}/municipios/delete/${selectedMunicipios}/false`, - { id: selectedMunicipios } - ); + const response = await DeleteData(`${API_URL}/municipios/delete/${selectedMunicipios}/false`, { + id: selectedMunicipios + }); if (response?.status) { setAlert({ show: false, message: '' }); handleDeleteDialog(false, null); toast.success('Success Delete Municipio'); reload(); + + const createActivity = { + module: 'Manage Municipios', + description: `Edit Municipio',', => ${selectedMunicipios}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); } else { setAlert({ show: true, message: response?.message }); toast.error('Failed Delete Municipio'); @@ -43,7 +57,6 @@ const DeleteDialog = () => { return ( handleDeleteDialog(open, null)}> - diff --git a/src/pages/master/municipios/blocks/EditDialog.tsx b/src/pages/master/municipios/blocks/EditDialog.tsx index 50406bc..e7365c5 100644 --- a/src/pages/master/municipios/blocks/EditDialog.tsx +++ b/src/pages/master/municipios/blocks/EditDialog.tsx @@ -60,13 +60,13 @@ const EditDialog = () => { resetForm(); toast.success('Success update municipio'); reload(); - // const createActivity = { - // module: 'Manage Municipio', - // description: `Edit Municipio => ${selectedMunicipios}`, - // action: 'U' - // }; + const createActivity = { + module: 'Manage Municipios', + description: `Edit Municipio => ${selectedMunicipios}`, + action: 'U' + }; - // doSaveLogActivity(createActivity); + doSaveLogActivity(createActivity); } else { toast.error('Failed update user'); setAlert({ show: true, message: 'Failed to update municipio. Please try again.' }); diff --git a/src/pages/master/postoadms/blocks/AddDialog.tsx b/src/pages/master/postoadms/blocks/AddDialog.tsx index eaa8b1e..d489f75 100644 --- a/src/pages/master/postoadms/blocks/AddDialog.tsx +++ b/src/pages/master/postoadms/blocks/AddDialog.tsx @@ -24,6 +24,7 @@ import { CommandItem, CommandList } from '@/components/ui/command'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface MunicipioProps { id: number; @@ -34,7 +35,7 @@ const API_URL = apiConfig.service_master_data; const AddDialog = () => { const parentRef = useRef(null); - const { showAddDialog, handleAddDialog } = useManagePostoAdmsContext(); + const { showAddDialog, handleAddDialog, selectedPostoAdms } = useManagePostoAdmsContext(); const { reload } = useDataGrid(); const { PostData, GetData } = useCallApi(); const parsedUser = getAuth()?.user; @@ -72,6 +73,13 @@ const AddDialog = () => { resetForm(); reload(); toast.success('Posto Adm created successfully!'); + const createActivity = { + module: 'Manage Posto Administrativo', + description: `Create PostoAdms => ${selectedPostoAdms}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Failed to create Posto Adm. Please try again.'); setAlert({ show: true, message: 'Failed to create Posto Adm. Please try again.' }); diff --git a/src/pages/master/postoadms/blocks/DeleteDialog.tsx b/src/pages/master/postoadms/blocks/DeleteDialog.tsx index fca5448..eaca302 100644 --- a/src/pages/master/postoadms/blocks/DeleteDialog.tsx +++ b/src/pages/master/postoadms/blocks/DeleteDialog.tsx @@ -4,8 +4,16 @@ import { useCallApi } from '@/hooks'; import { useCallback, useState } from 'react'; import { apiConfig } from '@/config/api.config'; import { toast } from 'sonner'; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL = apiConfig.service_master_data; @@ -24,16 +32,22 @@ const DeleteDialog = () => { return; } - const response = await DeleteData( - `${API_URL}/postoadms/delete/${selectedPostoAdms}/false`, - { id: selectedPostoAdms } - ); + const response = await DeleteData(`${API_URL}/postoadms/delete/${selectedPostoAdms}/false`, { + id: selectedPostoAdms + }); if (response?.status) { setAlert({ show: false, message: '' }); handleDeleteDialog(false, null); toast.success('Success Delete Posto Adm'); reload(); + const createActivity = { + module: 'Manage Posto Administrativo', + description: `Edit PostoAdms => ${selectedPostoAdms}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); } else { setAlert({ show: true, message: response?.message }); toast.error('Failed Delete Posto Adm'); diff --git a/src/pages/master/postoadms/blocks/EditDialog.tsx b/src/pages/master/postoadms/blocks/EditDialog.tsx index d170d1a..532403b 100644 --- a/src/pages/master/postoadms/blocks/EditDialog.tsx +++ b/src/pages/master/postoadms/blocks/EditDialog.tsx @@ -24,6 +24,7 @@ import { CommandItem, CommandList } from '@/components/ui/command'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface MunicipioProps { id: number; @@ -72,6 +73,14 @@ const EditDialog = () => { resetForm(); toast.success('Success Update Posto Adm'); reload(); + + const createActivity = { + module: 'Manage Posto Administrativo', + description: `Edit PostoAdms => ${selectedPostoAdms}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Error Update Posto Adm'); setAlert({ show: true, message: 'Failed to update posto adm. Please try again.' }); diff --git a/src/pages/master/products/blocks/AddDialog.tsx b/src/pages/master/products/blocks/AddDialog.tsx index f5b7a57..ad917e2 100644 --- a/src/pages/master/products/blocks/AddDialog.tsx +++ b/src/pages/master/products/blocks/AddDialog.tsx @@ -22,6 +22,7 @@ import { SelectTrigger, SelectValue } from '@/components/ui/select'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface ProviderProps { provider_id: number; @@ -32,7 +33,7 @@ const API_URL = apiConfig.service_master_data; const AddDialog = () => { const parentRef = useRef(null); const parsedUser = getAuth()?.user; - const { showAddDialog, handleAddDialog } = useManageProductsContext(); + const { showAddDialog, handleAddDialog, selectedProducts } = useManageProductsContext(); const { PostData, GetData } = useCallApi(); const { reload } = useDataGrid(); const [alert, setAlert] = useState({ @@ -75,6 +76,14 @@ const AddDialog = () => { handleAddDialog(false); toast.success('Success Create Product'); reload(); + + const createActivity = { + module: 'Manage Products', + description: `Create Product => ${selectedProducts}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Failed Create Product'); setAlert({ show: true, message: response?.message }); @@ -173,9 +182,7 @@ const AddDialog = () => { className="input" type="text" value={formField.name} - onChange={(e) => - setFormField({ ...formField, name: e.target.value }) - } + onChange={(e) => setFormField({ ...formField, name: e.target.value })} /> @@ -189,9 +196,7 @@ const AddDialog = () => { className="input" type="text" value={formField.type} - onChange={(e) => - setFormField({ ...formField, type: e.target.value }) - } + onChange={(e) => setFormField({ ...formField, type: e.target.value })} /> @@ -205,9 +210,7 @@ const AddDialog = () => { className="input" type="text" value={formField.code} - onChange={(e) => - setFormField({ ...formField, code: e.target.value }) - } + onChange={(e) => setFormField({ ...formField, code: e.target.value })} /> @@ -221,9 +224,7 @@ const AddDialog = () => { className="input" type="text" value={formField.description} - onChange={(e) => - setFormField({ ...formField, description: e.target.value }) - } + onChange={(e) => setFormField({ ...formField, description: e.target.value })} /> @@ -323,9 +324,7 @@ const AddDialog = () => { table.getColumn('name')?.setFilterValue(event.target.value)} + value={(table.getColumn('provider_name')?.getFilterValue() as string) ?? ''} + onChange={(event) => + table.getColumn('provider_name')?.setFilterValue(event.target.value) + } /> {/* diff --git a/src/pages/master/provider/hooks/ManageProviderContext.tsx b/src/pages/master/provider/hooks/ManageProviderContext.tsx index 6dc7ea4..7d7bb5f 100644 --- a/src/pages/master/provider/hooks/ManageProviderContext.tsx +++ b/src/pages/master/provider/hooks/ManageProviderContext.tsx @@ -75,7 +75,7 @@ const ManageProviderContextProvider = ({ children }: { children: React.ReactNode () => [ { accessorFn: (row) => row.provider_name, - id: 'name', + id: 'provider_name', header: ({ column }) => , enableSorting: true, enableHiding: false, @@ -162,8 +162,9 @@ const ManageProviderContextProvider = ({ children }: { children: React.ReactNode const getProviderLists = async (page: number, limit: number, sorting: any, filter: any) => { try { + const field = 'Provider.name'; sorting = sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting; - filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; + filter = filter.length == 0 ? {} : { [field]: filter[0].value?.toLowerCase() }; const response = await GetData(`${API_URL}/provider/list`, { limit, page: page + 1, @@ -172,7 +173,7 @@ const ManageProviderContextProvider = ({ children }: { children: React.ReactNode order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', filter: JSON.stringify(filter) }); - console.log(response?.data); + // console.log(response?.data); setProvider(response?.data.list); return { data: response?.data.list, totalCount: response?.data.total_count }; } catch (error) { diff --git a/src/pages/master/sucos/blocks/AddDialog.tsx b/src/pages/master/sucos/blocks/AddDialog.tsx index 4436fd1..de45ad3 100644 --- a/src/pages/master/sucos/blocks/AddDialog.tsx +++ b/src/pages/master/sucos/blocks/AddDialog.tsx @@ -24,6 +24,7 @@ import { CommandItem, CommandList } from '@/components/ui/command'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface PostoAdmsProps { PostoAdms_id: number; @@ -33,7 +34,7 @@ const API_URL = apiConfig.service_master_data; const AddDialog = () => { const parentRef = useRef(null); - const { showAddDialog, handleAddDialog } = useManageSucosContext(); + const { showAddDialog, handleAddDialog, selectedSucos } = useManageSucosContext(); const { reload } = useDataGrid(); const { PostData, GetData } = useCallApi(); const parsedUser = getAuth()?.user; @@ -69,6 +70,13 @@ const AddDialog = () => { handleAddDialog(false); reload(); toast.success('Sucos created successfully!'); + const createActivity = { + module: 'Manage Sucos', + description: `Create Suco => ${selectedSucos}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Failed to create Sucos Please try again.'); setAlert({ show: true, message: 'Failed to create Sucos Please try again.' }); diff --git a/src/pages/master/sucos/blocks/DeleteDialog.tsx b/src/pages/master/sucos/blocks/DeleteDialog.tsx index 440ee6a..9786b99 100644 --- a/src/pages/master/sucos/blocks/DeleteDialog.tsx +++ b/src/pages/master/sucos/blocks/DeleteDialog.tsx @@ -4,8 +4,16 @@ import { useCallback, useState } from 'react'; import { useCallApi } from '@/hooks'; import { Alert, useDataGrid } from '@/components'; import { toast } from 'sonner'; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL = apiConfig.service_master_data; @@ -31,6 +39,13 @@ const DeleteDialog = () => { handleDeleteDialog(false, null); toast.success('Success Delete Sucos'); reload(); + const createActivity = { + module: 'Manage Sucos', + description: `Edit Suco => ${selectedSucos}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); } else { setAlert({ show: true, message: response?.message }); toast.error('Failed Delete Sucos'); diff --git a/src/pages/master/sucos/blocks/EditDialog.tsx b/src/pages/master/sucos/blocks/EditDialog.tsx index 68b7bcd..54419cf 100644 --- a/src/pages/master/sucos/blocks/EditDialog.tsx +++ b/src/pages/master/sucos/blocks/EditDialog.tsx @@ -24,6 +24,7 @@ import { CommandItem, CommandList } from '@/components/ui/command'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface PostoAdmsProps { PostoAdms_id: number; // Ubah ke PostoAdms_id @@ -76,6 +77,13 @@ const EditDialog = () => { handleEditDialog(false, null); toast.success('Success Update Sucos'); reload(); + const createActivity = { + module: 'Manage Sucos', + description: `Edit Suco => ${selectedSucos}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Failed Update Sucos'); setAlert({ show: true, message: 'Failed Update Sucos. Please try again' }); diff --git a/src/pages/master/sucos/hooks/ManageSucosContext.tsx b/src/pages/master/sucos/hooks/ManageSucosContext.tsx index 81e38a6..6a888b1 100644 --- a/src/pages/master/sucos/hooks/ManageSucosContext.tsx +++ b/src/pages/master/sucos/hooks/ManageSucosContext.tsx @@ -153,7 +153,7 @@ const ManageSucosContextProvider = ({ children }: { children: React.ReactNode }) const response = await GetData(`${API_URL}/sucos/list`, { limit: limit, page: page + 1, - with_deleted: true, + with_deleted: false, order_field: sorting[0].id, order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', filter: JSON.stringify(filter) diff --git a/src/pages/master/wallet/WalletMaster.tsx b/src/pages/master/wallet/WalletMaster.tsx index d319707..3190787 100644 --- a/src/pages/master/wallet/WalletMaster.tsx +++ b/src/pages/master/wallet/WalletMaster.tsx @@ -3,7 +3,6 @@ import { ManageWalletContextProvider } from './hooks/ManageWalletContext'; import { Breadcrumbs, Link } from '@mui/material'; import AddDialog from './blocks/AddDialog'; import EditDialog from './blocks/EditDialog'; -import DeleteDialog from './blocks/DeleteDialog'; const WalletMaster = () => { return ( @@ -28,7 +27,6 @@ const WalletMaster = () => { - ); diff --git a/src/pages/master/wallet/blocks/AddDialog.tsx b/src/pages/master/wallet/blocks/AddDialog.tsx index b8100ba..ce8a07a 100644 --- a/src/pages/master/wallet/blocks/AddDialog.tsx +++ b/src/pages/master/wallet/blocks/AddDialog.tsx @@ -22,6 +22,7 @@ import { } from '@/components/ui/select'; import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface CurrencyProps { ID: string; @@ -42,7 +43,7 @@ const API_URL_WALLET = apiConfig.service_wallet; const API_URL_MASTER_DATA = apiConfig.service_master_data; const AddDialog = () => { - const { showAddDialog, handleAddDialog } = useManageWalletContext(); + const { showAddDialog, handleAddDialog, selectedWallet } = useManageWalletContext(); const { GetData, PostData } = useCallApi(); const { reload } = useDataGrid(); const [alert, setAlert] = useState({ @@ -101,6 +102,14 @@ const AddDialog = () => { handleAddDialog(false); toast.success('Success Create Wallet'); reload(); + + const createActivity = { + module: 'Manage Wallet', + description: `Create Wallet => ${selectedWallet?.Wallet_id} - ${selectedWallet?.Wallet_name}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Failed Create Wallet'); setAlert({ show: true, message: 'Failed Create Wallet' }); diff --git a/src/pages/master/wallet/blocks/EditDialog.tsx b/src/pages/master/wallet/blocks/EditDialog.tsx index c5faae1..09167d3 100644 --- a/src/pages/master/wallet/blocks/EditDialog.tsx +++ b/src/pages/master/wallet/blocks/EditDialog.tsx @@ -21,6 +21,7 @@ import { SelectValue } from '@/components/ui/select'; import { Button } from '@/components/ui/button'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface CurrencyProps { ID: string; @@ -53,13 +54,11 @@ const EditDialog = () => { description: string; status: string; group: string[]; - currency_id: string; } = { name: '', description: '', status: '', - group: [], - currency_id: '' + group: [] }; const [formField, setFormField] = useState(initialState); const [currencies, setCurrencies] = useState([]); @@ -71,18 +70,26 @@ const EditDialog = () => { }; const doUpdateWallet = useCallback( - async (e: React.FormEvent) => { - e.preventDefault(); + async (payload: { name: string; description: string; status: string }) => { + // e.preventDefault(); const response = await PutData( `${API_URL_MASTER_DATA}/wallet/update/${selectedWallet?.Wallet_id}`, - formField + payload ); if (response?.status) { handleEditDialog(false, null); toast.success('Success Update Wallet'); reload(); + + const createActivity = { + module: 'Manage Wallet', + description: `Edit Wallet => ${selectedWallet?.Wallet_id} - ${selectedWallet?.Wallet_name}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Failed Update Wallet'); setAlert({ show: true, message: 'Failed Update Wallet' }); @@ -94,8 +101,14 @@ const EditDialog = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - console.log(formField); - doUpdateWallet(e); + // const { name, description, status } = formField; + const payload = { + name: formField.name, + description: formField.description, + status: formField.status + }; + // console.log(payload); + doUpdateWallet(payload); setAlert({ show: false, message: '' }); }; @@ -156,8 +169,6 @@ const EditDialog = () => { .map((g) => g.name) .join(', '); - const selectedCurrency = currencies.find((currency) => currency.ID === formField.currency_id); - useEffect(() => { getCurrencyLists([{ id: 'name', desc: false }]); getGroupLists([{ id: 'name', desc: false }]); @@ -182,7 +193,7 @@ const EditDialog = () => { resetForm(); } }, [showEditDialog]); - // console.log(selectedWallet); + return ( handleEditDialog(open, null)}> @@ -246,17 +257,10 @@ const EditDialog = () => { -
-
- - -
-
-
- +
@@ -264,7 +268,9 @@ const EditDialog = () => { - + diff --git a/src/pages/master/wallet/blocks/ListToolbar.tsx b/src/pages/master/wallet/blocks/ListToolbar.tsx index 0d2a427..11b5767 100644 --- a/src/pages/master/wallet/blocks/ListToolbar.tsx +++ b/src/pages/master/wallet/blocks/ListToolbar.tsx @@ -15,7 +15,7 @@ const ListToolbar = () => { table.getColumn('name')?.setFilterValue(event.target.value)} /> diff --git a/src/pages/master/wallet/hooks/ManageWalletContext.tsx b/src/pages/master/wallet/hooks/ManageWalletContext.tsx index d92f73d..0108aa4 100644 --- a/src/pages/master/wallet/hooks/ManageWalletContext.tsx +++ b/src/pages/master/wallet/hooks/ManageWalletContext.tsx @@ -131,12 +131,6 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } > - ); }, @@ -152,7 +146,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } const getWalletLists = 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() }; + filter = filter.length == 0 ? {} : { name: filter[0].value?.toLowerCase() }; const response = await GetData(`${API_URL_MASTER_DATA}/wallet/list`, { limit, page: page + 1, @@ -189,7 +183,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } pagination={{ size: 25 }} toolbar={} layout={{ card: true }} - sorting={[{ id: 'id', desc: false }]} + sorting={[{ id: 'name', desc: false }]} serverSide={true} onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => getWalletLists(pageIndex, pageSize, sorting, columnFilters) diff --git a/src/pages/master/walletRule/blocks/AddDialog.tsx b/src/pages/master/walletRule/blocks/AddDialog.tsx index f18cd89..6bdd088 100644 --- a/src/pages/master/walletRule/blocks/AddDialog.tsx +++ b/src/pages/master/walletRule/blocks/AddDialog.tsx @@ -31,6 +31,7 @@ import { CommandList } from '@/components/ui/command'; import { NumericFormat } from 'react-number-format'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface GroupProps { ID: string; @@ -48,7 +49,7 @@ interface WalletProps { const API_URL_WALLET = apiConfig.service_wallet; const AddDialog = () => { - const { showAddDialog, handleAddDialog } = useManageWalletRuleContext(); + const { showAddDialog, handleAddDialog, selectedWalletRule } = useManageWalletRuleContext(); const { reload } = useDataGrid(); const { PostData, GetData } = useCallApi(); const [open, setOpen] = useState(false); @@ -94,6 +95,14 @@ const AddDialog = () => { handleAddDialog(false); toast.success('Success Create Wallet Rule'); reload(); + + const createActivity = { + module: 'Manage Wallet Rule', + description: `Create Wallet Rule => ${selectedWalletRule?.ID}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Failed Create Wallet Rule'); setAlert({ show: true, message: 'Failed Create Wallet Rule' }); diff --git a/src/pages/master/walletRule/blocks/DeleteDialog.tsx b/src/pages/master/walletRule/blocks/DeleteDialog.tsx index 97f3e0c..1602b3a 100644 --- a/src/pages/master/walletRule/blocks/DeleteDialog.tsx +++ b/src/pages/master/walletRule/blocks/DeleteDialog.tsx @@ -13,6 +13,7 @@ import { DialogTitle } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL_WALLET = apiConfig.service_wallet; @@ -37,6 +38,13 @@ const DeleteDialog = () => { toast.success('Wallet rule deleted successfully'); handleDeleteDialog(false, null); reload(); + const createActivity = { + module: 'Manage Wallet Rule', + description: `Edit Wallet Rule', => ${selectedWalletRule.ID}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); setAlert({ show: false, message: '' }); } else { toast.error('Failed to delete wallet rule'); diff --git a/src/pages/master/walletRule/blocks/EditDialog.tsx b/src/pages/master/walletRule/blocks/EditDialog.tsx index 8529c3f..b555d06 100644 --- a/src/pages/master/walletRule/blocks/EditDialog.tsx +++ b/src/pages/master/walletRule/blocks/EditDialog.tsx @@ -31,6 +31,7 @@ import { import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { NumericFormat } from 'react-number-format'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface GroupProps { ID: string; @@ -97,6 +98,14 @@ const EditDialog = () => { handleEditDialog(false, null); toast.success('Success Update Wallet Rule'); reload(); + + const createActivity = { + module: 'Manage Wallet Rule', + description: `Edit Wallet Rule => ${selectedWalletRule?.ID}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); } else { toast.error('Failed Update Wallet Rule'); setAlert({ show: true, message: 'Failed Update Wallet Rule' }); diff --git a/src/pages/menu/manage-menu/blocks/AddDIalog.tsx b/src/pages/menu/manage-menu/blocks/AddDIalog.tsx index beb6cc4..d7c2f2f 100644 --- a/src/pages/menu/manage-menu/blocks/AddDIalog.tsx +++ b/src/pages/menu/manage-menu/blocks/AddDIalog.tsx @@ -21,10 +21,11 @@ import { SelectTrigger, SelectValue } from '@/components/ui/select'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL = apiConfig.service_dashboard; const AddDialog = () => { - const { showAddDialog, handleAddDialog, parents } = useManageMenusContext(); + const { showAddDialog, handleAddDialog, parents, selectedMenu } = useManageMenusContext(); const { reload } = useDataGrid(); const { PostData } = useCallApi(); const [open, setOpen] = useState(false); @@ -57,21 +58,28 @@ const AddDialog = () => { return; } - console.log('Data dikirim ke API:', formField); + // console.log('Data dikirim ke API:', formField); const response = await PostData(`${API_URL}/menus/create`, formField); - console.log('Response from API:', response); + // console.log('Response from API:', response); if (response?.status) { handleAddDialog(false); resetForm(); toast.success('Success Create Menu'); + const createActivity = { + module: 'Manage Menu', + description: `Create Menu => ${selectedMenu}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); reload(); } else { toast.error('Failed Create Menu'); setAlert({ show: true, message: 'Failed Create Menu' }); } - console.log(formField); + // console.log(formField); setAlert({ show: false, message: '' }); }; diff --git a/src/pages/menu/manage-menu/blocks/DeleteDialog.tsx b/src/pages/menu/manage-menu/blocks/DeleteDialog.tsx index b5250eb..a1ddb07 100644 --- a/src/pages/menu/manage-menu/blocks/DeleteDialog.tsx +++ b/src/pages/menu/manage-menu/blocks/DeleteDialog.tsx @@ -14,6 +14,7 @@ import { } 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_dashboard; const DeleteDialog = () => { @@ -34,6 +35,13 @@ const DeleteDialog = () => { setAlert((prev) => ({ ...prev, show: false, message: '' })); handleDeleteDialog(false, null); toast.success('Success Delete Menu'); + const createActivity = { + module: 'Manage Menu', + description: `DeleteMenu => ${selectedMenu}`, + action: 'D' + }; + + doSaveLogActivity(createActivity); reload(); } else { toast.error('Failed Delete Menu'); diff --git a/src/pages/menu/manage-menu/blocks/EditDialog.tsx b/src/pages/menu/manage-menu/blocks/EditDialog.tsx index 6a40e87..42142ae 100644 --- a/src/pages/menu/manage-menu/blocks/EditDialog.tsx +++ b/src/pages/menu/manage-menu/blocks/EditDialog.tsx @@ -22,6 +22,7 @@ import { SelectTrigger, SelectValue } from '@/components/ui/select'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL = apiConfig.service_dashboard; @@ -69,6 +70,13 @@ const EditDialog = () => { handleEditDialog(false, null); resetForm(); toast.success('Success Update Menu'); + const createActivity = { + module: 'Manage Menu', + description: `Update Menu => ${selectedMenu}`, + action: 'U' + }; + + doSaveLogActivity(createActivity); reload(); } else { toast.error('Failed Update Menu'); diff --git a/src/pages/transaction/approval-transaction/ApprovalTransaction.tsx b/src/pages/transaction/approval-transaction/ApprovalTransaction.tsx new file mode 100644 index 0000000..e6aa68b --- /dev/null +++ b/src/pages/transaction/approval-transaction/ApprovalTransaction.tsx @@ -0,0 +1,31 @@ +import { Container, DataGridInner } from '@/components'; +import { ApprovalTransactionProvider } from './hooks/ApprovalTransactionContext'; +import { Breadcrumbs, Link } from '@mui/material'; + +const ApprovalTransaction = () => { + return ( + + +

TRANSACTION

+ + + Dashboard + + + + Transaction + + + + Approval Transaction + + +
+ +
+
+
+ ); +}; + +export default ApprovalTransaction; diff --git a/src/pages/transaction/approval-transaction/blocks/DetailApprovalTransaction.tsx b/src/pages/transaction/approval-transaction/blocks/DetailApprovalTransaction.tsx new file mode 100644 index 0000000..e0d0ecc --- /dev/null +++ b/src/pages/transaction/approval-transaction/blocks/DetailApprovalTransaction.tsx @@ -0,0 +1,538 @@ +import { useTransactionContext } from '../hooks/useApprovalTransactionContext'; +import { useCallApi } from '@/hooks'; +import { apiConfig } from '@/config/api.config'; +import { useEffect, useState } from 'react'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; + +const API_URL = apiConfig.transaction; + +const DetailApprovalTransaction = () => { + const { GetData } = useCallApi(); + const { + showDetailDialog, + setShowDetailDialog, + selectedTransactionId + } = useTransactionContext(); + + const [transactionDetails, setTransactionDetails] = useState(null); + + useEffect(() => { + const fetchTransactionDetails = async () => { + if (selectedTransactionId) { + try { + const response = await GetData(`${API_URL}/transaction/history/detail/${selectedTransactionId}`, { + id: selectedTransactionId + }); + // console.log(response?.data); + setTransactionDetails(response?.data); + } catch (error) { + console.error('Error fetching transaction', error); + } + } + }; + + if (showDetailDialog && selectedTransactionId) { + fetchTransactionDetails(); + } + }, [showDetailDialog, selectedTransactionId, GetData]); + + const [activeTab, setActiveTab] = useState('detail'); // 'detail', 'log', 'approve' + + return ( + + + + Transaction Details + + + {/* Tabs Navigation */} +
+ + + + + +
+ + {/* Tab Content */} +
+ {activeTab === 'detail' && transactionDetails?.kind === 'P' && ( +
+

+ Transaction Information + + Info + +

+
+
+

Transaction Date

+

{transactionDetails?.transaction_date}

+
+
+

Full Name

+

{transactionDetails?.origin_customer.fullname}

+
+
+

Amount

+

{new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(transactionDetails?.purchase.amount)}

+
+
+

Fee

+

+ {transactionDetails?.kind === 'P' + ? transactionDetails?.purchase.fee_amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' }) + : transactionDetails?.transfer.fee_amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' })} +

+
+
+

Status

+

+ {(() => { + let status; + if (transactionDetails?.status === 'C') { + status = 'COMPLETE'; + } else if (transactionDetails?.status === 'F') { + status = 'FAILED'; + } else if (transactionDetails?.status === 'O') { + status = 'ON PROCESS'; + } else { + status = 'PENDING'; + } + return status; + })()} +

+
+
+

Transaction Type

+

+ {(() => { + let kind; + if (transactionDetails?.kind === 'T') { + kind = 'TRANSFER'; + } else if (transactionDetails?.kind === 'P') { + kind = 'PURCHASE'; + } else if (transactionDetails?.kind === 'W') { + kind = 'WITHDRAW'; + } else if (transactionDetails?.kind === 'U') { + kind = 'TOP UP'; + } else if (transactionDetails?.kind === 'R') { + kind = 'RETURN'; + } + return kind; + })()} +

+
+
+

Description

+

{transactionDetails?.description}

+
+
+

Name

+

{transactionDetails?.type.name}

+
+
+ +

+ Origin Wallet + + Wallet + +

+
+
+

Name

+

{transactionDetails?.origin_wallet.name}

+
+
+

Description

+

{transactionDetails?.origin_wallet.description}

+
+
+ +

+ Purchase + + Purchase + +

+
+
+

Amount

+

{new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(transactionDetails?.purchase.amount)}

+
+
+

Cashback

+

{new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(transactionDetails?.purchase.cashback)}

+
+
+

Cashback Point

+

{transactionDetails?.purchase.cashback_point}

+
+
+

Fee Amount

+

{new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(transactionDetails?.purchase.fee_amount)}

+
+
+
+ )} + + {activeTab === 'detail' && transactionDetails?.kind != 'P' && transactionDetails?.transfer!=null && ( +
+

+ Transaction Information + + Info + +

+
+
+

Transaction Date

+

{transactionDetails?.transaction_date}

+
+
+

Full Name

+

{transactionDetails?.origin_customer.fullname}

+
+
+

Amount

+

{new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(transactionDetails?.transfer.amount)}

+
+
+

Fee

+

+ {transactionDetails?.transfer.fee_amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' })} +

+
+
+

Status

+

+ {(() => { + let status; + if (transactionDetails?.status === 'C') { + status = 'COMPLETE'; + } else if (transactionDetails?.status === 'F') { + status = 'FAILED'; + } else if (transactionDetails?.status === 'O') { + status = 'ON PROCESS'; + } else { + status = 'PENDING'; + } + return status; + })()} +

+
+
+

Transaction Type

+

+ {(() => { + let kind; + if (transactionDetails?.kind === 'T') { + kind = 'TRANSFER'; + } else if (transactionDetails?.kind === 'P') { + kind = 'PURCHASE'; + } else if (transactionDetails?.kind === 'W') { + kind = 'WITHDRAW'; + } else if (transactionDetails?.kind === 'U') { + kind = 'TOP UP'; + } else if (transactionDetails?.kind === 'R') { + kind = 'RETURN'; + } + return kind; + })()} +

+
+
+

Description

+

{transactionDetails?.description}

+
+
+

Name

+

{transactionDetails?.type.name}

+
+
+

Reference

+

{transactionDetails?.transfer.reference}

+
+
+

Destination Iban

+

{transactionDetails?.transfer.destination_iban}

+
+
+ +

+ Destination Wallet + + Wallet + +

+
+
+

Name

+

{transactionDetails?.transfer.destination_wallet.name}

+
+
+

Description

+

{transactionDetails?.transfer.destination_wallet.description}

+
+
+ +

+ Destination Customer + + Destination Customer + +

+
+
+

Name

+

{transactionDetails?.transfer.destination_customer.fullname}

+
+
+

MSISDN

+

{transactionDetails?.transfer.destination_customer.msisdn}

+
+
+

Email

+

{transactionDetails?.transfer.destination_customer.email}

+
+
+

MSISDN

+

{transactionDetails?.transfer.destination_customer.username}

+
+
+ +

+ Origin Wallet + + Wallet + +

+
+
+

Name

+

{transactionDetails?.origin_wallet.name}

+
+
+

Description

+

{transactionDetails?.origin_wallet.description}

+
+
+
+ )} + + + {activeTab === 'origincustomer' && ( +
+

Origin Customer

+
+
+

Full Name

+

{transactionDetails?.origin_customer.fullname}

+
+
+

Phone Number

+

{transactionDetails?.origin_customer.msisdn}

+
+
+

Email

+

{transactionDetails?.origin_customer.email}

+
+
+

Username

+

{transactionDetails?.origin_customer.username}

+
+
+
+ )} + + {activeTab === 'log' && ( +
+

Transaction Logs

+
+ + + + + + + + + + + + + {transactionDetails?.log && transactionDetails?.log.length > 0 ? ( + transactionDetails.log.map((log: { request_endpoint: string, status: string; request_date: string; response_date: string; request_body: string; response_body: string; response_code: number }, index: number) => ( + + + + + + + + + )) + ) : ( + + + + )} + +
StatusRequest DateRequest BodyResponse BodyResponse CodeRequest End Point
+ {(() => { + let status; + if (log.status === 'P') { + status = 'PENDING'; + } else if (log.status === 'O') { + status = 'ON PROCESS'; + } else if (log.status === 'F') { + status = 'FAILED'; + } else if (log.status === 'C') { + status = 'COMPLETE'; + } + return status; + })()} + {log.request_date ?? '-'}{log.response_date ?? '-'}{log.request_body ?? '-'}{log.response_body ?? '-'}{log.request_endpoint ?? '-'}
+ No logs available +
+
+
+ )} + + {activeTab === 'approve' && ( +
+

Approval Logs

+ {transactionDetails?.log_approve.length === 0 ? ( +

No data available

+ ) : ( +
+ + + + + + + + + + {transactionDetails?.log_approve && transactionDetails?.log_approve.length > 0 ? ( + transactionDetails.log_approve.map((log: { created_at: string; status: string; updated_at: string }, index: number) => ( + + + + + + )) + ) : ( + + + + )} + +
StatusCreated AtUpdated At
+ {(() => { + let status; + if (log.status === 'W') { + status = 'WAITING'; + } else if (log.status === 'Y') { + status = 'APPROVE'; + } else if (log.status === 'N') { + status = 'REJECT'; + } else if (log.status === 'T') { + status = 'NO NEED'; + } + return status; + })()} + {log.created_at}{log.updated_at}
+ No logs available +
+
+ )} +
+ )} + + {activeTab === 'p24' && ( +
+

P24 Logs

+ {transactionDetails?.p24.length === 0 ? ( +

No data available

+ ) : ( +
+ + + + + + + + + + + + + {transactionDetails?.p24 && transactionDetails?.p24.length > 0 ? ( + transactionDetails.p24.map((log: { request_endpoint: string, type: string; request_date: string; response_date: string; request_body: string; response_body: string; response_code: number }, index: number) => ( + + + + + + + + + )) + ) : ( + + + + )} + +
TypeRequest DateRequest BodyResponse BodyResponse CodeRequest Endpoint
{log.type}{log.request_date}{log.response_date}{log.request_body}{log.response_body}{log.request_endpoint ?? '-'}
+ No logs available +
+
+ )} +
+ )} + +
+
+
+
+ ); +}; + +export default DetailApprovalTransaction; diff --git a/src/pages/transaction/approval-transaction/blocks/ListToolbar.tsx b/src/pages/transaction/approval-transaction/blocks/ListToolbar.tsx new file mode 100644 index 0000000..3247955 --- /dev/null +++ b/src/pages/transaction/approval-transaction/blocks/ListToolbar.tsx @@ -0,0 +1,82 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useTransactionContext } from '../hooks/useApprovalTransactionContext'; +import { Button } from '@/components/ui/button'; +import { useCallback, useState, useEffect } from 'react'; +import { toast } from 'sonner'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + + // Set the initial state for trxDate + const [trxDate, settrxDate] = useState({ from: '', to: '' }); + + // Function to format date to YYYY-MM-DD + const formatDate = (date: Date): string => { + return date.toISOString().split('T')[0]; + }; + + // useEffect to set the default date values + useEffect(() => { + const today = new Date(); + const nextWeek = new Date(today); + nextWeek.setDate(today.getDate() + 7); + + settrxDate({ + from: formatDate(today), // Set 'from' to today + to: formatDate(nextWeek), // Set 'to' to 7 days later + }); + }, []); + + const handleFilterData = useCallback(() => { + try { + table.getColumn('transaction_date')?.setFilterValue(trxDate); + } catch (error) { + toast.error('Error applying filter'); + console.error('Error applying filter:', error); + } + }, [trxDate, table]); + + useEffect(() => { + if (trxDate.from && trxDate.to) { + handleFilterData(); + } + }, [trxDate]); + + return ( +
+
+
+
+ + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/transaction/approval-transaction/hooks/ApprovalTransactionContext.tsx b/src/pages/transaction/approval-transaction/hooks/ApprovalTransactionContext.tsx new file mode 100644 index 0000000..91c87c2 --- /dev/null +++ b/src/pages/transaction/approval-transaction/hooks/ApprovalTransactionContext.tsx @@ -0,0 +1,268 @@ +import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; +import { Toaster } from '@/components/ui/sonner'; +import { apiConfig } from '@/config/api.config'; +import { ColumnDef } from '@tanstack/react-table'; +import axios from 'axios'; +import React, { createContext, useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallApi } from '@/hooks'; +import ListToolbar from '../blocks/ListToolbar'; +import { Button } from '@/components/ui/button'; +import { useNavigate } from 'react-router'; +import DetailApprovalTransaction from '../blocks/DetailApprovalTransaction'; + +interface ApprovalTransactionProps { + id: number; + name: string; +} + +interface ContextProps { + getTransactionLists: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: any, + order_direction: any, + filter: any + ) => Promise<{ data: ApprovalTransactionProps[]; totalCount: number } | undefined>; + showDetailDialog: boolean; + setShowDetailDialog: React.Dispatch>; + selectedTransactionId: number | null; + setSelectedTransactionId: React.Dispatch>; +} + +const initialProps: ContextProps = { + getTransactionLists: async () => ({ data: [], totalCount: 0 }), + showDetailDialog: false, + setShowDetailDialog: () => { }, + selectedTransactionId: null, + setSelectedTransactionId: () => { } +}; + +const ManageApprovalTransactionContext = createContext(initialProps); +const API_URL = apiConfig.transaction; + +const ApprovalTransactionProvider = ({ children }: { children: React.ReactNode }) => { + const [showDetailDialog, setShowDetailDialog] = useState(false); + const [selectedTransactionId, setSelectedTransactionId] = useState(null); + const [transaction, setTransaction] = useState([]); + const { GetData } = useCallApi(); + const navigate = useNavigate(); + const handleNavigate = (path: string) => { + const url = navigate(`${API_URL}/transaction/history/${path}`); + }; + + const columns = useMemo[]>( + () => [ + // { + // accessorKey: 'transaction_date', + // header: ({ column }) => , + // enableSorting: false, + // enableHiding: false, + // meta: { + // headerClassName: 'w-[250px]' + // } + // }, + { + accessorKey: 'transaction_date', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + }, + cell: ({ row }) => { + // Memformat tanggal dan waktu dari ISO ke format biasa (DD-MM-YYYY HH:MM:SS) + const transactionDate = new Date(row.original.transaction_date); + const formattedDateTime = transactionDate.toLocaleString('en-GB', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hour12: false // Gunakan format 24 jam + }); + return formattedDateTime; // Format DD-MM-YYYY HH:MM:SS (menggunakan waktu yang sudah ada) + } + }, + { + accessorKey: 'origin_customer.fullname', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorFn: (row) => { + const purchaseAmount = row?.purchase?.amount; + const transferAmount = row?.transfer?.amount; + + return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(purchaseAmount ?? transferAmount ?? 0); + }, + id: 'amount', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]', + }, + }, + { + accessorFn: (row) => { + const purchaseAmount = row?.purchase?.fee_amount; + const transferAmount = row?.transfer?.fee_amount; + + return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(purchaseAmount ?? transferAmount ?? 0); + }, + id: 'feeamount', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]', + }, + }, + { + accessorFn: (row) => { + let status; + if (row.status === 'C') { + status = 'COMPLETE'; + } else if (row.status === 'F') { + status = 'FAILED'; + } else if (row.status === 'O') { + status = 'ON PROCESS'; + } else { + status = 'PENDING'; + } + return status; + }, + accessorKey: 'status', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]', + }, + }, + { + accessorKey: 'description', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + } + }, + { + accessorKey: 'type.name', + header: ({ column }) => , + enableSorting: false, + 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 getTransactionLists = async (page: number, limit: number, sorting: any, filter: any) => { + try { + let startdate; + let enddate; + let formattedFilter; + + if (filter == undefined || filter.length == 0) { + const today = new Date(); + const nextWeek = new Date(); + nextWeek.setDate(today.getDate() + 7); + + startdate = today.toISOString().split('T')[0]; + enddate = nextWeek.toISOString().split('T')[0]; + } else if (filter != undefined || filter.length != 0) { + startdate = filter[0].value.from; + enddate = filter[0].value.to; + } + + formattedFilter = { + "Transactions.transaction_date": { + from: startdate + " 00:00:00", + to: enddate + " 23:59:59" + } + }; + + const response = await GetData(`${API_URL}/transaction/history`, { + limit, + page: page + 1, + with_deleted: false, + order_field: "Transactions.created_at", + order_direction: 'DESC', + filter: JSON.stringify(formattedFilter) + }); + + setTransaction(response?.data.list); + return { data: response?.data.list, totalCount: response?.data.total_count }; + } catch (error) { + console.error('Error fetching transaction', error); + } + }; + + return ( + + + + + } + layout={{ card: true }} + sorting={[{ id: 'id', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + getTransactionLists(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + + + ); +}; + +export { ApprovalTransactionProvider, ManageApprovalTransactionContext }; +export type { ApprovalTransactionProps }; diff --git a/src/pages/transaction/approval-transaction/hooks/useApprovalTransactionContext.tsx b/src/pages/transaction/approval-transaction/hooks/useApprovalTransactionContext.tsx new file mode 100644 index 0000000..3f93690 --- /dev/null +++ b/src/pages/transaction/approval-transaction/hooks/useApprovalTransactionContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageApprovalTransactionContext } from './ApprovalTransactionContext'; + +const useTransactionContext = () => { + const context = useContext(ManageApprovalTransactionContext); + + if (!context) throw new Error('useTransactionContext must be used within AuthProvider'); + + return context; +}; + +export { useTransactionContext }; diff --git a/src/pages/transaction/Transaction.tsx b/src/pages/transaction/history-transaction/Transaction.tsx similarity index 93% rename from src/pages/transaction/Transaction.tsx rename to src/pages/transaction/history-transaction/Transaction.tsx index 9456873..3afcc68 100644 --- a/src/pages/transaction/Transaction.tsx +++ b/src/pages/transaction/history-transaction/Transaction.tsx @@ -17,7 +17,7 @@ const Transaction = () => { - Transaction + History Transaction
diff --git a/src/pages/transaction/blocks/DetailTransaction.tsx b/src/pages/transaction/history-transaction/blocks/DetailTransaction.tsx similarity index 93% rename from src/pages/transaction/blocks/DetailTransaction.tsx rename to src/pages/transaction/history-transaction/blocks/DetailTransaction.tsx index ec5dd9f..5f3ad0d 100644 --- a/src/pages/transaction/blocks/DetailTransaction.tsx +++ b/src/pages/transaction/history-transaction/blocks/DetailTransaction.tsx @@ -208,8 +208,44 @@ const DetailTransaction = () => {
)} + {activeTab === 'detail' && transactionDetails?.kind === 'P' && ( +
+

+ Product Information + + Product Info + +

+
+
+

Product Name

+

{transactionDetails?.purchase.product.name}

+
+
+

Price Cash

+ {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(transactionDetails?.purchase.product.price_cash)} +
+
+

Price Point

+ {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(transactionDetails?.purchase.product.price_point)} +
+
+

Product Type

+

{transactionDetails?.purchase.product.type}

+
+
+

Provider Name

+

{transactionDetails?.purchase.product.provider.description}

+
+
+

Provider Type

+

{transactionDetails?.purchase.product.provider.type}

+
+
+
+ )} - {activeTab === 'detail' && transactionDetails?.kind != 'P' && transactionDetails?.transfer!=null && ( + {activeTab === 'detail' && transactionDetails?.kind != 'P' && transactionDetails?.transfer != null && (

Transaction Information diff --git a/src/pages/transaction/blocks/ListToolbar.tsx b/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx similarity index 100% rename from src/pages/transaction/blocks/ListToolbar.tsx rename to src/pages/transaction/history-transaction/blocks/ListToolbar.tsx diff --git a/src/pages/transaction/hooks/TransactionContext.tsx b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx similarity index 100% rename from src/pages/transaction/hooks/TransactionContext.tsx rename to src/pages/transaction/history-transaction/hooks/TransactionContext.tsx diff --git a/src/pages/transaction/hooks/useTransactionContext.tsx b/src/pages/transaction/history-transaction/hooks/useTransactionContext.tsx similarity index 100% rename from src/pages/transaction/hooks/useTransactionContext.tsx rename to src/pages/transaction/history-transaction/hooks/useTransactionContext.tsx diff --git a/src/pages/transfer/transfertype/blocks/AddDialog.tsx b/src/pages/transfer/transfertype/blocks/AddDialog.tsx index a781c1d..5a3bfbf 100644 --- a/src/pages/transfer/transfertype/blocks/AddDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/AddDialog.tsx @@ -1,5 +1,5 @@ import { apiConfig } from '@/config/api.config'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; import { Alert, @@ -30,6 +30,15 @@ import { import { Button } from '@/components/ui/button'; import { toast } from 'sonner'; import { getAuth } from '@/auth'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList +} from '@/components/ui/command'; interface WalletProps { Wallet_id: string; @@ -48,6 +57,7 @@ const API_URL3_CUSTOMER = apiConfig.service_customer; const AddDialog = () => { const parentRef = useRef(null); + const [open, setOpen] = useState(false); const { GetData } = useCallApi(); const { showAddDialog, handleAddDialog, selectedTransferType } = useManageTransferTypeContext(); const [wallets, setWallets] = useState([]); @@ -70,37 +80,102 @@ const AddDialog = () => { maximum_amount: 0, max_transaction_per_day: 0, status: '', + type: '', status_approval: '', created_by: '', created_at: '' }; const [formField, setFormField] = useState(initialState); + const [isSubmitting, setIsSubmitting] = useState(false); const resetForm = () => { setFormField(initialState); }; - const [isSubmitting, setIsSubmitting] = useState(false); const parsedUser = getAuth()?.user; + // Updated validation function to make only certain fields required + const validateForm = () => { + const requiredFields = [ + 'name', + 'description', + 'wallet_origin', + 'wallet_destination', + 'wallet_fee_destination', + 'customer_fee_destination', + 'status', + 'status_approval' + ]; + + const missingFields = requiredFields.filter( + (field) => + formField[field as keyof typeof formField] === '' || + formField[field as keyof typeof formField] === null || + formField[field as keyof typeof formField] === undefined + ); + + if (missingFields.length > 0) { + setAlert({ + show: true, + message: `Please fill out all required fields: ${missingFields.join(', ')}` + }); + return false; + } + + setAlert({ show: false, message: '' }); + return true; + }; + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - // setIsSubmitting(true); - const payload = { - name: formField.name, - description: formField.description, - wallet_origin: formField.wallet_origin, - wallet_destination: formField.wallet_destination, - minimum_amount: formField.minimum_amount, - maximum_amount: formField.maximum_amount, - max_transaction_per_day: formField.max_transaction_per_day, - wallet_fee_destination: formField.wallet_fee_destination, - customer_fee_destination: formField.customer_fee_destination, - status_approval: formField.status_approval, - status: formField.status - }; + setIsSubmitting(true); + + if (!validateForm()) { + setIsSubmitting(false); + return; + } + + doCreateTransferType(formField) + .then((success) => { + if (success) { + handleAddDialog(false); + toast.success('Success Create Transfer Type'); + reload(); + resetForm(); + } + }) + .finally(() => { + setIsSubmitting(false); + }); }; + + const doCreateTransferType = useCallback( + async (data: typeof formField) => { + try { + const response = await PostData(`${API_URL}/transactiontype/create`, data); + + if (response?.status) { + setAlert({ show: false, message: '' }); + return true; + } else { + setAlert({ show: true, message: response?.message || 'Failed to create transfer type' }); + return false; + } + } catch (error) { + setAlert({ + show: true, + message: + error instanceof Error + ? error.message + : 'An error occurred while creating transfer type' + }); + return false; + } + }, + [PostData] + ); + useEffect(() => { const created_time = new Date(); const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); @@ -128,7 +203,6 @@ const AddDialog = () => { order_direction: sorting[0].desc ? 'DESC' : 'ASC' }); setCustomers(response?.data.list); - // console.log('CUSTOMER: ', response?.data.list); } catch (error) { console.error('Error fetching customer', error); } @@ -161,34 +235,6 @@ const AddDialog = () => { fetchWallets(); }, [showAddDialog]); - const doCreateTransferType = useCallback( - async (e: React.FormEvent) => { - e.preventDefault(); - for (const key in formField) { - if (formField[key as keyof typeof formField] === '') { - setAlert({ show: true, message: 'All fields must be filled out' }); - return; - } - } - - setAlert({ show: false, message: '' }); - - const response = await PostData(`${API_URL}/transactiontype/create`, formField); - - if (response?.status) { - setAlert({ show: false, message: '' }); - handleAddDialog(false); - toast.success('Success Create Transfer Type'); - reload(); - resetForm(); - } else { - setAlert({ show: true, message: response?.message || 'Failed to create transfer type' }); - } - handleAddDialog(false); - }, - [formField] - ); - return ( handleAddDialog(open)}> @@ -198,7 +244,7 @@ const AddDialog = () => {

- Addd Transaction Type + Add Transaction Type

@@ -220,7 +266,7 @@ const AddDialog = () => {

{alert.message}

)} -
+
@@ -228,15 +274,17 @@ const AddDialog = () => { Transfer Type Name * - - setFormField((prev) => ({ ...prev, name: target.value })) - } - /> +
+ + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> +
@@ -246,15 +294,17 @@ const AddDialog = () => { Description * - - setFormField((prev) => ({ ...prev, description: target.value })) - } - /> +
+ + setFormField((prev) => ({ ...prev, description: target.value })) + } + /> +
@@ -263,20 +313,22 @@ const AddDialog = () => { - { - setFormField((prev) => ({ - ...prev, - minimum_amount: values.floatValue || 0 - })); - }} - placeholder="Enter Minimum Amount" - /> +
+ { + setFormField((prev) => ({ + ...prev, + minimum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Minimum Amount" + /> +

@@ -285,20 +337,22 @@ const AddDialog = () => { - { - setFormField((prev) => ({ - ...prev, - maximum_amount: values.floatValue || 0 - })); - }} - placeholder="Enter Maximum Amount" - /> +
+ { + setFormField((prev) => ({ + ...prev, + maximum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Maximum Amount" + /> +
@@ -306,24 +360,26 @@ const AddDialog = () => { - { - setFormField((prev) => ({ - ...prev, - max_transaction_per_day: values.floatValue || 0 - })); - }} - placeholder="Enter Max Transaction Per Day" - /> +
+ { + setFormField((prev) => ({ + ...prev, + max_transaction_per_day: values.floatValue || 0 + })); + }} + placeholder="Enter Max Transaction Per Day" + /> +
-
+
-
+
-
+
-
+
+
+ + + + + + + + { + e.currentTarget.scrollTop += e.deltaY; + }} + > + No Customer found. + + {customers.map((customer) => ( + { + setFormField({ + ...formField, + customer_fee_destination: customer.id + }); + setOpen(false); + }} + > + {customer.username} + + ))} + + + + + +
+
+
+
+
+ +
-
-
+
-
+
@@ -299,20 +380,22 @@ const EditDialog = () => { - { - setFormField((prev) => ({ - ...prev, - maximum_amount: values.floatValue || 0 - })); - }} - placeholder="Enter Maximum Amount" - /> +
+ { + setFormField((prev) => ({ + ...prev, + maximum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Maximum Amount" + /> +
@@ -320,24 +403,26 @@ const EditDialog = () => { - { - setFormField((prev) => ({ - ...prev, - max_transaction_per_day: values.floatValue || 0 - })); - }} - placeholder="Enter Max Transaction Per Day" - /> +
+ { + setFormField((prev) => ({ + ...prev, + max_transaction_per_day: values.floatValue || 0 + })); + }} + placeholder="Enter Max Transaction Per Day" + /> +
-
+
-
+
-
+
-
+
+
+ + + + + + + + { + e.currentTarget.scrollTop += e.deltaY; + }} + > + No Customer found. + + {customers.map((customer) => ( + { + setFormField({ + ...formField, + customer_fee_destination: customer.id + }); + setOpen(false); + }} + > + {customer.username} - {customer.msisdn} + + ))} + + + + + +
+
+
+ +
+
+
@@ -447,12 +589,11 @@ const EditDialog = () => {
-
+
-
{
- {/* Bagian Transaction Fee */} + + {/* Transaction Fee Section */} -
+
@@ -530,4 +671,4 @@ const EditDialog = () => { ); }; -export { EditDialog }; +export { EditDialog }; \ No newline at end of file diff --git a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx index ef182c6..4d2b233 100644 --- a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx +++ b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx @@ -20,6 +20,7 @@ interface TransferType { walletOriginId: string; walletDestinationId: string; status: string; + type: string; } interface ContextProps { @@ -155,6 +156,16 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, + { + accessorFn: (row) => row.type, + id: 'type', + header: ({ column }) => ( + + ), + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, { accessorFn: (row) => (row.status === 'Y' ? 'Active' : 'Inactive'), id: 'status', diff --git a/src/pages/wallet/wallet-history/blocks/ListToolbar.tsx b/src/pages/wallet/wallet-history/blocks/ListToolbar.tsx index 9b239b2..546a14a 100644 --- a/src/pages/wallet/wallet-history/blocks/ListToolbar.tsx +++ b/src/pages/wallet/wallet-history/blocks/ListToolbar.tsx @@ -11,15 +11,15 @@ const ListToolbar = () => {
- */} {/* + + + ); + }, + meta: { + headerClassName: 'w-[150px]' + } } - // { - // id: 'actions', - // header: ({ column }) => , - // cell: (data) => { - // const row = data.row.original; - // return ( - // <> - // - // - // - // ); - // }, - // meta: { - // headerClassName: 'w-[150px]' - // } - // } ], [] ); + + const getWalletLists = async (page: number, limit: number, sorting: any, filter: any) => { try { sorting = sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting; filter = filter.length == 0 ? {} : { name: filter[0].value?.toLowerCase() }; - const response = await GetData(`${API_URL_WALLET}/dashboard/wallet`, { + const response = await GetData(`${API_URL_WALLET}/dashboard/balance/`, { limit, page: page + 1, with_deleted: false, @@ -167,7 +242,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', // filter: JSON.stringify(filter) }); - console.log(response?.data); + // console.log(response?.data); setWallets(response?.data.list); return { data: response?.data.list, totalCount: response?.data.total_count }; } catch (error) { @@ -192,7 +267,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } } layout={{ card: true }} sorting={[{ id: 'id', desc: false }]} diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index 1b0896b..01bd4f6 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -8,7 +8,8 @@ import { ErrorsRouting } from '@/errors'; import DashboardHomePage from '@/pages/dashboards/home/DashboardHomePage'; import ManageUserPage from '@/pages/settings/user/manage-user/ManageUserPage'; -import Transaction from '@/pages/transaction/Transaction'; +import Transaction from '@/pages/transaction/history-transaction/Transaction'; +import ApprovalTransaction from '@/pages/transaction/approval-transaction/ApprovalTransaction'; import LogActivityPage from '@/pages/settings/user/log-activity/LogActivityPage'; import ManagePositionPage from '@/pages/settings/user/manage-position/ManagePositionPage'; import ManageAccount from '@/pages/account/manage-account/ManageAccount'; @@ -36,6 +37,7 @@ import ConversionMaster from '@/pages/master/conversion/ConversionMaster'; import WalletRuleMaster from '@/pages/master/walletRule/WalletRuleMaster'; import WalletHistory from '@/pages/wallet/wallet-history/WalletHistory'; import WalletMaster from '@/pages/master/wallet/WalletMaster'; +import CurrencyMaster from '@/pages/master/currency/CurrencyMaster'; const AppRoutingSetup = (): ReactElement => { return ( @@ -58,6 +60,8 @@ const AppRoutingSetup = (): ReactElement => { /> } /> + } /> + } /> } /> @@ -82,6 +86,7 @@ const AppRoutingSetup = (): ReactElement => { } /> } /> + } /> } /> } /> } />