diff --git a/src/components/ActionButtonNoAdd.tsx b/src/components/ActionButtonNoAdd.tsx new file mode 100644 index 0000000000000000000000000000000000000000..737333966ce00ca56a9ebe92381d1b4b9143edb8 --- /dev/null +++ b/src/components/ActionButtonNoAdd.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import { Heading, HStack } from "@chakra-ui/react"; +import Searchbar from "../components/Searchbar"; + +export default function ActionButtons(props: any) { + return ( + <HStack + mt={8} + maxW="full" + alignItems="center" + justifyContent="space-between" + marginLeft="6%" // Add 5% left margin + marginRight="6%" // Add 5% right margin + > + <Heading + fontWeight="bold" + fontSize={50} + color="#02033B" + whiteSpace="nowrap" + mr="5%" + > + Data {props.title} + </Heading> + <Searchbar placeholder={props.placeholder} /> + </HStack> + ); +} diff --git a/src/components/ActionButtons.tsx b/src/components/ActionButtons.tsx new file mode 100644 index 0000000000000000000000000000000000000000..58a8e99033b221b81b66729c0f5395c5bf941eb1 --- /dev/null +++ b/src/components/ActionButtons.tsx @@ -0,0 +1,48 @@ +/* import { + Image, + IconButton, + useDisclosure, + HStack, + Heading, + } from "@chakra-ui/react"; + import Searchbar from "../components/Searchbar"; + import Plus from "../assets/plus_button.svg"; + import AddData from "../components/AddData"; + + export default function ActionButtons(props: any) { + const { isOpen, onOpen, onClose } = useDisclosure(); // Use Chakra UI useDisclosure hook + const handleAddDataClick = () => { + onOpen(); + }; + + return ( + <HStack + mt={8} + maxW="full" + alignItems="center" + justifyContent="space-between" + marginLeft="6%" // Add 5% left margin + marginRight="6%" // Add 5% right margin + > + <Heading + fontWeight={"bold"} + fontSize={50} + color="#02033B" + whiteSpace={"nowrap"} + mr={"5%"} + > + Data {props.title} + </Heading> + <Searchbar placeholder={props.placeholder} /> + <IconButton + ml={"5%"} + aria-label="Add" + icon={<Image src={Plus} boxSize={35} />} + onClick={handleAddDataClick} + size="lg" + /> + {isOpen && <AddData disclosure={{ isOpen, onOpen, onClose }} title={props.title} placeholders={props.placeholders} submitFunction={props.submitFunction} onChange={props.onChange} />} + </HStack> + ); + } + */ \ No newline at end of file diff --git a/src/components/Adddatakendaraan.tsx b/src/components/Adddatakendaraan.tsx index 68aa3ca45784b896bd42abf7e7b2dcf9efb90707..01d34db5194a9b32592a52b93d6c0a1dc9874b4e 100644 --- a/src/components/Adddatakendaraan.tsx +++ b/src/components/Adddatakendaraan.tsx @@ -16,6 +16,7 @@ import { Select, ChakraProvider, } from '@chakra-ui/react'; +import { Form } from 'react-router-dom'; interface AddDataProps { disclosure: { @@ -39,9 +40,10 @@ const AddData: React.FC<AddDataProps> = ({ disclosure, onAdd }) => { lastService: new Date().toString().split('T')[0], statusKen: 'Active', idKendaraan: 0, // This will be fetched from VehicleType endpoint + urlKen: '', }); - const [vehicleTypes, setVehicleTypes] = useState<{ idKen: number; jenisKen: string; namaKen: string }[]>([]); + const [vehicleTypes, setVehicleTypes] = useState<{ idKen: number; jenisKen: string; namaKen: string, urlKen : string }[]>([]); const handleAdd = async () => { try { @@ -55,6 +57,7 @@ const AddData: React.FC<AddDataProps> = ({ disclosure, onAdd }) => { const response = await axios.post('http://localhost:5000/vehicleType', { namaKen: newData.namaKen, jenisKen: newData.jenisKen, + urlKen: newData.urlKen, }); // Assuming the response data includes the newly added data @@ -74,7 +77,7 @@ const AddData: React.FC<AddDataProps> = ({ disclosure, onAdd }) => { // Send a POST request to the backend API to add new data const response2 = await axios.post('http://localhost:5000/vehicle', newData); console.log('Data added:', response2.data); - + window.location.reload(); onClose(); // Close the modal } catch (error) { console.error(error); @@ -153,6 +156,15 @@ const AddData: React.FC<AddDataProps> = ({ disclosure, onAdd }) => { /> </FormControl> + <FormControl mt={4}> + <FormLabel>URL Gambar</FormLabel> + <Input + placeholder="URL Gambar" + value={newData.urlKen} + onChange={(e) => setNewData({ ...newData, urlKen: e.target.value })} + /> + </FormControl> + <FormControl mt={4}> <FormLabel>Status Kendaraan</FormLabel> <Select diff --git a/src/components/CardWrapper.tsx b/src/components/CardWrapper.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4361077a197276136323d9be0023dc6d9810a7c4 --- /dev/null +++ b/src/components/CardWrapper.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import {SimpleGrid, SimpleGridProps, ChakraProvider, extendTheme, Flex} from '@chakra-ui/react' + +const theme = extendTheme({ + fonts: { + body: "Roboto Bold, sans-serif", + }, + }); + +interface CardWrapperProps extends SimpleGridProps{ + +} + +const CardWrapper: React.FC<CardWrapperProps> = (props) => { + return( + <ChakraProvider theme={theme}> + <Flex alignContent={'center'} justifyContent={'center'}> + <SimpleGrid + columns={props.columns} + spacing='35px' + pr='5vh' + w='auto' + h='full' + pb={4} + pt={4} + mt={4} + overflowX={'auto'} + overflowY={'auto'} + whiteSpace='nowrap' + > + {props.children} + </SimpleGrid> + </Flex> + </ChakraProvider> + ); +} + +export default CardWrapper; \ No newline at end of file diff --git a/src/components/ClassCard.tsx b/src/components/ClassCard.tsx index 671713fb5e25b24283857bbbb842ac799cb3df4a..78e3c55dc4620b55596c8a86df08b8cb29ba16a7 100644 --- a/src/components/ClassCard.tsx +++ b/src/components/ClassCard.tsx @@ -1,4 +1,13 @@ -import { Box, Image, Text, Button, VStack } from '@chakra-ui/react'; +import { + Box, + Text, + Image, + Spacer, + Stack, + Button, + HStack, +} from '@chakra-ui/react'; +import { NavLink } from 'react-router-dom'; interface ClassCardProps { className: string; @@ -10,23 +19,46 @@ interface ClassCardProps { export const ClassCard: React.FC<ClassCardProps> = ({ className, price, vehicle, imageUrl }) => { return ( <Box - maxW="sm" - borderWidth="1px" - borderRadius="lg" - overflow="hidden" - p={4} - m={2} - boxShadow="md" + w = '400px' + h = 'auto' + bg = 'white' + border={'1px solid #000'} + borderRadius={15} + padding={4} + ml={25} + mr={25} > - <Image src={imageUrl} alt={`Class ${className}`} /> - <VStack align="stretch" mt={4}> - <Text fontWeight="bold">{className}</Text> - <Text>{price}</Text> - <Text>{vehicle}</Text> - <Button colorScheme="blue" variant="solid"> - Lihat Detail - </Button> - </VStack> + <Stack w='100%' h='100%' align='left'> + <Box boxSize={'auto'} w = '100%'> + <Image + style={{objectFit: 'contain'}} + alt='Katalog kelas mengemudi' + maxWidth={'100%'} + maxHeight={'100%'} + src={imageUrl}/> + </Box> + <HStack alignItems={'left'} w='100%' pb={4}> + <Box> + <Text fontSize={'20px'} fontWeight={'Bold'} color='#02033B' pb={1}>{className}</Text> + <Text color='#02033B'>{vehicle}</Text> + </Box> + <Spacer></Spacer> + <HStack alignItems={'top'} mt={0.5}> + <Text color='#02033B'>{price}</Text> + </HStack> + </HStack> + <NavLink to='/ClassOwnerDetail'> + <Box textAlign={'center'}> + <Button + bgColor='#02033B' + color='white' + _hover={{bg: '#00027A'}} + w='80%' + fontWeight={'bold'} + borderRadius={30}>Lihat Detail</Button> + </Box> + </NavLink> + </Stack> </Box> ); }; diff --git a/src/components/ClassCardDetailPublic.tsx b/src/components/ClassCardDetailPublic.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a6f931dc53c99c4c054d0f5709d519eb0c6f25a7 --- /dev/null +++ b/src/components/ClassCardDetailPublic.tsx @@ -0,0 +1,77 @@ +import { + Box, + Text, + Image, + Spacer, + Stack, + Button, + HStack, + useDisclosure +} from '@chakra-ui/react'; + +import AddData from '../components/EnrollStudent'; + +export default function ClassCardDetail(props: any) { + const { isOpen, onOpen, onClose } = useDisclosure(); // Use Chakra UI useDisclosure hook + const handleAddDataClick = () => { + onOpen(); + }; + + return ( + <Box + w="350px" + h="auto" + bg="white" + border={'1px solid #000'} + borderRadius={15} + padding={4} + > + <Stack w="100%" h="100%" align="left"> + <Image + width={'350px'} + height={'150px'} + objectFit={'cover'} + alt="Katalog kelas mengemudi" + src={props.urlKen} + /> + <HStack alignItems={'left'} w="100%" pb={4}> + <Box> + <Text fontSize={'20px'} fontWeight={'Bold'} color="#02033B" pb={1}> + {props.namaKelas} + </Text> + <Text color="#02033B" pb={0.3}> + {props.namaKen} + </Text> + <Text color="#02033B" pb={0.3}> + Jumlah sesi: {props.jmlSesi} + </Text> + <Text color="#02033B" pb={0.3}> + Total jam: {props.totalJam} + </Text> + </Box> + <Spacer></Spacer> + <HStack alignItems={'top'} mt={0.5}> + <Text color="#02033B"> IDR {props.hargaKelas}</Text> + </HStack> + </HStack> + <Box textAlign={'center'}> + <Button + bgColor="#02033B" + color="white" + _hover={{ bg: '#00027A' }} + w="80%" + fontWeight={'bold'} + borderRadius={30} + onClick={handleAddDataClick} + > + Enroll + </Button> + </Box> + </Stack> + <AddData + disclosure={{ isOpen, onOpen, onClose }} + idKelas={props.classId} + /> + </Box> + ); +} diff --git a/src/components/ClassCardPublic.tsx b/src/components/ClassCardPublic.tsx new file mode 100644 index 0000000000000000000000000000000000000000..31714f43e2a515a33ac42c3044edf83fbffe4536 --- /dev/null +++ b/src/components/ClassCardPublic.tsx @@ -0,0 +1,111 @@ +import React from 'react'; +import { + Box, + Text, + Image, + Spacer, + Stack, + Button, + HStack, +} from '@chakra-ui/react'; +import { NavLink, useNavigate } from 'react-router-dom'; + +interface ClassCardProps { + drivingClassData: { + namaKelas: string; + hargaKelas: number; + totalJam: number; + jumlahSesi: number; + idKendaraan: number; + idClass: number; + deskripsiKelas: string; + vehicleType: { + idKendaraan: number; + namaKen: string; + urlKen: string; + }; + }[]; + vehicleTypeData: { + idKen: number; + namaKen: string; + jenisKen: string; + urlKen: string; + }[]; +} + +export const ClassCardComponent: React.FC<ClassCardProps> = ({ + drivingClassData, + vehicleTypeData, +}) => { + const navigate = useNavigate(); + + const handleLihatDetailClick = (idKelas: number) => { + // Redirect to ClassPublicDetail with the idKelas parameter + navigate(`/ClassPublicDetail/${idKelas}`); + }; + + return ( + <> + {drivingClassData.map((classData) => ( + <Box + key={classData.idClass} + w="400px" + h="auto" + bg="white" + border={'1px solid #000'} + borderRadius={15} + padding={4} + ml={25} + mr={25} + > + <Stack w="100%" h="100%" align="left"> + <Box boxSize={'auto'} w="100%"> + <Image + style={{ objectFit: 'contain' }} + alt="Katalog kelas mengemudi" + maxWidth={'100%'} + maxHeight={'100%'} + src={ + vehicleTypeData.find( + (type) => type.idKen === classData.idKendaraan + )?.urlKen || '' + } + /> + </Box> + <HStack alignItems={'left'} w="100%" pb={4}> + <Box> + <Text + fontSize={'20px'} + fontWeight={'Bold'} + color="#02033B" + pb={1} + > + {classData.namaKelas} + </Text> + <Text color="#02033B">{classData.vehicleType.namaKen}</Text> + </Box> + <Spacer></Spacer> + <HStack alignItems={'top'} mt={0.5}> + <Text color="#02033B">{classData.hargaKelas}</Text> + </HStack> + </HStack> + <div onClick={() => handleLihatDetailClick(classData.idClass)}> + <Box textAlign={'center'}> + <Button + bgColor="#02033B" + color="white" + _hover={{ bg: '#00027A' }} + w="80%" + fontWeight={'bold'} + borderRadius={30} + > + Lihat Detail + </Button> + </Box> + </div> + </Stack> + </Box> + ))} + </> + ); +}; diff --git a/src/components/ClassDetailPublic.tsx b/src/components/ClassDetailPublic.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8f1a50ec707cc7ddb1726c55761b6c4c2ca81d68 --- /dev/null +++ b/src/components/ClassDetailPublic.tsx @@ -0,0 +1,95 @@ +import React, { useState } from 'react'; +import { Text, Image, VStack, Heading, HStack, Spacer } from '@chakra-ui/react'; +import ClassCardDetail from './ClassCardDetailPublic'; + +interface ClassDetailProps { + drivingClassData: { + namaKelas: string; + hargaKelas: string; + totalJam: string; + jmlSesi: string; + idKendaraan: string; + idClass: string; + deskripsiKelas: string; + vehicleType: { + idKendaraan: string; + namaKen: string; + urlKen: string; + }; + }[]; + vehicleTypeData: { + idKen: number; + namaKen: string; + jenisKen: string; + urlKen: string; + }[]; + key: number; +} + +const ClassDetail: React.FC<ClassDetailProps> = ({ drivingClassData, vehicleTypeData}) => { + const [isDeleteDataOpen, setIsDeleteDataOpen] = useState(false); + + const placeholderToVariableMap = { + 'ID': 'id', + 'Nama': 'namaKelas', + 'Harga': 'hargaKelas', + 'Total Jam': 'totalJam', + 'Jumlah Sesi': 'jmlSesi', + 'Kendaraan': 'namaKen', + 'Deskripsi': 'deskripsi', + 'Link Gambar Kelas': 'urlKen', + }; + + return ( + <VStack h='100%' w={'100vw'} align='left'> + {drivingClassData.map((data) => ( + <React.Fragment key={data.idClass}> + <Image + style={{ objectFit: 'cover' }} + alt={`Katalog ${data.namaKelas}`} + maxWidth={'100vw'} + maxHeight={'12vw'} + src={data.vehicleType.urlKen} + /> + <HStack + mt={8} + maxW='full' + alignItems='left' + marginLeft='6%' // Add 5% left margin + marginRight='6%' // Add 5% right margin + > + <Heading fontWeight='bold' fontSize={50} color='#02033B' whiteSpace='nowrap'> + {data.namaKelas} + </Heading> + <Spacer /> + </HStack> + <HStack + mt={8} + maxW='full' + alignItems='left' + marginLeft='6%' // Add 5% left margin + marginRight='6%' // Add 5% right margin + > + <Text w='70%' whiteSpace='pre-line' mr='6%' textAlign='justify'> + {data.deskripsiKelas} + </Text> + <Spacer /> + <HStack align='top' height='100%'> + <ClassCardDetail + namaKelas={data.namaKelas} + hargaKelas={data.hargaKelas} + namaKen={data.vehicleType.namaKen} + urlKen={data.vehicleType.urlKen} + totalJam={data.totalJam} + jmlSesi={data.jmlSesi} + classId={data.idClass} + /> + </HStack> + </HStack> + </React.Fragment> + ))} + </VStack> + ); +}; + +export default ClassDetail; diff --git a/src/components/ClassGrid.tsx b/src/components/ClassGrid.tsx deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/components/DeletedataKendaraan.tsx b/src/components/DeletedataKendaraan.tsx index 0724ffc15f7e77acaf92128ae412e236017dd590..2a12d605c1d79c6f6dff13da294b54cca2b81fd1 100644 --- a/src/components/DeletedataKendaraan.tsx +++ b/src/components/DeletedataKendaraan.tsx @@ -30,12 +30,14 @@ interface DeleteDataProps { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; } } | null; vehicleTypeData: { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; }[] | null; onDelete: (vehicleData: any, vehicleTypeData: any) => void; } @@ -47,8 +49,9 @@ const DeleteData: React.FC<DeleteDataProps> = ({ disclosure, onDelete, kendaraan try { // Perform the deletion logic, for example, calling the API to delete the data await axios.delete(`http://localhost:5000/vehicle/${kendaraanData?.platKen}`); - + await axios.delete(`http://localhost:5000/vehicleType/${kendaraanData?.idKendaraan}`); // Handle other logic, such as closing the modal and notifying the parent component + window.location.reload(); onCloseDelete(); } catch (error) { console.error('Error while deleting data:', error); diff --git a/src/components/EditDataKendaraanAdmin.tsx b/src/components/EditDataKendaraanAdmin.tsx index 39397b292c5d12771100c4c4c0feb131054029ad..e5f6264290ca3a0685f17fa2996706aa577b40fa 100644 --- a/src/components/EditDataKendaraanAdmin.tsx +++ b/src/components/EditDataKendaraanAdmin.tsx @@ -32,12 +32,14 @@ interface EditDataProps { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; } } | null; vehicleTypeData: { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; }[] | null; onSave: (updatedVehicleData: any, updatedVehicleTypeData: any) => void; // Define a callback to save the updated data } @@ -51,6 +53,7 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT const [editedVehicleTypeData, setEditedVehicleTypeData] = useState({ namaKen: '', jenisKen: '', + urlKen: '', }); const [editedVehicleData, setEditedVehicleData] = useState({ @@ -68,6 +71,7 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT setEditedVehicleTypeData({ namaKen: selectedVehicleType.namaKen, jenisKen: selectedVehicleType.jenisKen, + urlKen: selectedVehicleType.urlKen, }); } setEditedVehicleData({ @@ -85,6 +89,7 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT const editedVehicleTypeDataa = { namaKen: editedVehicleTypeData.namaKen, jenisKen: editedVehicleTypeData.jenisKen, + urlKen: editedVehicleTypeData.urlKen, }; // Update VehicleType using idKen @@ -102,6 +107,7 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT await axios.put(`http://localhost:5000/vehicle/${kendaraanData?.platKen}`, editedVehicleDataa); // Handle other logic, such as closing the modal + window.location.reload(); onClose(); // Close the modal after saving } catch (error) { console.error('Error while saving updated data:', error); diff --git a/src/components/Editdatakendaraan.tsx b/src/components/Editdatakendaraan.tsx index edbe957ed878f9d9e1d0b482a8af2fa29366f1df..d9117d36d7f9ea3dda40fe18487bcd7f9ded9eea 100644 --- a/src/components/Editdatakendaraan.tsx +++ b/src/components/Editdatakendaraan.tsx @@ -32,12 +32,14 @@ interface EditDataProps { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; } } | null; vehicleTypeData: { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; }[] | null; onSave: (updatedVehicleData: any, updatedVehicleTypeData: any) => void; // Define a callback to save the updated data } @@ -51,6 +53,7 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT const [editedVehicleTypeData, setEditedVehicleTypeData] = useState({ namaKen: '', jenisKen: '', + urlKen: '', }); const [editedVehicleData, setEditedVehicleData] = useState({ @@ -68,6 +71,7 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT setEditedVehicleTypeData({ namaKen: selectedVehicleType.namaKen, jenisKen: selectedVehicleType.jenisKen, + urlKen: selectedVehicleType.urlKen, }); } setEditedVehicleData({ @@ -85,6 +89,7 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT const editedVehicleTypeDataa = { namaKen: editedVehicleTypeData.namaKen, jenisKen: editedVehicleTypeData.jenisKen, + urlKen: editedVehicleTypeData.urlKen, }; // Update VehicleType using idKen @@ -102,6 +107,7 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT await axios.put(`http://localhost:5000/vehicle/${kendaraanData?.platKen}`, editedVehicleDataa); // Handle other logic, such as closing the modal + window.location.reload(); onClose(); // Close the modal after saving } catch (error) { console.error('Error while saving updated data:', error); @@ -177,6 +183,15 @@ const EditData: React.FC<EditDataProps> = ({ disclosure, kendaraanData, vehicleT /> </FormControl> + <FormControl mt={4}> + <FormLabel>URL Kendaraan</FormLabel> + <Input + placeholder="URL Kendaraan" + value={editedVehicleTypeData.urlKen} + onChange={(e) => setEditedVehicleTypeData({ ...editedVehicleTypeData, urlKen: e.target.value })} + /> + </FormControl> + <FormControl mt={4}> <FormLabel>Status Kendaraan</FormLabel> <Select diff --git a/src/components/EnrollStudent.tsx b/src/components/EnrollStudent.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2bc24169d26ac8ca7dde4d61534c41f0cb2b9831 --- /dev/null +++ b/src/components/EnrollStudent.tsx @@ -0,0 +1,121 @@ +import React, { useRef, useEffect, useState } from 'react'; +import axios from 'axios'; + +import { + Button, + Modal, + ModalOverlay, + ModalContent, + ModalHeader, + ModalCloseButton, + ModalBody, + ModalFooter, + FormControl, + FormLabel, + Input, + ChakraProvider, +} from '@chakra-ui/react'; + +interface AddDataProps { + disclosure: { + isOpen: boolean; + onOpen: () => void; + onClose: () => void; + }; + idKelas: number; +} + +const AddData: React.FC<AddDataProps> = ({ disclosure, idKelas }) => { + const { isOpen, onOpen, onClose } = disclosure; + const initialRef = useRef<HTMLInputElement | null>(null); + + const [newData, setNewData] = useState({ + namaSiswa: '', + umurSiswa: 0, + noTelpSiswa: '', + alamatSiswa: '', + kelasSiswa: 0, + }); + + const enrollStudent = async () => { + try { + await axios.post('http://localhost:5000/student', { + namaSiswa: newData.namaSiswa, + umurSiswa: newData.umurSiswa, + noTelpSiswa: newData.noTelpSiswa, + alamatSiswa: newData.alamatSiswa, + kelasSiswa: idKelas, + status : 'Inactive', + }); + + console.log('Enrolling student:', newData); + // You can update state or perform other actions based on the result + onClose(); // Close the modal after enrollment + } catch (error) { + console.error('Error enrolling student:', error); + // Handle error, show error message, etc. + } + }; + + return ( + <ChakraProvider> + <Modal initialFocusRef={initialRef} isOpen={isOpen} onClose={onClose} size="xl"> + <ModalOverlay /> + <ModalContent> + <ModalHeader + fontWeight="bold" + color="#02033B" + fontFamily="Roboto" + fontSize="2xl" + textAlign="center" + > + Data Diri Pendaftar + </ModalHeader> + <ModalCloseButton /> + <ModalBody pb={6}> + <FormControl mt={4}> + <FormLabel>Nama</FormLabel> + <Input + ref={initialRef} + placeholder="Nama" + onChange={(e) => setNewData({ ...newData, namaSiswa: e.target.value })} + /> + </FormControl> + <FormControl mt={4}> + <FormLabel>Usia</FormLabel> + <Input + type="number" + placeholder="Usia" + onChange={(e) => + setNewData({ ...newData, umurSiswa: parseInt(e.target.value) || 0 }) + } + /> + </FormControl> + <FormControl mt={4}> + <FormLabel>No. Telepon</FormLabel> + <Input + placeholder="No. Telepon" + onChange={(e) => setNewData({ ...newData, noTelpSiswa: e.target.value })} + /> + </FormControl> + <FormControl mt={4}> + <FormLabel>Alamat</FormLabel> + <Input + placeholder="Alamat" + onChange={(e) => setNewData({ ...newData, alamatSiswa: e.target.value })} + /> + </FormControl> + </ModalBody> + <ModalFooter> + <Button colorScheme="orange" mr={3} onClick={enrollStudent}> + Submit + </Button> + <Button onClick={onClose}>Cancel</Button> + </ModalFooter> + </ModalContent> + </Modal> + </ChakraProvider> + ); +}; + +export default AddData; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index ce25d7bc1995e4aaa16bc8281abe064711cea8e1..8806242917ff15e8074b2df9ce7a9660977b12ef 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,29 +1,22 @@ -import React from "react"; import { Box, Flex, Spacer, Text, - ChakraProvider, - extendTheme, Link, - Icon, Image, + Button, } from "@chakra-ui/react"; import Admin from '../assets/Admin.svg'; import KarsusLogo from '../assets/logo_horizontal.svg' import { Link as RouterLink } from "react-router-dom"; import Logout from '../components/Logout'; -const theme = extendTheme({ - fonts: { - body: "Roboto Bold, sans-serif", - }, -}); - -const Navbar = () => { +export default function Navbar(props: { status: string; } ){ + const isOwner = (props.status == "owner"); + const isAdmin = (props.status == "admin"); + const isPublic = (props.status == "public"); return ( - <ChakraProvider theme={theme}> <Box bg="#FDB235" color="#02033B" @@ -48,6 +41,8 @@ const Navbar = () => { {/* Links */} <Flex display={{ base: "none", md: "flex" }}> + { + isPublic && <Box mx={10} position="relative" @@ -67,9 +62,39 @@ const Navbar = () => { }} as={RouterLink} to="/" > - Data Kelas + Beranda + </Link> + </Box> + } + + { + isOwner && + <Box + mx={10} + position="relative" + fontWeight="bold" + padding= '10px' + style={{ whiteSpace: 'nowrap' }} + _hover={{ + color: 'white', + bgColor: '#02033B', + rounded: 'md', + }} + > + <Link + fontWeight="bold" // Make the link text bold + _hover={{ + color: 'white', + }} + as={RouterLink} to="/userdata" + > + Data User </Link> </Box> + } + + { + (isOwner || isAdmin || isPublic) && <Box mx={10} position="relative" @@ -87,12 +112,42 @@ const Navbar = () => { _hover={{ textColor: 'white', }} - as={RouterLink} to="/studentdata" + as={RouterLink} to={isOwner ? "/classowner" : "/classpublic"} > - Data Siswa + Data Kelas </Link> </Box> + } + + { + isAdmin && + <Box + mx={10} + position="relative" + fontWeight="bold" + rounded='md' + padding='10px' + style={{ whiteSpace: 'nowrap' }} + _hover={{ + color: 'white', + bgColor: '#02033B', + }} + > + <Link + fontWeight="bold" + _hover={{ + color: 'white', + }} + as={RouterLink} to="/studentdata" + > + Data Siswa + </Link> + </Box> + } + + { + isOwner && <Box mx={10} position="relative" @@ -110,26 +165,67 @@ const Navbar = () => { _hover={{ color: 'white', }} - as={RouterLink} to="/vehicledataadmin" + as={RouterLink} to="/instructordata" > - Data Kendaraan + Data Instruktur </Link> </Box> + } + + { + (isOwner || isAdmin) && + <Box + mx={10} + position="relative" + fontWeight="bold" + rounded='md' + padding='10px' + style={{ whiteSpace: 'nowrap' }} + _hover={{ + color: 'white', + bgColor: '#02033B', + }} + > + <Link + fontWeight="bold" + _hover={{ + color: 'white', + }} + as={RouterLink} to={isOwner ? "/vehicledataowner" : "/vehicledataadmin"} + > + Data Kendaraan + </Link> + </Box> + } </Flex> - <Spacer mx={36} /> + <Spacer mx={5} /> {/* Admin Greeting */} + + { (isOwner || isAdmin) && <Flex alignItems="center"> - <Text mr={4} fontWeight="bold" style={{ whiteSpace: 'nowrap' }}>Hi, Admin</Text> + <Text mr={4} fontWeight="bold" style={{ whiteSpace: 'nowrap' }}> + Hi, { + isOwner ? ( + "Owner" + ) : ( + "Admin" + ) + } + </Text> <Image src={Admin} boxSize={6} /> <Spacer mx={2} /> <Logout onLogout={() => console.log('Perform Logout')} /> </Flex> + } + + { isPublic && + <Button colorScheme="orange" mr={3} as={RouterLink} to="/login"> + Login + </Button> + } </Box> - </ChakraProvider> ); -}; - -export default Navbar; \ No newline at end of file +}; \ No newline at end of file diff --git a/src/components/Searchbar.tsx b/src/components/Searchbar.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4a2a1f6d30b28a1925ea84f7351f0345d355d8c1 --- /dev/null +++ b/src/components/Searchbar.tsx @@ -0,0 +1,22 @@ +import { Input, InputGroup, InputRightElement, Image } from "@chakra-ui/react"; +import SearchIcon from "../assets/search_icon.svg"; +import { ChakraProvider } from "@chakra-ui/react"; + +export default function Searchbar(props: { placeholder: string }) { + return ( + <ChakraProvider> + <InputGroup> + <InputRightElement pointerEvents="none"> + <Image + src={SearchIcon} + alt="Search Icon" + boxSize="16px" + mt={3} + mr={3} + /> + </InputRightElement> + <Input variant="variant" placeholder={props.placeholder} size="lg" /> + </InputGroup> + </ChakraProvider> + ); +} diff --git a/src/components/TableKendaraan.tsx b/src/components/TableKendaraan.tsx index 78771d399f820b9719eab296385a88d72d70862e..332c9d306f848e32ed7e185fbc64464b7f683c40 100644 --- a/src/components/TableKendaraan.tsx +++ b/src/components/TableKendaraan.tsx @@ -28,12 +28,14 @@ interface TableProps { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; }; }[]; vehicleTypeData: { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; }[]; onEditClick: (vehicleData: any, vehicleTypeData: any) => void; onDeleteClick: (vehicleData: any, vehicleTypeData: any) => void; diff --git a/src/components/TableKendaraanAdmin.tsx b/src/components/TableKendaraanAdmin.tsx index 01f5667c766d247cb80934756f44dfed3e0cb516..23056f83335085f143cad41c85e5ad43de381d78 100644 --- a/src/components/TableKendaraanAdmin.tsx +++ b/src/components/TableKendaraanAdmin.tsx @@ -23,12 +23,14 @@ interface TableProps { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; }; }[]; vehicleTypeData: { idKen: number; namaKen: string; jenisKen: string; + urlKen: string; }[]; onEditClick: (vehicleData: any, vehicleTypeData: any) => void; } diff --git a/src/index.css b/src/index.css index f0283e7cc7eade6de24af75bd2be79e734a62ba9..3e9f73e0889bfc6940c8f39d26e9b15bbf86e266 100644 --- a/src/index.css +++ b/src/index.css @@ -19,24 +19,9 @@ margin: 0; box-sizing: border-box; } -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - place-items: center; - min-width: 320px; - min-height: 100vh; -} h1 { - font-size: 3.2em; + font-size: 3.2 em; line-height: 1.1; } @@ -45,38 +30,5 @@ html, body { padding: 0; width: 100%; height: 100%; - overflow: hidden; -} - - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} + overflow: auto; +} \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index 19743f9155420eb2e22a7cb2595b806cde440b7f..8065c06729ad121ff14f3755e62157eb15a4ba17 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -30,7 +30,7 @@ const router = createBrowserRouter([ element: <LoginPage /> }, { - path: "/classpublicdetail", + path: "/classpublicdetail/:id", // Updated path to include the id parameter element: <ClassPublicDetail /> }, { @@ -58,7 +58,7 @@ const router = createBrowserRouter([ element: <ClassOwner/> }, { - path: "/classownerdetail", + path: "/classownerdetail/:id", // Updated path to include the id parameter element: <ClassOwnerDetail/> } ]); diff --git a/src/pages/ClassPublic.tsx b/src/pages/ClassPublic.tsx index 8a9d31da9379f14304ddf4bd0e67ec43488d1bc6..8d5fa01e19055d7d5fe27aae1846f8e4313e28bf 100644 --- a/src/pages/ClassPublic.tsx +++ b/src/pages/ClassPublic.tsx @@ -1,88 +1,61 @@ -import React from 'react'; -import Navbar from "../components/NavbarOwner"; -import { Box, Flex, Text, IconButton, Image, SimpleGrid } from "@chakra-ui/react"; -import { ClassCard } from "../components/ClassCard"; - -interface ClassInfo { - id: number; - className: string; - price: string; - vehicle: string; - imageUrl: string; -} - -const classData: ClassInfo[] = [ - { - id: 1, - className: 'Economy Class', - price: 'IDR 1.000.000', - vehicle: 'Toyota Yaris', - imageUrl: 'https://via.placeholder.com/150', - }, - { - id: 2, - className: 'Business Class', - price: 'IDR 2.000.000', - vehicle: 'Honda Civic', - imageUrl: 'https://via.placeholder.com/150', - }, - { - id: 3, - className: 'First Class', - price: 'IDR 3.000.000', - vehicle: 'BMW 3 Series', - imageUrl: 'https://via.placeholder.com/150', - }, - // ...add more classes -]; +import React, { useEffect, useState } from 'react'; +import Navbar from '../components/Navbar'; +import { ClassCardComponent } from '../components/ClassCardPublic'; +import CardWrapper from '../components/CardWrapper'; +import ActionButtons from '../components/ActionButtonNoAdd'; +import { VStack, Flex, ChakraProvider } from '@chakra-ui/react'; // Import ChakraProvider +import axios from 'axios'; const ClassData: React.FC = () => { - return ( - <> - <Navbar /> - <Flex - direction="column" - minHeight="100vh" - bg="#F5F8FD" // Set the background color for the entire section here - > - <Flex - mt={8} - maxW="full" - alignItems="center" // Center items vertically - justifyContent="space-between" // Space between the title, search bar, and add button - px={20} // Padding on the sides - > - <Text - as="h1" - fontSize="2xl" - color="#02033B" - fontWeight="bold" - my={8} // Margin on top and bottom - > - Data Kelas - </Text> + const [drivingClass, setDrivingClass] = useState<any>(null); // State for driving class + const [vehicleType, setVehicleType] = useState<any[]>([]); // State for vehicle type - </Flex> + useEffect(() => { + const fetchData = async () => { + try { + const drivingClassResponse = await axios.get('http://localhost:5000/drivingClass'); + const vehicleTypeResponse = await axios.get('http://localhost:5000/vehicleType'); + setDrivingClass(drivingClassResponse.data); + setVehicleType(vehicleTypeResponse.data); + } catch (error) { + console.log('error fetching data: ', error); + } + }; + fetchData(); + }, []); - <SimpleGrid - mt={8} - columns={{ sm: 1, md: 2, lg: 3 }} - spacing={10} - px={20} // Padding on the sides - > - {classData.map((data) => ( - <ClassCard - key={data.id} - className={data.className} - price={data.price} - vehicle={data.vehicle} - imageUrl={data.imageUrl} - /> - ))} - </SimpleGrid> + const placeholderToVariableMap = { + 'Nama': 'namaKelas', + 'Harga': 'hargaKelas', + 'Total Jam': 'total_jam', + 'Jumlah Sesi': 'jml_sesi', + 'Kendaraan': 'vehicle', + }; - </Flex> - </> + return ( + <ChakraProvider> {/* Wrap your entire app with ChakraProvider */} + <VStack h="100%" w={'100vw'} bg="#F5F8FD"> + <Navbar status="public" /> + <Flex direction="column" w="100vw" pl={25} pr={25}> + <ActionButtons + placeholder="Search Class" + title="Kelas" + placeholders={['Nama', 'Harga', 'Total Jam', 'Jumlah Sesi', 'Kendaraan']} + placeholderToVariableMap={placeholderToVariableMap} + /> + <CardWrapper columns={{ base: 1, sm: 1, md: 2, lg: 3 }}> + {drivingClass && + drivingClass.map((data: any) => ( + <ClassCardComponent + key={data.idClass} + drivingClassData={drivingClass} + vehicleTypeData={vehicleType} + /> + ))} + </CardWrapper> + </Flex> + </VStack> + </ChakraProvider> ); }; diff --git a/src/pages/ClassPublicDetail.tsx b/src/pages/ClassPublicDetail.tsx index b354c2fba0265650cb3f02b6ee49306f644f55a1..e3fce8227d102cf00eaa948ecc6e28ee9871c8e0 100644 --- a/src/pages/ClassPublicDetail.tsx +++ b/src/pages/ClassPublicDetail.tsx @@ -1,7 +1,59 @@ -export default function ClassPublicDetail(){ - return(<> - <h1> - This is the class public detail page - </h1> - </>) -} \ No newline at end of file +import React, { useEffect, useState } from 'react'; +import Navbar from '../components/Navbar'; +import { Box, Flex, ChakraProvider } from '@chakra-ui/react'; // Import ChakraProvider +import ClassDetail from '../components/ClassDetailPublic'; +import { useParams } from 'react-router-dom'; +import axios from 'axios'; + +const ClassData: React.FC = () => { + const { id: idString } = useParams<{ id: string }>(); + const idNumber = Number(idString); + const [drivingClass, setDrivingClass] = useState<any>(null); // State for driving class + const [vehicleType, setVehicleType] = useState<any[]>([]); // State for vehicle type + + useEffect(() => { + const fetchData = async () => { + try { + const drivingClassResponse = await axios.get('http://localhost:5000/drivingClass'); + const vehicleTypeResponse = await axios.get('http://localhost:5000/vehicleType'); + setDrivingClass(drivingClassResponse.data); + setVehicleType(vehicleTypeResponse.data); + } catch (error) { + console.log('error fetching data: ', error); + } + }; + fetchData(); + }, []); + + const placeholderToVariableMap = { + ID: 'id', + Nama: 'className', + Harga: 'price', + 'Total Jam': 'total_jam', + 'Jumlah Sesi': 'jml_sesi', + Kendaraan: 'vehicle', + Deskripsi: 'deskripsi', + 'Link Gambar Kelas': 'imageUrl', + }; + + console.log('id from useParams:', idNumber); // Log the id to check if it's undefined or has a value + + return ( + <ChakraProvider> {/* Wrap your component with ChakraProvider */} + <Box h="100%" w={'100vw'}> + <Navbar status ="public" /> + <Flex direction="column" w="100vw"> + {drivingClass && drivingClass.map((data: any) => ( + <ClassDetail + key={data.idClass} + drivingClassData={drivingClass} + vehicleTypeData={vehicleType} + /> + ))} + </Flex> + </Box> + </ChakraProvider> + ); +}; + +export default ClassData; diff --git a/src/pages/StudentData.tsx b/src/pages/StudentData.tsx index 3bc650c55af56239cdc97dae96523405f88acafb..cb3f4851055e17d2a67f67224382aa95123a7bbc 100644 --- a/src/pages/StudentData.tsx +++ b/src/pages/StudentData.tsx @@ -35,7 +35,7 @@ const UserData: React.FC = () => { return ( <> - <Navbar /> + <Navbar status = "admin" /> <Flex direction="column" minHeight="100vh" diff --git a/src/pages/VehicleDataAdmin.tsx b/src/pages/VehicleDataAdmin.tsx index 555ac68f222197b5d413b64c575c1c20087943a8..8d78ec5e5a519fb4c0a44c3f188f56323243a3ff 100644 --- a/src/pages/VehicleDataAdmin.tsx +++ b/src/pages/VehicleDataAdmin.tsx @@ -1,12 +1,10 @@ import React, { useState, useEffect } from "react"; -import Navbar from "../components/NavbarOwner"; -import { Box, Text, Flex, IconButton, useDisclosure } from "@chakra-ui/react"; -import Searchbar from "../components/SearchbarSiswa"; +import Navbar from "../components/Navbar"; +import { Box, Text, Flex, IconButton, useDisclosure, ChakraProvider } from "@chakra-ui/react"; // Import ChakraProvider import TableComponent from "../components/TableKendaraanAdmin"; -import Plus from "../assets/plus_button.svg"; -import Adddata from "../components/Adddatakendaraan"; import EditData from "../components/EditDataKendaraanAdmin"; import axios from "axios"; +import Searchbar from "../components/Searchbar"; const KendaraanDataOwner: React.FC = () => { const { isOpen, onOpen, onClose } = useDisclosure(); @@ -16,28 +14,23 @@ const KendaraanDataOwner: React.FC = () => { const [vehicleTypeData, setVehicleTypeData] = useState<any[]>([]); // State for vehicle type data] const [selectedVehicleType, setSelectedVehicleType] = useState<any>(null); // State for selected vehicle type const [selectedVehicleData, setSelectedVehicleData] = useState<any>(null); // State for selected vehicle data -//declare state for selected data + //declare state for selected data + useEffect(() => { + const fetchData = async () => { + try { + const vehicleResponse = await axios.get("http://localhost:5000/vehicle"); + const vehicleTypeResponse = await axios.get("http://localhost:5000/vehicleType"); - // Fetch vehicle data - axios.get("http://localhost:5000/vehicle") - .then((response) => { - setKendaraanData(response.data); - console.log(response.data); - }) - .catch((error) => { - console.error('Error fetching vehicle data:', error); - }); - - // Fetch vehicle type data - axios.get("http://localhost:5000/vehicleType") - .then((response) => { - setVehicleTypeData(response.data); - }) - .catch((error) => { - console.error('Error fetching vehicle type data:', error); - }); + setKendaraanData(vehicleResponse.data); + setVehicleTypeData(vehicleTypeResponse.data); + } catch (error) { + console.error('Error fetching data:', error); + } + }; + fetchData(); + }, []); const handleAddDataClick = () => { onOpen(); @@ -50,84 +43,64 @@ const KendaraanDataOwner: React.FC = () => { }; return ( - <> - <Navbar /> - <Flex - direction="column" - minHeight="100vh" - bg="#F5F8FD" - > - <Box - mt={8} - maxW="100%" // Adjusted to 100% for full width - display="flex" - alignItems="center" - style={{ whiteSpace: 'nowrap' }} - ml="5%" // Add 5% left margin - mr="5%" // Add 5% right margin + <ChakraProvider> {/* Wrap your component with ChakraProvider */} + <> + <Navbar status="admin" /> + <Flex + direction="column" + minHeight="100vh" + bg="#F5F8FD" > - <Text - as="h1" - fontSize="2xl" - color="#02033B" - fontWeight="bold" - marginTop="50px" - > - Data Kendaraan - </Text> - - <Flex - maxW="20%" // Adjusted to 20% for the search bar - ml="auto" // Auto margin for better alignment - mt="60px" - justify="center" // Center the content horizontally + <Box + mt={8} + maxW="100%" // Adjusted to 100% for full width + display="flex" + alignItems="center" + style={{ whiteSpace: 'nowrap' }} + ml="5%" // Add 5% left margin + mr="5%" // Add 5% right margin > - <Searchbar /> - </Flex> + <Text + fontWeight="bold" + fontSize={50} + color="#02033B" + whiteSpace="nowrap" + mr="5%" + > + Data Kendaraan + </Text> - <Box ml="auto" mt="65px"> {/* Adjusted margin */} - <IconButton - aria-label="Add" - icon={<img src={Plus} alt="Plus Icon" style={{ width: '40px' }} />} - onClick={handleAddDataClick} - size="lg" - variant="ghost" - /> + <Flex + > + <Searchbar placeholder="Cari Kendaraan" /> + </Flex> </Box> - </Box> - <Flex - mt={24} + <Flex + mt={10} maxW="100%" justify="center" ml="5%" // Add 5% left margin mr="5%" // Add 5% right margin - > - <TableComponent data={kendaraanData} vehicleTypeData={vehicleTypeData} onEditClick={handleEditDataClick} /> + > + <TableComponent data={kendaraanData} vehicleTypeData={vehicleTypeData} onEditClick={handleEditDataClick} /> + </Flex> </Flex> - </Flex> - - {isOpen && ( - <Adddata disclosure={{ isOpen, onOpen, onClose }} onAdd={(newData: any) => { - console.log('Adding new data:', newData); - // Implement logic to add the new data (e.g., API call) - onClose(); - }} /> - )} - {isEditDataOpen && ( - <EditData - disclosure={{ isOpen: isEditDataOpen, onOpen: handleOpenEditData, onClose: handleCloseEditData }} - kendaraanData={selectedVehicleData} - vehicleTypeData={selectedVehicleType} - onSave={(updatedVehicleData: any, updatedVehicleTypeData:any ) => { - console.log('Saving updated data:', updatedVehicleData, updatedVehicleTypeData); - // Implement logic to save the updated data (e.g., API call) - handleCloseEditData(); - }} - /> - )} - </> + {isEditDataOpen && ( + <EditData + disclosure={{ isOpen: isEditDataOpen, onOpen: handleOpenEditData, onClose: handleCloseEditData }} + kendaraanData={selectedVehicleData} + vehicleTypeData={selectedVehicleType} + onSave={(updatedVehicleData: any, updatedVehicleTypeData:any ) => { + console.log('Saving updated data:', updatedVehicleData, updatedVehicleTypeData); + // Implement logic to save the updated data (e.g., API call) + handleCloseEditData(); + }} + /> + )} + </> + </ChakraProvider> ); }; diff --git a/src/pages/VehicleDataOwner.tsx b/src/pages/VehicleDataOwner.tsx index c0a607f0cc433f3ce76bcb38702a4cfff0909c93..a0e26c4859ef6f6f9b99f6807b1c0b6726628abd 100644 --- a/src/pages/VehicleDataOwner.tsx +++ b/src/pages/VehicleDataOwner.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from "react"; -import Navbar from "../components/NavbarOwner"; -import { Box, Text, Flex, IconButton, useDisclosure } from "@chakra-ui/react"; -import Searchbar from "../components/SearchbarSiswa"; +import Navbar from "../components/Navbar"; +import { Box, Text, Flex, IconButton, useDisclosure, ChakraProvider } from "@chakra-ui/react"; +import Searchbar from "../components/Searchbar"; import TableComponent from "../components/TableKendaraan"; import Plus from "../assets/plus_button.svg"; import Adddata from "../components/Adddatakendaraan"; @@ -12,7 +12,6 @@ import DeleteData from "../components/DeletedataKendaraan"; const KendaraanDataOwner: React.FC = () => { const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen: isEditDataOpen, onOpen: handleOpenEditData, onClose: handleCloseEditData } = useDisclosure(); - const [selectedData, setSelectedData] = useState<any>(null); const [kendaraanData, setKendaraanData] = useState<any[]>([]); // State for vehicle data const [vehicleTypeData, setVehicleTypeData] = useState<any[]>([]); // State for vehicle type data] const [selectedVehicleType, setSelectedVehicleType] = useState<any>(null); // State for selected vehicle type @@ -38,24 +37,21 @@ const KendaraanDataOwner: React.FC = () => { }; // Fetch vehicle data - axios.get("http://localhost:5000/vehicle") - .then((response) => { - setKendaraanData(response.data); - console.log(response.data); - }) - .catch((error) => { - console.error('Error fetching vehicle data:', error); - }); + useEffect(() => { + const fetchData = async () => { + try { + const vehicleResponse = await axios.get("http://localhost:5000/vehicle"); + const vehicleTypeResponse = await axios.get("http://localhost:5000/vehicleType"); - // Fetch vehicle type data - axios.get("http://localhost:5000/vehicleType") - .then((response) => { - setVehicleTypeData(response.data); - }) - .catch((error) => { - console.error('Error fetching vehicle type data:', error); - }); + setKendaraanData(vehicleResponse.data); + setVehicleTypeData(vehicleTypeResponse.data); + } catch (error) { + console.error('Error fetching data:', error); + } + }; + fetchData(); + }, []); const handleAddDataClick = () => { onOpen(); @@ -68,98 +64,96 @@ const KendaraanDataOwner: React.FC = () => { }; return ( - <> - <Navbar /> - <Flex - direction="column" - minHeight="100vh" - bg="#F5F8FD" - > - <Box - mt={8} - maxW="100%" // Adjusted to 100% for full width - display="flex" - alignItems="center" - style={{ whiteSpace: 'nowrap' }} - ml="5%" // Add 5% left margin - mr="5%" // Add 5% right margin + <ChakraProvider> {/* Wrap your component with ChakraProvider */} + <> + <Navbar status="owner" /> + <Flex + direction="column" + minHeight="100vh" + bg="#F5F8FD" > - <Text - as="h1" - fontSize="2xl" - color="#02033B" - fontWeight="bold" - marginTop="50px" + <Box + mt={8} + maxW="100%" // Adjusted to 100% for full width + display="flex" + alignItems="center" + style={{ whiteSpace: 'nowrap' }} + ml="5%" // Add 5% left margin + mr="5%" // Add 5% right margin > - Data Kendaraan - </Text> + <Text + fontWeight="bold" + fontSize={50} + color="#02033B" + whiteSpace="nowrap" + mr="5%" + > + Data Kendaraan + </Text> - <Flex - maxW="20%" // Adjusted to 20% for the search bar - ml="auto" // Auto margin for better alignment - mt="60px" - justify="center" // Center the content horizontally - > - <Searchbar /> - </Flex> + <Flex + > + <Searchbar placeholder="Cari Kendaraan"/> + </Flex> - <Box ml="auto" mt="65px"> {/* Adjusted margin */} - <IconButton - aria-label="Add" - icon={<img src={Plus} alt="Plus Icon" style={{ width: '40px' }} />} - onClick={handleAddDataClick} - size="lg" - variant="ghost" - /> + <Box ml="auto" mt="65px"> {/* Adjusted margin */} + <IconButton + aria-label="Add" + icon={<img src={Plus} alt="Plus Icon" style={{ width: '40px' }} />} + onClick={handleAddDataClick} + size="lg" + variant="ghost" + /> + </Box> </Box> - </Box> - <Flex - mt={24} - maxW="100%" - justify="center" - ml="5%" // Add 5% left margin - mr="5%" // Add 5% right margin - > - <TableComponent data={kendaraanData} vehicleTypeData={vehicleTypeData} onEditClick={handleEditDataClick} onDeleteClick={handleDeleteDataClick} /> + <Flex + mt={10} + maxW="100%" + justify="center" + ml="5%" // Add 5% left margin + mr="5%" // Add 5% right margin + > + <TableComponent data={kendaraanData} vehicleTypeData={vehicleTypeData} onEditClick={handleEditDataClick} onDeleteClick={handleDeleteDataClick} /> + </Flex> </Flex> - </Flex> - {isOpen && ( - <Adddata disclosure={{ isOpen, onOpen, onClose }} onAdd={(newData: any) => { - console.log('Adding new data:', newData); - // Implement logic to add the new data (e.g., API call) - onClose(); - }} /> - )} + {isOpen && ( + <Adddata disclosure={{ isOpen, onOpen, onClose }} onAdd={(newData: any) => { + console.log('Adding new data:', newData); + // Implement logic to add the new data (e.g., API call) + onClose(); + }} /> + )} - {isEditDataOpen && ( - <EditData - disclosure={{ isOpen: isEditDataOpen, onOpen: handleOpenEditData, onClose: handleCloseEditData }} - kendaraanData={selectedVehicleData} - vehicleTypeData={selectedVehicleType} - onSave={(updatedVehicleData: any, updatedVehicleTypeData: any) => { - console.log('Saving updated data:', updatedVehicleData, updatedVehicleTypeData); - // Implement logic to save the updated data (e.g., API call) - handleCloseEditData(); - }} - /> - )} - {/* DeleteData modal */} - {isDeleteDataOpen && ( - <DeleteData - disclosure={{ isOpenDelete: isDeleteDataOpen, onOpenDelete: handleOpenDeleteData, onCloseDelete: handleCloseDeleteData }} - kendaraanData={selectedVehicleData} - vehicleTypeData={selectedVehicleType} - onDelete={() => { - console.log('Deleting data:', selectedVehicleData); - // Implement logic to delete the data (e.g., API call) - handleCloseDeleteData(); - }} - /> - )} - </> + {isEditDataOpen && ( + <EditData + disclosure={{ isOpen: isEditDataOpen, onOpen: handleOpenEditData, onClose: handleCloseEditData }} + kendaraanData={selectedVehicleData} + vehicleTypeData={selectedVehicleType} + onSave={(updatedVehicleData: any, updatedVehicleTypeData: any) => { + console.log('Saving updated data:', updatedVehicleData, updatedVehicleTypeData); + // Implement logic to save the updated data (e.g., API call) + handleCloseEditData(); + }} + /> + )} + {/* DeleteData modal */} + {isDeleteDataOpen && ( + <DeleteData + disclosure={{ isOpenDelete: isDeleteDataOpen, onOpenDelete: handleOpenDeleteData, onCloseDelete: handleCloseDeleteData }} + kendaraanData={selectedVehicleData} + vehicleTypeData={selectedVehicleType} + onDelete={() => { + console.log('Deleting data:', selectedVehicleData); + // Implement logic to delete the data (e.g., API call) + handleCloseDeleteData(); + }} + /> + )} + </> + </ChakraProvider> ); }; -export default KendaraanDataOwner; +export default KendaraanDataOwner