From 5ed5ee26bf145b120de8a75cd0aa70e9d59a2c6e Mon Sep 17 00:00:00 2001 From: Iqbal Rizqi Kurniawan Date: Mon, 13 Oct 2025 20:26:29 +0700 Subject: [PATCH] feat: implement shift management with CRUD operations and local storage integration --- src/pages/master/shift/IndexShift.jsx | 58 +++++++++- .../master/shift/component/DetailShift.jsx | 107 +++++++++++++----- .../master/shift/component/ListShift.jsx | 82 +++++++------- 3 files changed, 177 insertions(+), 70 deletions(-) diff --git a/src/pages/master/shift/IndexShift.jsx b/src/pages/master/shift/IndexShift.jsx index bb67155..4e860d3 100644 --- a/src/pages/master/shift/IndexShift.jsx +++ b/src/pages/master/shift/IndexShift.jsx @@ -1,10 +1,58 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import ListShift from './component/ListShift'; import DetailShift from './component/DetailShift'; +import { getAllShift } from '../../../api/master-shift'; const IndexShift = () => { const [actionMode, setActionMode] = useState('list'); const [selectedData, setSelectedData] = useState(null); + const [shiftData, setShiftData] = useState([]); + const [loading, setLoading] = useState(false); + + const fetchData = async () => { + setLoading(true); + try { + const localData = localStorage.getItem('shiftData'); + if (localData) { + setShiftData(JSON.parse(localData)); + } else { + const response = await getAllShift(); + if (response.data) { + setShiftData(response.data.data); + localStorage.setItem('shiftData', JSON.stringify(response.data.data)); + } + } + } catch (error) { + console.error("Error fetching shift data:", error); + } + setLoading(false); + }; + + useEffect(() => { + fetchData(); + }, []); + + const handleAddShift = (newShift) => { + const newData = { ...newShift, id: Date.now() }; // Simulate adding an ID + const updatedData = [newData, ...shiftData]; + setShiftData(updatedData); + localStorage.setItem('shiftData', JSON.stringify(updatedData)); + setActionMode('list'); + }; + + const handleUpdateShift = (updatedShift) => { + const updatedData = shiftData.map(shift => shift.id === updatedShift.id ? updatedShift : shift); + setShiftData(updatedData); + localStorage.setItem('shiftData', JSON.stringify(updatedData)); + setActionMode('list'); + }; + + const handleDeleteShift = (id) => { + const updatedData = shiftData.filter(shift => shift.id !== id); + setShiftData(updatedData); + localStorage.setItem('shiftData', JSON.stringify(updatedData)); + }; + return ( <> @@ -12,6 +60,10 @@ const IndexShift = () => { )} {(actionMode === 'add' || actionMode === 'edit' || actionMode === 'preview') && ( @@ -20,9 +72,11 @@ const IndexShift = () => { selectedData={selectedData} setActionMode={setActionMode} setSelectedData={setSelectedData} + onAdd={handleAddShift} + onUpdate={handleUpdateShift} /> )} - + ); }; diff --git a/src/pages/master/shift/component/DetailShift.jsx b/src/pages/master/shift/component/DetailShift.jsx index 1ca4d31..d0b354b 100644 --- a/src/pages/master/shift/component/DetailShift.jsx +++ b/src/pages/master/shift/component/DetailShift.jsx @@ -45,22 +45,23 @@ const DetailShift = (props) => { }; try { - const response = FormData.id - ? await updateShift(FormData.id, payload) - : await createShift(payload); - - if (response && (response.statusCode === 200 || response.statusCode === 201)) { - NotifOk({ - icon: 'success', - title: 'Berhasil', - message: `Data Shift "${FormData.nama_shift}" berhasil ${FormData.id ? 'diubah' : 'ditambahkan'}.`, - }); - props.setActionMode('list'); + if (FormData.id) { + props.onUpdate(payload); } else { - NotifAlert({ icon: 'error', title: 'Gagal', message: response?.message || 'Terjadi kesalahan saat menyimpan data.' }); + props.onAdd(payload); } + NotifOk({ + icon: 'success', + title: 'Berhasil', + message: `Data Shift "${payload.nama_shift}" berhasil ${FormData.id ? 'diubah' : 'ditambahkan'}.`, + }); } catch (error) { - NotifAlert({ icon: 'error', title: 'Error', message: error.message || 'Terjadi kesalahan pada server.' }); + console.error('Save Shift Error:', error); + NotifAlert({ + icon: 'error', + title: 'Error', + message: error.message || 'Terjadi kesalahan pada server. Coba lagi nanti.', + }); } setConfirmLoading(false); @@ -89,28 +90,78 @@ const DetailShift = (props) => { open={props.actionMode !== 'list'} onCancel={handleCancel} footer={[ - , - !readOnly && ( - - ), + <> + + + + + {!readOnly && ( + + )} + + , ]} > {FormData && (
- Status -
- - {FormData.status ? 'Active' : 'Inactive'} +
+ Status +
+
+
+ +
+
+ {FormData.status === true ? 'Active' : 'Inactive'} +
- +
Nama Shift * diff --git a/src/pages/master/shift/component/ListShift.jsx b/src/pages/master/shift/component/ListShift.jsx index ab20b52..303c76f 100644 --- a/src/pages/master/shift/component/ListShift.jsx +++ b/src/pages/master/shift/component/ListShift.jsx @@ -1,21 +1,17 @@ import React, { memo, useState, useEffect } from 'react'; -import { Button, Col, Row, Input, ConfigProvider, Card, Tag } from 'antd'; +import { Button, Col, Row, Input, ConfigProvider, Card, Tag, Table, Space } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, SearchOutlined, EyeOutlined, + SyncOutlined, } from '@ant-design/icons'; -import { NotifAlert, NotifConfirmDialog } from '../../../../components/Global/ToastNotif'; +import { NotifConfirmDialog } from '../../../../components/Global/ToastNotif'; import { useNavigate } from 'react-router-dom'; -import TableList from '../../../../components/Global/TableList'; -import { getAllShift, deleteShift } from '../../../../api/master-shift'; const ListShift = (props) => { - const [trigerFilter, setTrigerFilter] = useState(false); - const defaultFilter = { search: '' }; - const [formDataFilter, setFormDataFilter] = useState(defaultFilter); const [searchValue, setSearchValue] = useState(''); const navigate = useNavigate(); @@ -26,19 +22,14 @@ const ListShift = (props) => { } }, [navigate]); - const doFilter = () => { - setTrigerFilter((prev) => !prev); - }; - const handleSearch = (value) => { - setFormDataFilter({ search: value }); - doFilter(); + // This will be handled by the parent component if server-side search is needed + console.log('Search value:', value); }; const handleSearchClear = () => { setSearchValue(''); - setFormDataFilter(defaultFilter); - doFilter(); + // This will be handled by the parent component if server-side search is needed }; const showPreviewModal = (record) => { @@ -61,24 +52,10 @@ const ListShift = (props) => { icon: 'question', title: 'Konfirmasi', message: `Apakah anda yakin ingin menghapus data shift "${record.nama_shift}"?`, - onConfirm: () => handleDelete(record.id), + onConfirm: () => props.onDelete(record.id), }); }; - const handleDelete = async (id) => { - try { - const response = await deleteShift(id); - if (response.statusCode === 200) { - NotifAlert({ icon: 'success', title: 'Berhasil', message: 'Data shift berhasil dihapus' }); - doFilter(); - } else { - NotifAlert({ icon: 'error', title: 'Gagal', message: response.message }); - } - } catch (error) { - NotifAlert({ icon: 'error', title: 'Error', message: error.message }); - } - }; - const columns = [ { title: 'No', @@ -114,15 +91,40 @@ const ListShift = (props) => { align: 'center', width: '15%', render: (_, record) => ( - -