diff --git a/src/app/(application)/banner/edit/[id]/page.tsx b/src/app/(application)/banner/edit/[id]/page.tsx index ef3b077..1df7437 100644 --- a/src/app/(application)/banner/edit/[id]/page.tsx +++ b/src/app/(application)/banner/edit/[id]/page.tsx @@ -1,11 +1,7 @@ - import { EditBanner } from "@/module/banner"; -import { Box } from "@mantine/core"; export default function Page() { return ( - - - + ); } \ No newline at end of file diff --git a/src/module/banner/index.ts b/src/module/banner/index.ts index f84b767..1aa792a 100644 --- a/src/module/banner/index.ts +++ b/src/module/banner/index.ts @@ -3,4 +3,4 @@ import ListBanner from "./ui/list_banner"; import CreateBanner from "./ui/create_banner"; import EditBanner from "./ui/edit_banner"; import ViewfileBanner from "./ui/viewfile_banner"; -export {NavbarBanner, ListBanner, CreateBanner, EditBanner, ViewfileBanner} \ No newline at end of file +export { NavbarBanner, ListBanner, CreateBanner, EditBanner, ViewfileBanner } diff --git a/src/module/banner/ui/create_banner.tsx b/src/module/banner/ui/create_banner.tsx index 86499e1..25e938d 100644 --- a/src/module/banner/ui/create_banner.tsx +++ b/src/module/banner/ui/create_banner.tsx @@ -10,6 +10,7 @@ import { useRouter } from 'next/navigation'; import { useRef, useState } from 'react'; import toast from 'react-hot-toast'; import { funCreateBanner } from '../lib/api_banner'; +import { title } from 'process'; function CreateBanner() { const router = useRouter(); @@ -17,36 +18,49 @@ function CreateBanner() { const tema = useHookstate(TEMA) const [loadingKonfirmasi, setLoadingKonfirmasi] = useState(false) const [listData, setListData] = useState({ - title: "", - + title: "", + image: "" + }); const [imgForm, setImgForm] = useState() const openRef = useRef<() => void>(null) const [img, setIMG] = useState() - // const [body, setBody] = useState({ - // id: "", - // title: "", - // }); - - - // function onCheck() { - // const cek = checkAll() - // if (!cek) - // return false - // setModal(true) - // } - - + const [touched, setTouched] = useState({ + title: false, + image: false + }) + + function onValidation(kategori: string, val: any) { + if (kategori == 'title') { + setListData({ ...listData, title: val }) + if (val === "") { + setTouched({ ...touched, title: true }) + } else { + setTouched({ ...touched, title: false }) + } + } else if (kategori == 'image') { + if (imgForm) { + setTouched({ ...touched, image: false }) + } else { + setTouched({ ...touched, image: true }) + } + } + } + + async function onSubmit(val: boolean) { + if (!imgForm || !listData.title) { + toast.error("Mohon lengkapi semua data"); + } try { - console.log(listData) setLoadingKonfirmasi(true) const fd = new FormData() fd.append("file", imgForm) fd.append("data", JSON.stringify( { - title: listData.title + title: listData.title, + image: listData.image } )) const res = await funCreateBanner(fd); @@ -80,10 +94,11 @@ function CreateBanner() { onDrop={async (files) => { if (!files || _.isEmpty(files)) return toast.error('Tidak ada gambar yang dipilih') - setImgForm(files[0]) - // const buffer = URL.createObjectURL(files[0]); + const file = files[0] + setImgForm(file) const buffer = URL.createObjectURL(new Blob([new Uint8Array(await files[0].arrayBuffer())])) setIMG(buffer) + onValidation('image', files[0]) }} activateOnClick={false} maxSize={1 * 1024 ** 2} @@ -96,7 +111,7 @@ function CreateBanner() { { img ? - + : @@ -123,7 +138,7 @@ function CreateBanner() { Klik Untuk Upload Image - Ukuran Foto Tidak Boleh Lebih Dari 500MB + Ukuran Foto Tidak Boleh Lebih Dari 1MB @@ -134,15 +149,21 @@ function CreateBanner() { Judul Banner} + label={Judul Banner} + value={listData.title} placeholder='Judul Banner' + onChange={(e) => { + setListData({ ...listData, title: e.target.value }) + onValidation('title', e.target.value) + }} styles={{ input: { - border: `1px solid ${"#D6D8F6"}`, + border: `1px solid ${touched.title ? 'red' : "#D6D8F6"}`, borderRadius: 10, }, }} - onChange={(val) => { setListData({ title: val.target.value })}} + + /> { setModal(true)}} + onClick={() => { + if (touched.title || touched.image) { + toast.error("Mohon Isi Semua Data") + } else { + setModal(true) + } + }} >Simpan @@ -172,7 +199,7 @@ function CreateBanner() { setModal(false); } }} - + /> ); diff --git a/src/module/banner/ui/edit_banner.tsx b/src/module/banner/ui/edit_banner.tsx index d40ac60..411c731 100644 --- a/src/module/banner/ui/edit_banner.tsx +++ b/src/module/banner/ui/edit_banner.tsx @@ -2,22 +2,101 @@ import { LayoutNavbarNew, TEMA, WARNA } from '@/module/_global'; import LayoutModal from '@/module/_global/layout/layout_modal'; import { useHookstate } from '@hookstate/core'; -import { Box, Button, Group, Paper, rem, Text, TextInput } from '@mantine/core'; -import { Dropzone, DropzoneProps, IMAGE_MIME_TYPE } from '@mantine/dropzone'; -import { IconPhoto, IconUpload, IconX } from '@tabler/icons-react'; +import { Box, Button, Image, Paper, rem, TextInput } from '@mantine/core'; +import { Dropzone } from '@mantine/dropzone'; +import { useShallowEffect } from '@mantine/hooks'; +import _ from 'lodash'; import { useParams, useRouter } from 'next/navigation'; -import { useState } from 'react'; +import { useRef, useState } from 'react'; +import toast from 'react-hot-toast'; +import { funEditBanner, funGetOneBanner } from '../lib/api_banner'; +import { IEditDataBanner } from '../lib/type_banner'; -function EditBanner(props: Partial ) { +export default function EditBanner() { + const router = useRouter() + const param = useParams<{ id: string }>() const tema = useHookstate(TEMA) - const [title, setTitle] = useState("") - const [openModal, setOpenModal] = useState(false) + const [isModal, setModal] = useState(false) + const [data, setData] = useState({ + id: "", + title: "", + extension: "", + image: "", + }); + const openRef = useRef<() => void>(null) + const [img, setIMG] = useState() + const [imgForm, setImgForm] = useState() + const [loading, setLoading] = useState(false) const [touched, setTouched] = useState({ title: false, - }); + image: false + }) + function onValidation(kategori: string, val: any) { + if (kategori == 'title') { + setData({ ...data, title: val }) + if (val === "") { + setTouched({ ...touched, title: true }) + } else { + setTouched({ ...touched, title: false }) + } + } else if (kategori == 'image') { + if (imgForm) { + setTouched({ ...touched, image: false }) + } else { + setTouched({ ...touched, image: true }) + } + } + } + + + async function getOneData() { + try { + const res = await funGetOneBanner(param.id) + console.log(res) + setData(res.data) + setIMG(`https://wibu-storage.wibudev.com/api/files/${res.data.image}`) + } catch (error) { + console.error(error) + } + } + + async function onSubmit(val: boolean) { + try { + setLoading(true) + const fd = new FormData() + fd.append("file", imgForm) + fd.append("data", JSON.stringify( + { + id: data.id, + title: data.title, + image: data.image, + extension: data.extension + } + )) + + const res = await funEditBanner(param.id, fd) + + if (res.success) { + toast.success(res.message) + router.push('/banner') + } else { + toast.error(res.message) + } + } catch (error) { + toast.error("Error"); + } finally { + setLoading(false) + setModal(false) + } + } + + useShallowEffect(() => { + getOneData() + }, []) + return ( } /> @@ -25,41 +104,24 @@ function EditBanner(props: Partial ) { console.log('accepted files', files)} - onReject={(files) => console.log('rejected files', files)} - maxSize={5 * 1024 ** 2} - accept={IMAGE_MIME_TYPE} - {...props} + openRef={openRef} + onDrop={async (files) => { + if (!files || _.isEmpty(files)) + return toast.error("Tidak Ada Gambar Yang Dipilih") + setImgForm(files[0]) + const buffer = URL.createObjectURL(new Blob([new Uint8Array(await files[0].arrayBuffer())])) + setIMG(buffer) + onValidation('image', files[0]) + }} + activateOnClick={false} + maxSize={1 * 1024 ** 2} + accept={['image/png', 'image/jpeg', 'image/heic']} + onReject={(files) => { + return toast.error('File yang diizinkan: .png, .jpg, dan .heic dengan ukuran maksimal 1 MB') + }} + onClick={() => openRef.current?.()} > - - - - - - - - - - - - - - Upload File - - - File Tidak Boleh Melebihi 500mb - - - + @@ -67,20 +129,19 @@ function EditBanner(props: Partial ) { mt={10} label="Judul Banner" placeholder='Banner' + value={data.title} + onChange={(e) => { + setData({ ...data, title: e.target.value }) + onValidation('title', e.target.value) + }} styles={{ input: { - border: `1px solid ${"#D6D8F6"}`, + border: `1px solid ${touched.title ? 'red' : "#D6D8F6"}`, borderRadius: 10, }, }} required size='md' - value={title} - onChange={(e) => { - setTitle(e.currentTarget.value) - setTouched({...touched, title: false}) - }} - /> ) { - setOpenModal(false)} + setModal(false)} description="Apakah Anda yakin ingin mengedit banner ini?" onYes={(val) => { - - setOpenModal(false) + if (val) { + onSubmit(val) + } else { + setModal(false) + } }} /> @@ -112,4 +186,3 @@ function EditBanner(props: Partial ) { ); } -export default EditBanner; diff --git a/src/module/banner/ui/list_banner.tsx b/src/module/banner/ui/list_banner.tsx index 7251a54..4d8de51 100644 --- a/src/module/banner/ui/list_banner.tsx +++ b/src/module/banner/ui/list_banner.tsx @@ -13,7 +13,7 @@ import { funDeleteBanner, funGetAllBanner, funGetOneBanner } from '../lib/api_ba import { HiMagnifyingGlass } from 'react-icons/hi2'; function ListBanner() { - const [isList, setIsList] = useState (false) + const [isList, setIsList] = useState(false) const tema = useHookstate(TEMA) const router = useRouter(); const param = useParams<{ id: string }>() @@ -28,19 +28,18 @@ function ListBanner() { const [isPage, setPage] = useState(1) const [searchQuerry, setSearchQuerry] = useState('') // const { value: containerRef } = useHookstate(currentScroll); - + const handleList = () => { setIsList(!isList) } const fetchData = async (loading: boolean) => { - console.log('jallan') try { if (loading) setLoading(true) const response = await funGetAllBanner('?search=' + searchQuerry) if (response.success) { - setData(response.data) + setData(response.data.map((banner: { image: any; }) => ({ ...banner, image: banner.image }))); } else { toast.error(response.message) } @@ -57,8 +56,8 @@ function ListBanner() { setSearchQuerry(search) setPage(1) } - - + + useShallowEffect(() => { fetchData(true) }, [searchQuerry]) @@ -68,28 +67,28 @@ function ListBanner() { }, [isPage]) - async function onDelete() { + async function onDelete(id: string) { try { - const res = await funDeleteBanner(idData); + const res = await funDeleteBanner(id); if (res.success) { toast.success(res.message) - getOneData() + setData(isData.filter((banner) => banner.id !== id)); setIdData("") setIdDataStorage("") setOpenDrawer(false) } else { toast.error(res.message); - } - } catch (error) { - console.error(error); - toast.error("Gagal menghapus banner, coba lagi nanti"); } - + } catch (error) { + console.error(error); + toast.error("Gagal menghapus banner, coba lagi nanti"); } - - - + } + + + + return ( @@ -99,23 +98,28 @@ function ListBanner() { color: tema.get().utama, borderRadius: '#A3A3A3', borderColor: '#A3A3A3', - }, + }, }} size='md' radius={30} leftSection={} placeholder='pencarian' value={searchQuerry} - onChange={(val) => { searchBanner(val.target.value)}} + onChange={(val) => { searchBanner(val.target.value) }} /> - + - {isData.map((_, index) => ( - { setOpenDrawer(true) } + {isData.map((v, index) => ( + { + setIdData(v.id); + setIdDataStorage(v.image); + setExtension(v.extension); + setOpenDrawer(true) + } } style={{ width: '100%', @@ -127,11 +131,16 @@ function ListBanner() { }}> - + - Banner {index + 1} - Banner + {v.title} @@ -141,6 +150,7 @@ function ListBanner() { + setOpenDrawer(false)}> @@ -151,14 +161,15 @@ function ListBanner() { alignItems: "flex-start" }} > - router.push("/banner/edit/[id]")} direction="column" align="center" justify="center" pb={20}> - - - - - Edit - - + router.push(`/banner/edit/${idData}`)} direction="column" align="center" justify="center" pb={20}> + + + + + Edit + + + { setOpenModalView(true) }} direction={"column"} align={"center"} justify={"center"}> @@ -181,50 +192,46 @@ function ListBanner() { - setOpenModal(false)} + + setOpenModal(false)} description='Apakah Anda yakin ingin menghapus banner?' onYes={(val) => { if (val) { - onDelete() + onDelete(idData) } setOpenModal(false) }} /> - setOpenModalView(false)} file={idDataStorage} extension={isExtension} fitur='task' /> + setOpenModalView(false)} file={idDataStorage} extension={isExtension} fitur="image" /> ); } - export default ListBanner; +export default ListBanner; - function funGetBanner(arg0: string) { - throw new Error('Function not implemented.'); - } - function getOneData() { - throw new Error('Function not implemented.'); - } - - - - // useEffect(() => { - // const handleScroll = async () => { - // if (containerRef && containerRef.current) { - // const scrollTop = containerRef.current.scrollTop; - // const containerHeight = containerRef.current.clientHeight; - // const scrollHeight = containerRef.current.scrollHeight; - // if (scrollTop + containerHeight + 1 >= scrollHeight) { - // setPage(isPage + 1) - // } - // } - // }; - // const container = containerRef?.current; - // container?.addEventListener("scroll", handleScroll); +// useEffect(() => { +// const handleScroll = async () => { +// if (containerRef && containerRef.current) { +// const scrollTop = containerRef.current.scrollTop; +// const containerHeight = containerRef.current.clientHeight; +// const scrollHeight = containerRef.current.scrollHeight; + +// if (scrollTop + containerHeight + 1 >= scrollHeight) { +// setPage(isPage + 1) +// } +// } +// }; + +// const container = containerRef?.current; +// container?.addEventListener("scroll", handleScroll); + +// return () => { +// container?.removeEventListener("scroll", handleScroll); +// }; +// }, [containerRef, isPage]); - // return () => { - // container?.removeEventListener("scroll", handleScroll); - // }; - // }, [containerRef, isPage]); -