From 4a41face169a3e12aba43b4d9cc2bfa3a9a18574 Mon Sep 17 00:00:00 2001 From: Flook Date: Tue, 15 Apr 2025 07:30:30 +0700 Subject: [PATCH] Updated frontend --- .drone.yml | 28 --- src/App.jsx | 121 ++++++---- src/api/employee.js | 436 +++++++++-------------------------- src/components/ModalForm.jsx | 2 +- src/utils/appUtils.js | 3 + 5 files changed, 178 insertions(+), 412 deletions(-) delete mode 100644 .drone.yml diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 6f82fae..0000000 --- a/.drone.yml +++ /dev/null @@ -1,28 +0,0 @@ -kind: pipeline -type: docker -name: default - -steps: - - name: SonarQube Scan - image: sonarsource/sonar-scanner-cli - environment: - SONAR_HOST_URL: - from_secret: SCANNER_HOST_URL - SONAR_LOGIN: - from_secret: SCANNER_LOGIN - SONAR_TOKEN: - from_secret: SCANNER_TOKEN - commands: - - mkdir -p /tmp/.scannerwork - - chmod -R 777 /tmp/.scannerwork - - sonar-scanner -Dsonar.projectKey=gitea_opengis -Dsonar.login=$SONAR_LOGIN -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.token=$SONAR_TOKEN -Dsonar.working.directory=/tmp/.scannerwork - - - name: Deploy to Server - image: curlimages/curl:latest - environment: - WEBHOOK_URL: - from_secret: WEBHOOK_URL - WEBHOOK_SECRET: - from_secret: WEBHOOK_SECRET - commands: - - 'curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $WEBHOOK_SECRET" -d "{\"branch\":\"master\"}" "$WEBHOOK_URL"' diff --git a/src/App.jsx b/src/App.jsx index edecd05..bd72846 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,7 +3,7 @@ import Table from "./components/Table.jsx"; import ModalForm from "./components/ModalForm.jsx"; import {useEffect, useState} from "react"; import Pagination from "./components/Pagination.jsx"; -import {getEmployees} from "./api/employee.js"; +import {getEmployees, addEmployee, updateEmployee, deleteEmployee, searchEmployees} from "./api/employee.js"; import {showToast} from "./utils/appUtils.js"; function App() { @@ -20,35 +20,40 @@ function App() { // โหลดข้อมูลครั้งแรกครั้งเดียว ใช้ allEmployeeData เป็นแหล่งข้อมูลหลักในการแบ่งหน้าใหม่ useEffect(() => { - const employeeData = getEmployees(); - setAllEmployeeData(employeeData); - setTotalPage(Math.ceil(employeeData.length / limit)); + const fetchData = async () =>{ + const employeeData = await getEmployees(); + setAllEmployeeData(employeeData); + setTotalPage(Math.ceil(employeeData.length / limit)); + } + fetchData(); }, []); - // แบ่งหน้าแสดงข้อมูลใหม่ เมื่อหน้าเปลี่ยน + // แบ่งหน้าแสดงข้อมูลใหม่ เมื่อหน้าเปลี่ยนหรือมีการค้นหา useEffect(() => { - // กรองข้อมูลตาม searchTerm จาก allEmployeeData - const filtered = allEmployeeData.filter(employee => - employee.name.toLowerCase().includes(searchTerm.toLowerCase()) || - employee.mail.toLowerCase().includes(searchTerm.toLowerCase()) || - employee.job.toLowerCase().includes(searchTerm.toLowerCase()) || - employee.department.toLowerCase().includes(searchTerm.toLowerCase()) - ); + const fetchFilteredEmployees = async () => { + let filtered; + if(searchTerm){ + filtered = await searchEmployees(searchTerm); + } + else{ + filtered = allEmployeeData; + } + // คำนวณจำนวนหน้าทั้งหมดใหม่ + const newTotalPage = Math.ceil(filtered.length / limit); + setTotalPage(newTotalPage); - // คำนวณจำนวนหน้าทั้งหมดใหม่ - const newTotalPage = Math.ceil(filtered.length / limit); - setTotalPage(newTotalPage); + // ตรวจสอบว่าหน้าปัจจุบันยังอยู่ในช่วงที่มีข้อมูลหรือไม่ + if (page > newTotalPage && newTotalPage > 0) { + setPage(newTotalPage); + return; // ยกเลิกรอบนี้ก่อน รอให้ page เปลี่ยนแล้วค่อยรันใหม่ + } - // ตรวจสอบว่าหน้าปัจจุบันยังอยู่ในช่วงที่มีข้อมูลหรือไม่ - if (page > newTotalPage && newTotalPage > 0) { - setPage(newTotalPage); - return; // ยกเลิกรอบนี้ก่อน รอให้ page เปลี่ยนแล้วค่อยรันใหม่ - } - - const start = (page - 1) * limit; - const end = page * limit; - const employeeDataPaginationArray = filtered.slice(start, end); - setTableData(employeeDataPaginationArray); + const start = (page - 1) * limit; + const end = page * limit; + const employeeDataPaginationArray = filtered.slice(start, end); + setTableData(employeeDataPaginationArray); + }; + fetchFilteredEmployees(); }, [page, allEmployeeData, searchTerm]); // เมื่อกดที่ปุ่มใด ๆ ก็ตาม @@ -59,29 +64,37 @@ function App() { setEmployee(employee); } // ตรวจสอบว่าเป็นการกดปุ่มอะไร - const handleSubmit = (newEmployeeData)=>{ + const handleSubmit = async (newEmployeeData)=>{ if(modalMode === 'add'){ - // ในอนาคตจะ Update ข้อมูลด้วย Rest API - // ปรับปรุงข้อมูลที่จะแสดงใน Table - setAllEmployeeData((prevData) => { - const updatedData = [...prevData, newEmployeeData]; - setTotalPage(Math.ceil(updatedData.length / limit)); - return updatedData; - }); - showToast('เพิ่มข้อมูลเรียบร้อย', 'success'); - console.log('Add button: ', newEmployeeData); + // ในอนาคตจะ Add ข้อมูลด้วย Rest API + const addedEmployee = await addEmployee(newEmployeeData); + if(addedEmployee){ + // เรียกดูข้อมูลพนักงานใหม่จากฐานข้อมูล + const employeeData = await getEmployees(); + // ปรับปรุงข้อมูลที่จะแสดงใน Table + setAllEmployeeData(employeeData); + setTotalPage(Math.ceil(employeeData.length / limit)); + showToast('เพิ่มข้อมูลเรียบร้อย', 'success'); + } + else { + showToast('ไม่สามารถเพิ่มข้อมูลได้','error'); + } } else{ - console.log('Update button:', newEmployeeData); // ในอนาคตจะ Update ข้อมูลในฐานข้อมูลด้วย Rest API - // ปรับปรุงข้อมูลที่จะแสดงใน Table - setAllEmployeeData((prevData) => { - const updatedData = prevData.map((emp) => - emp.id === newEmployeeData.id ? newEmployeeData : emp - ); - return updatedData; - }); - showToast('ปรับปรุงข้อมูลเรียบร้อย', 'success'); + const updatedEmployee = await updateEmployee(newEmployeeData.id, newEmployeeData); + if(updatedEmployee){ + // เรียกดูข้อมูลพนักงานใหม่จากฐานข้อมูล + const employeeData = await getEmployees(); + setAllEmployeeData(employeeData); + setTotalPage(Math.ceil(employeeData.length / limit)); + + showToast('ปรับปรุงข้อมูลเรียบร้อย', 'success'); + } + else{ + showToast('ไม่สามารถปรับปรุงข้อมูลได้','error'); + } + } } @@ -119,19 +132,25 @@ function App() { } // ตรวจสอบกรณีที่มีการลบข้อมูลสุดท้ายในหน้า - const handleDelete = (employeeId) =>{ - setAllEmployeeData((prevData) => { - const updatedData = prevData.filter(emp => emp.id !== employeeId); - const newTotalPage = Math.ceil(updatedData.length / limit); + const handleDelete = async (employeeId) =>{ + const success = await deleteEmployee(employeeId); + if(success){ + // เรียกดูข้อมูลพนักงานใหม่จากฐานข้อมูล + const employeeData = await getEmployees(); + // ปรับปรุงข้อมูลที่จะแสดงใน Table + setAllEmployeeData(employeeData); + const newTotalPage = Math.ceil(employeeData.length / limit); // ถ้าหน้าที่อยู่เกินหน้าสุดท้ายหลังลบ ให้ลดหน้าลง if (page > newTotalPage) { setPage(newTotalPage === 0 ? 1 : newTotalPage); } - setTotalPage(newTotalPage); - return updatedData; - }); + showToast('ลบข้อมูลเรียบร้อย', 'success'); + } + else{ + showToast('ไม่สามารถลบข้อมูลได้', 'error'); + } } return ( diff --git a/src/api/employee.js b/src/api/employee.js index 61c9f55..def1fe7 100644 --- a/src/api/employee.js +++ b/src/api/employee.js @@ -1,334 +1,106 @@ -const employees = [ - { - id: 1, - name: "Cy Ganderton", - mail: "ganderton@gmail.com", - job: "Quality Control Specialist", - department: "Quality Control Department", - active: true - }, - { - id: 2, - name: "Hart Hagerty", - mail: "hagerty@gmail.com", - job: "Desktop Support Technician", - department: "Desktop Support Department", - active: true - }, - { - id: 3, - name: "Brice Swyre", - mail: "swyre@gmail.com", - job: "Tax Accountant", - department: "Desktop Support Department", - active: false - }, - { - id: 4, - name: "Grace Lee", - mail: "grace.lee@example.com", - job: "Software Engineer", - department: "Data Analysis Department", - active: false - }, - { - id: 5, - name: "Frank Miller", - mail: "frank.miller@example.com", - job: "Project Manager", - department: "Data Analysis Department", - active: true - }, - { - id: 6, - name: "Alice Johnson", - mail: "alice.johnson@company.com", - job: "HR Specialist", - department: "HR Department", - active: false - }, - { - id: 7, - name: "Charlie Davis", - mail: "charlie.davis@business.com", - job: "Software Engineer", - department: "Data Analysis Department", - active: true - }, - { - id: 8, - name: "Emily Wilson", - mail: "emily.wilson@company.com", - job: "Marketing Coordinator", - department: "Marketing Department", - active: false - }, - { - id: 9, - name: "Henry Clark", - mail: "henry.clark@business.com", - job: "HR Specialist", - department: "HR Department", - active: true - }, - { - id: 10, - name: "Ivy Lewis", - mail: "ivy.lewis@example.com", - job: "Software Engineer", - department: "Engineering Department", - active: false - }, - { - id: 11, - name: "John Doe", - mail: "john.doe@company.com", - job: "Marketing Coordinator", - department: "Marketing Department", - active: true - }, - { - id: 12, - name: "Jane Smith", - mail: "jane.smith@business.com", - job: "Data Analyst", - department: "Data Analysis Department", - active: false - }, - { - id: 13, - name: "Alice Johnson", - mail: "alice.johnson@example.com", - job: "Project Manager", - department: "Project Management Department", - active: true - }, - { - id: 14, - name: "Bob Brown", - mail: "bob.brown@company.com", - job: "HR Specialist", - department: "HR Department", - active: false - }, - { - id: 15, - name: "Charlie Davis", - mail: "charlie.davis@business.com", - job: "Software Engineer", - department: "Data Analysis Department", - active: true - }, - { - id: 16, - name: "Emily Wilson", - mail: "emily.wilson@company.com", - job: "Marketing Coordinator", - department: "Marketing Department", - active: false - }, - { - id: 17, - name: "Frank Miller", - mail: "frank.miller@business.com", - job: "Project Manager", - department: "Project Management Department", - active: true - }, - { - id: 18, - name: "Grace Lee", - mail: "grace.lee@example.com", - job: "Data Analyst", - department: "Data Analysis Department", - active: false - }, - { - id: 19, - name: "Henry Clark", - mail: "henry.clark@company.com", - job: "Software Engineer", - department: "Engineering Department", - active: true - }, - { - id: 20, - name: "Ivy Lewis", - mail: "ivy.lewis@business.com", - job: "HR Specialist", - department: "HR Department", - active: false - }, - { - id: 21, - name: "John Doe", - mail: "john.doe@example.com", - job: "Marketing Coordinator", - department: "Marketing Department", - active: true - }, - { - id: 22, - name: "Jane Smith", - mail: "jane.smith@company.com", - job: "Data Analyst", - department: "Data Analysis Department", - active: false - }, - { - id: 23, - name: "Alice Johnson", - mail: "alice.johnson@business.com", - job: "Project Manager", - department: "Project Management Department", - active: true - }, - { - id: 24, - name: "Bob Brown", - mail: "bob.brown@example.com", - job: "HR Specialist", - department: "HR Department", - active: false - }, - { - id: 25, - name: "Charlie Davis", - mail: "charlie.davis@company.com", - job: "Software Engineer", - department: "Data Analysis Department", - active: true - }, - { - id: 26, - name: "Emily Wilson", - mail: "emily.wilson@business.com", - job: "Marketing Coordinator", - department: "Marketing Department", - active: false - }, - { - id: 27, - name: "Frank Miller", - mail: "frank.miller@company.com", - job: "Project Manager", - department: "Project Management Department", - active: true - }, - { - id: 28, - name: "Grace Lee", - mail: "grace.lee@business.com", - job: "Data Analyst", - department: "Data Analysis Department", - active: false - }, - { - id: 29, - name: "Henry Clark", - mail: "henry.clark@example.com", - job: "Software Engineer", - department: "Engineering Department", - active: true - }, - { - id: 30, - name: "Ivy Lewis", - mail: "ivy.lewis@company.com", - job: "HR Specialist", - department: "HR Department", - active: false - }, - { - id: 31, - name: "John Doe", - mail: "john.doe@business.com", - job: "Marketing Coordinator", - department: "Marketing Department", - active: true - }, - { - id: 32, - name: "Jane Smith", - mail: "jane.smith@example.com", - job: "Data Analyst", - department: "Data Analysis Department", - active: false - }, - { - id: 33, - name: "Alice Johnson", - mail: "alice.johnson@company.com", - job: "Project Manager", - department: "Project Management Department", - active: true - }, - { - id: 34, - name: "Bob Brown", - mail: "bob.brown@business.com", - job: "HR Specialist", - department: "HR Department", - active: false - }, - { - id: 35, - name: "Charlie Davis", - mail: "charlie.davis@example.com", - job: "Software Engineer", - department: "Data Analysis Department", - active: true - }, - { - id: 36, - name: "Emily Wilson", - mail: "emily.wilson@company.com", - job: "Marketing Coordinator", - department: "Marketing Department", - active: false - }, - { - id: 37, - name: "Frank Miller", - mail: "frank.miller@business.com", - job: "Project Manager", - department: "Project Management Department", - active: true - }, - { - id: 38, - name: "Grace Lee", - mail: "grace.lee@company.com", - job: "Data Analyst", - department: "Data Analysis Department", - active: false - }, - { - id: 39, - name: "Henry Clark", - mail: "henry.clark@business.com", - job: "Software Engineer", - department: "Engineering Department", - active: true - }, - { - id: 40, - name: "Ivy Lewis", - mail: "ivy.lewis@example.com", - job: "HR Specialist", - department: "HR Department", - active: false - }, - { - id: 41, - name: "John Doe", - mail: "john.doe@company.com", - job: "Marketing Coordinator", - department: "Marketing Department", - active: true - } -]; +const BASE_URL = "/api/employees"; -export const getEmployees = ()=>{ - return employees; +export const getEmployees = async ()=>{ + try{ + const response = await fetch(`${BASE_URL}`); + if(!response.ok){ + throw new Error("Error while fetching all employees"); + } + const data = await response.json() + return data; + } + catch (e) { + console.log("Error while fetching all employees"); + return null; + } + //return employees; +} + +export const addEmployee = async (employee) =>{ + try { + const response = await fetch(`${BASE_URL}`,{ + method:"POST", + headers:{ + "Content-Type":"application/json" + }, + body: JSON.stringify(employee) + }); + + if(!response.ok){ + throw new Error("Fail to create employee"); + } + + const data = response.json(); + return data; + } + catch (e) { + console.log("Fail to create employee"); + return null; + } +} + +export const updateEmployee = async (id, employee) => { + try { + const response = await fetch(`${BASE_URL}/${id}`, { + method: "PUT", + headers: { + "Content-Type":"application/json" + }, + body: JSON.stringify(employee) + }); + + if(!response.ok){ + throw new Error("Fail to update employee") + } + + const data = response.json(); + return data; + } + catch (e) { + console.log("Fail to update employee"); + return null; + } +} + +export const deleteEmployee = async (id) => { + try { + const response = await fetch(`${BASE_URL}/${id}`,{ + method : "DELETE", + headers : { + "Content-Type":"application/json" + }, + }); + + if(!response.ok){ + throw new Error("Fail to delete employee"); + } + + return true; + } + catch (e) { + console.log("Fail to delete employee"); + return false; + } +} + +export const searchEmployees = async (keyword) => { + try{ + const response = await fetch(`${BASE_URL}/search?keyword=${keyword}`,{ + method : "GET", + headers: { + "Content-type":"application/json" + }, + }); + + if(!response.ok){ + throw new Error("Fail to search employees"); + } + + const data = response.json(); + return data; + } + catch (e) { + console.log("Fail to search employees"); + return null; + } } \ No newline at end of file diff --git a/src/components/ModalForm.jsx b/src/components/ModalForm.jsx index 4674efc..270b05a 100644 --- a/src/components/ModalForm.jsx +++ b/src/components/ModalForm.jsx @@ -38,7 +38,7 @@ export default function ModalForm({isOpen, onClose, mode, OnSubmit, employee}){ e.preventDefault(); const errorMessage = validateForm(id,name,mail,job,department); if (errorMessage) { - showToast('กรุณากรอกข้อมูลให้ครบถ้วนและถูกต้อง', 'error'); + showToast(errorMessage, 'error'); return; } try{ diff --git a/src/utils/appUtils.js b/src/utils/appUtils.js index 2360bf9..c9e3f2f 100644 --- a/src/utils/appUtils.js +++ b/src/utils/appUtils.js @@ -42,6 +42,9 @@ export const validateForm = (id, name, mail, job, department ) => { if (!id || !name || !mail || !job || !department) { return 'กรุณากรอกข้อมูลให้ครบถ้วน'; } + if(isNaN(Number(id))){ + return 'กรุณากรอกข้อมูล id เป็นตัวเลข'; + } if (!/\S+@\S+\.\S+/.test(mail)) { return 'กรุณากรอกอีเมลให้ถูกต้อง'; }