/* eslint-disable @typescript-eslint/no-shadow */ /* eslint-disable react/destructuring-assignment */ /* eslint-disable react/jsx-props-no-spreading */ /* * Copyright (C) Contributors to the Suwayomi project * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import React, { useState, useContext, useEffect } from 'react'; import { List, ListItem, ListItemText, ListItemIcon, IconButton, } from '@mui/material'; import { DragDropContext, Droppable, Draggable, DropResult, DraggingStyle, NotDraggingStyle, } from 'react-beautiful-dnd'; import DragHandleIcon from '@mui/icons-material/DragHandle'; import EditIcon from '@mui/icons-material/Edit'; import { useTheme, Palette } from '@mui/material/styles'; import Fab from '@mui/material/Fab'; import AddIcon from '@mui/icons-material/Add'; import DeleteIcon from '@mui/icons-material/Delete'; import Button from '@mui/material/Button'; import TextField from '@mui/material/TextField'; import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogTitle from '@mui/material/DialogTitle'; import Checkbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; import NavbarContext from 'context/NavbarContext'; import client from 'util/client'; const getItemStyle = (isDragging: boolean, draggableStyle: DraggingStyle | NotDraggingStyle | undefined, palette: Palette) => ({ // styles we need to apply on draggables ...draggableStyle, ...(isDragging && { background: palette.mode === 'dark' ? '#424242' : 'rgb(235,235,235)', }), }); export default function Categories() { const { setTitle, setAction } = useContext(NavbarContext); useEffect(() => { setTitle('Categories'); setAction(<>); }, []); const [categories, setCategories] = useState([]); const [categoryToEdit, setCategoryToEdit] = useState(-1); // -1 means new category const [dialogOpen, setDialogOpen] = useState(false); const [dialogName, setDialogName] = useState(''); const [dialogDefault, setDialogDefault] = useState(false); const theme = useTheme(); const [updateTriggerHolder, setUpdateTriggerHolder] = useState(0); // just a hack const triggerUpdate = () => setUpdateTriggerHolder(updateTriggerHolder + 1); // just a hack useEffect(() => { if (!dialogOpen) { client.get('/api/v1/category/') .then((response) => response.data) .then((data) => { if (data.length > 0 && data[0].name === 'Default') data.shift(); return data; }) .then((data) => setCategories(data)); } }, [updateTriggerHolder]); const categoryReorder = (list: ICategory[], from: number, to: number) => { const formData = new FormData(); formData.append('from', `${from + 1}`); formData.append('to', `${to + 1}`); client.patch('/api/v1/category/reorder', formData) .finally(() => triggerUpdate()); // also move it in local state to avoid jarring moving behviour... const result = Array.from(list); const [removed] = result.splice(from, 1); result.splice(to, 0, removed); return result; }; const onDragEnd = (result: DropResult) => { // dropped outside the list? if (!result.destination) { return; } setCategories(categoryReorder( categories, result.source.index, result.destination.index, )); }; const resetDialog = () => { setDialogName(''); setDialogDefault(false); setCategoryToEdit(-1); }; const handleDialogOpen = () => { resetDialog(); setDialogOpen(true); }; const handleEditDialogOpen = (index:number) => { setDialogName(categories[index].name); setDialogDefault(categories[index].default); setCategoryToEdit(index); setDialogOpen(true); }; const handleDialogCancel = () => { setDialogOpen(false); }; const handleDialogSubmit = () => { setDialogOpen(false); const formData = new FormData(); formData.append('name', dialogName); formData.append('default', dialogDefault.toString()); if (categoryToEdit === -1) { client.post('/api/v1/category/', formData) .finally(() => triggerUpdate()); } else { const category = categories[categoryToEdit]; client.patch(`/api/v1/category/${category.id}`, formData) .finally(() => triggerUpdate()); } }; const deleteCategory = (index:number) => { const category = categories[index]; client.delete(`/api/v1/category/${category.id}`) .finally(() => triggerUpdate()); }; return ( <> {(provided) => ( {categories.map((item, index) => ( {(provided, snapshot) => ( { handleEditDialogOpen(index); }} size="large" > { deleteCategory(index); }} size="large" > )} ))} {provided.placeholder} )} {categoryToEdit === -1 ? 'New Catalog' : 'Edit Catalog'} setDialogName(e.target.value)} /> setDialogDefault(e.target.checked)} color="default" /> )} label="Default category when adding new manga to library" /> ); }