diff --git a/src/pages/jadwalShift/IndexJadwalShift.jsx b/src/pages/jadwalShift/IndexJadwalShift.jsx index 0a9f7ea..95895a2 100644 --- a/src/pages/jadwalShift/IndexJadwalShift.jsx +++ b/src/pages/jadwalShift/IndexJadwalShift.jsx @@ -1,62 +1,74 @@ -import { useState, useEffect } from 'react'; +import React, { memo, useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; import ListJadwalShift from './component/ListJadwalShift'; import DetailJadwalShift from './component/DetailJadwalShift'; -import { getAllJadwalShift, deleteJadwalShift } from '../../api/jadwal-shift'; +import { useBreadcrumb } from '../../layout/LayoutBreadcrumb'; +import { Typography } from 'antd'; + +const { Text } = Typography; + +const IndexJadwalShift = memo(function IndexJadwalShift() { + const navigate = useNavigate(); + const { setBreadcrumbItems } = useBreadcrumb(); -const IndexJadwalShift = () => { const [actionMode, setActionMode] = useState('list'); const [selectedData, setSelectedData] = useState(null); - const [jadwalShiftData, setJadwalShiftData] = useState([]); - const [loading, setLoading] = useState(false); + const [readOnly, setReadOnly] = useState(false); + const [showModal, setShowModal] = useState(false); - const fetchData = async () => { - setLoading(true); - try { - const response = await getAllJadwalShift(new URLSearchParams()); - if (response.data) { - setJadwalShiftData(response.data.data); - } - } catch (error) { - console.error("Error fetching jadwal shift data:", error); + const setMode = (param) => { + setShowModal(true); + switch (param) { + case 'add': + setReadOnly(false); + break; + + case 'edit': + setReadOnly(false); + break; + + case 'preview': + setReadOnly(true); + break; + + default: + setShowModal(false); + break; } - setLoading(false); + setActionMode(param); }; useEffect(() => { - fetchData(); + const token = localStorage.getItem('token'); + if (token) { + setBreadcrumbItems([ + { title: • Jadwal }, + { title: Jadwal Shift } + ]); + } else { + navigate('/signin'); + } }, []); - const handleDelete = async (id) => { - try { - await deleteJadwalShift(id); - fetchData(); - } catch (error) { - console.error("Error deleting jadwal shift:", error); - } - }; - return ( - <> - {actionMode === 'list' && ( - - )} - {(actionMode === 'add' || actionMode === 'edit') && ( - - )} - > + + + + ); -}; +}); -export default IndexJadwalShift; +export default IndexJadwalShift; \ No newline at end of file diff --git a/src/pages/jadwalShift/component/DetailJadwalShift.jsx b/src/pages/jadwalShift/component/DetailJadwalShift.jsx index 697e6c5..4f77120 100644 --- a/src/pages/jadwalShift/component/DetailJadwalShift.jsx +++ b/src/pages/jadwalShift/component/DetailJadwalShift.jsx @@ -1,51 +1,32 @@ -import { useEffect, useState } from 'react'; -import { Modal, Select, Divider, Typography, Button, ConfigProvider } from 'antd'; -import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif'; -import { createJadwalShift, updateJadwalShift } from '../../../api/jadwal-shift'; -import { getAllShift } from '../../../api/master-shift'; -import { getAllUser } from '../../../api/user'; +import React, { useEffect, useState } from 'react'; +import { + Modal, + Input, + Typography, + Button, + ConfigProvider, + Row, + Col +} from 'antd'; +import { NotifOk } from '../../../components/Global/ToastNotif'; const { Text } = Typography; -const { Option } = Select; const DetailJadwalShift = (props) => { const [confirmLoading, setConfirmLoading] = useState(false); - const [shifts, setShifts] = useState([]); - const [users, setUsers] = useState([]); const defaultData = { id: '', - id_shift: null, - id_user: null, + nama_shift: '', + jam_masuk: '', + jam_pulang: '', + username: '', + nama_employee: '', + whatsapp: '' }; const [FormData, setFormData] = useState(defaultData); - const fetchShifts = async () => { - try { - const response = await getAllShift(new URLSearchParams()); - setShifts(response?.data?.data || []); - } catch (error) { - console.error("Failed to fetch shifts:", error); - setShifts([]); - } - }; - - const fetchUsers = async () => { - try { - const response = await getAllUser(new URLSearchParams("limit=1000")); // Fetch all users - setUsers(response?.data?.data || []); - } catch (error) { - console.error("Failed to fetch users:", error); - setUsers([]); - } - }; - - useEffect(() => { - fetchShifts(); - fetchUsers(); - }, []); - const handleCancel = () => { props.setSelectedData(null); props.setActionMode('list'); @@ -53,70 +34,16 @@ const DetailJadwalShift = (props) => { const handleSave = async () => { setConfirmLoading(true); - - if (!FormData.id_shift) { - NotifOk({ - icon: 'warning', - title: 'Peringatan', - message: 'Kolom Shift Tidak Boleh Kosong', - }); + // This is a dummy save function for slicing purposes + setTimeout(() => { setConfirmLoading(false); - return; - } - - if (!FormData.id_user) { NotifOk({ - icon: 'warning', - title: 'Peringatan', - message: 'Kolom User Tidak Boleh Kosong', + icon: 'success', + title: 'Berhasil', + message: 'Data dummy berhasil disimpan.', }); - setConfirmLoading(false); - return; - } - - const payload = { - id_shift: FormData.id_shift, - id_user: FormData.id_user, - }; - - try { - const response = FormData.id - ? await updateJadwalShift(FormData.id, payload) - : await createJadwalShift(payload); - - if (response && (response.statusCode === 200 || response.statusCode === 201)) { - NotifOk({ - icon: 'success', - title: 'Berhasil', - message: `Data Jadwal Shift berhasil ${FormData.id ? 'diubah' : 'ditambahkan'}.`, - }); - - props.setActionMode('list'); - props.fetchData(); - } else { - NotifAlert({ - icon: 'error', - title: 'Gagal', - message: response?.message || 'Terjadi kesalahan saat menyimpan data.', - }); - } - } catch (error) { - console.error('Save Jadwal Shift Error:', error); - NotifAlert({ - icon: 'error', - title: 'Error', - message: error.message || 'Terjadi kesalahan pada server. Coba lagi nanti.', - }); - } - - setConfirmLoading(false); - }; - - const handleSelectChange = (name, value) => { - setFormData({ - ...FormData, - [name]: value, - }); + props.setActionMode('list'); + }, 1000); }; useEffect(() => { @@ -125,93 +52,119 @@ const DetailJadwalShift = (props) => { } else { setFormData(defaultData); } - }, [props.actionMode, props.selectedData]); + }, [props.showModal, props.selectedData]); + + // Dummy handler for slicing + const handleInputChange = (e) => { + const { name, value } = e.target; + setFormData({ ...FormData, [name]: value }); + }; return ( + - Batal + {props.readOnly ? 'Tutup' : 'Batal'} - - Simpan - + {!props.readOnly && ( + + Simpan + + )} - >, + , ]} > {FormData && ( - - Shift - * - handleSelectChange('id_shift', value)} - value={FormData.id_shift} - > - {shifts.map(shift => ( - {shift.nama_shift} ({shift.jam_shift}) - ))} - - - - User - * - handleSelectChange('id_user', value)} - value={FormData.id_user} - showSearch - optionFilterProp="children" - filterOption={(input, option) => - option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 - } - > - {users.map(user => ( - {user.username} ({user.nama_employee}) - ))} - - + + + Nama Karyawan + + + + Username + + + + Nama Shift + + + + Whatsapp + + + + Jam Masuk + + + + Jam Pulang + + + )} diff --git a/src/pages/jadwalShift/component/ListJadwalShift.jsx b/src/pages/jadwalShift/component/ListJadwalShift.jsx index 3bfdacd..23f5dae 100644 --- a/src/pages/jadwalShift/component/ListJadwalShift.jsx +++ b/src/pages/jadwalShift/component/ListJadwalShift.jsx @@ -1,186 +1,282 @@ import React, { memo, useState, useEffect } from 'react'; -import { Button, Col, Row, Input, ConfigProvider, Card, Table, Space } from 'antd'; +import { Space, Tag, ConfigProvider, Button, Row, Col, Card, Input } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, - SearchOutlined, EyeOutlined, + SearchOutlined, } from '@ant-design/icons'; -import { NotifConfirmDialog } from '../../../components/Global/ToastNotif'; +import { NotifAlert, NotifConfirmDialog } from '../../../components/Global/ToastNotif'; import { useNavigate } from 'react-router-dom'; +import TableList from '../../../components/Global/TableList'; -const ListJadwalShift = (props) => { +// --- DUMMY DATA (Initial State) --- // +const initialDummyData = [ + { + id: 1, + nama_shift: 'Shift Pagi', + jam_masuk: '07:00', + jam_pulang: '15:00', + username: 'd.sanjaya', + nama_employee: 'Dede Sanjaya', + whatsapp: '081234567890' + }, + { + id: 2, + nama_shift: 'Shift Siang', + jam_masuk: '15:00', + jam_pulang: '23:00', + username: 'a.wijaya', + nama_employee: 'Andi Wijaya', + whatsapp: '081234567891' + }, + { + id: 3, + nama_shift: 'Shift Malam', + jam_masuk: '23:00', + jam_pulang: '07:00', + username: 'b.cahya', + nama_employee: 'Budi Cahya', + whatsapp: '081234567892' + }, +]; + +const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [ + { + title: 'Nama Karyawan', + dataIndex: 'nama_employee', + key: 'nama_employee', + }, + { + title: 'Username', + dataIndex: 'username', + key: 'username', + }, + { + title: 'Nama Shift', + dataIndex: 'nama_shift', + key: 'nama_shift', + }, + { + title: 'Jam Masuk', + dataIndex: 'jam_masuk', + key: 'jam_masuk', + }, + { + title: 'Jam Pulang', + dataIndex: 'jam_pulang', + key: 'jam_pulang', + }, + { + title: 'Whatsapp', + dataIndex: 'whatsapp', + key: 'whatsapp', + }, + { + title: 'Aksi', + key: 'aksi', + align: 'center', + render: (_, record) => ( + + } + onClick={() => showPreviewModal(record)} + /> + } + onClick={() => showEditModal(record)} + /> + } + onClick={() => showDeleteDialog(record)} + /> + + ), + }, +]; + +const ListJadwalShift = memo(function ListJadwalShift(props) { + const [dataSource, setDataSource] = useState(initialDummyData); + const [trigerFilter, setTrigerFilter] = useState(false); + const defaultFilter = { criteria: '' }; + const [formDataFilter, setFormDataFilter] = useState(defaultFilter); const [searchValue, setSearchValue] = useState(''); const navigate = useNavigate(); + // --- DUMMY API --- // + const getDummyData = (queryParams) => { + return new Promise((resolve) => { + const { criteria } = queryParams; + let data = dataSource; + if (criteria) { + data = dataSource.filter(item => + item.nama_employee.toLowerCase().includes(criteria.toLowerCase()) || + item.username.toLowerCase().includes(criteria.toLowerCase()) + ); + } + setTimeout(() => { + resolve({ + status: 200, + data: { + data: data, + paging: { + page: 1, + limit: 10, + total: data.length, + page_total: 1 + } + } + }); + }, 100); + }); + }; + useEffect(() => { const token = localStorage.getItem('token'); - if (!token) { + if (token) { + if (props.actionMode === 'list') { + setFormDataFilter(defaultFilter); + doFilter(); + } + } else { navigate('/signin'); } - }, [navigate]); + }, [props.actionMode, dataSource]); // Added dataSource to dependency array - const handleSearch = (value) => { - console.log('Search value:', value); + const doFilter = () => { + setTrigerFilter((prev) => !prev); + }; + + const handleSearch = () => { + setFormDataFilter({ criteria: searchValue }); + setTrigerFilter((prev) => !prev); }; const handleSearchClear = () => { setSearchValue(''); + setFormDataFilter({ criteria: '' }); + setTrigerFilter((prev) => !prev); }; - const showPreviewModal = (record) => { - props.setSelectedData(record); + const showPreviewModal = (param) => { + props.setSelectedData(param); props.setActionMode('preview'); }; - const showEditModal = (record) => { - props.setSelectedData(record); + const showEditModal = (param = null) => { + props.setSelectedData(param); props.setActionMode('edit'); }; - const showAddModal = () => { - props.setSelectedData(null); + const showAddModal = (param = null) => { + props.setSelectedData(param); props.setActionMode('add'); }; - const showDeleteDialog = (record) => { + const showDeleteDialog = (param) => { NotifConfirmDialog({ icon: 'question', - title: 'Konfirmasi', - message: `Apakah anda yakin ingin menghapus data jadwal shift untuk "${record.nama_employee}"?`, - onConfirm: () => props.onDelete(record.id), + title: 'Konfirmasi Hapus', + message: `Jadwal shift untuk "${param.nama_employee}" akan dihapus?`, + onConfirm: () => handleDelete(param.id), + onCancel: () => props.setSelectedData(null), }); }; - const columns = [ - { - title: 'No', - key: 'no', - width: '5%', - align: 'center', - render: (_, __, index) => index + 1, - }, - { - title: 'Nama Shift', - dataIndex: 'nama_shift', - key: 'nama_shift', - }, - { - title: 'Jam Shift', - dataIndex: 'jam_shift', - key: 'jam_shift', - }, - { - title: 'Username', - dataIndex: 'username', - key: 'username', - }, - { - title: 'Nama Employee', - dataIndex: 'nama_employee', - key: 'nama_employee', - }, - { - title: 'WhatsApp', - dataIndex: 'whatsapp', - key: 'whatsapp', - }, - { - title: 'Aksi', - key: 'action', - align: 'center', - width: '15%', - render: (_, record) => ( - - } - onClick={() => showPreviewModal(record)} - style={{ - color: '#1890ff', - borderColor: '#1890ff', - }} - /> - } - onClick={() => showEditModal(record)} - style={{ - color: '#faad14', - borderColor: '#faad14', - }} - /> - } - onClick={() => showDeleteDialog(record)} - style={{ - borderColor: '#ff4d4f', - }} - /> - - ), - }, - ]; - - const filteredData = props.jadwalShiftData.filter(item => - item.nama_employee.toLowerCase().includes(searchValue.toLowerCase()) || - item.username.toLowerCase().includes(searchValue.toLowerCase()) || - item.nama_shift.toLowerCase().includes(searchValue.toLowerCase()) - ); + const handleDelete = (id) => { + setDataSource(prevData => prevData.filter(item => item.id !== id)); + NotifAlert({ + icon: 'success', + title: 'Berhasil', + message: 'Data Jadwal Shift berhasil dihapus.', + }); + doFilter(); // Trigger a re-fetch from the new state + }; return ( - - - - setSearchValue(e.target.value)} - onSearch={handleSearch} - allowClear={{ - clearIcon: x, - }} - enterButton={} style={{ backgroundColor: '#23A55A', borderColor: '#23A55A' }}>Cari} - size="large" - /> - - - - } - onClick={showAddModal} - size="large" - > - Tambah Jadwal Shift - - - - - - - - - - + + + + + + + { + const value = e.target.value; + setSearchValue(value); + if (value === '') { + handleSearchClear(); + } + }} + onSearch={handleSearch} + allowClear={{ + clearIcon: ✕, + }} + enterButton={ + } + style={{ + backgroundColor: '#23A55A', + borderColor: '#23A55A', + }} + > + Search + + } + size="large" + /> + + + + + } + onClick={() => showAddModal()} + size="large" + > + Tambah Data + + + + + + + + + + + + ); -}; +}); -export default ListJadwalShift; +export default ListJadwalShift; \ No newline at end of file