/* * 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 { useContext, useLayoutEffect, useMemo, useState } from 'react'; import { DragDropContext, Draggable, DropResult } from 'react-beautiful-dnd'; import { useTheme } from '@mui/material/styles'; import Fab from '@mui/material/Fab'; import AddIcon from '@mui/icons-material/Add'; 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 { useTranslation } from 'react-i18next'; import Box from '@mui/material/Box'; import { requestManager } from '@/lib/requests/requests/RequestManager.ts'; import { StrictModeDroppable } from '@/modules/core/components/StrictModeDroppable.tsx'; import { DEFAULT_FULL_FAB_HEIGHT } from '@/modules/core/components/buttons/StyledFab.tsx'; import { NavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx'; import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables } from '@/lib/graphql/generated/graphql.ts'; import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts'; import { CategorySettingsCard } from '@/modules/category/components/CategorySettingsCard.tsx'; import { CategoryIdInfo } from '@/modules/category/Category.types.ts'; export function CategorySettings() { const { t } = useTranslation(); const { setTitle, setAction } = useContext(NavBarContext); useLayoutEffect(() => { setTitle(t('category.title.category_other')); setAction(null); return () => { setTitle(''); setAction(null); }; }, [t]); const { data, loading, error, refetch } = requestManager.useGetCategories< GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables >(GET_CATEGORIES_SETTINGS, { notifyOnNetworkStatusChange: true }); const categories = useMemo(() => { const res = [...(data?.categories.nodes ?? [])]; if (res.length > 0 && res[0].name === 'Default') { res.shift(); } return res; }, [data]); const [categoryToEdit, setCategoryToEdit] = useState(-1); // -1 means new category const [dialogOpen, setDialogOpen] = useState(false); const [dialogName, setDialogName] = useState(''); const [dialogDefault, setDialogDefault] = useState(false); const [reorderCategory, { reset: revertReorder }] = requestManager.useReorderCategory(); const theme = useTheme(); const categoryReorder = (list: CategoryIdInfo[], from: number, to: number) => { const reorderedCategory = list[from]; reorderCategory({ variables: { input: { id: reorderedCategory.id, position: to + 1 } } }).catch(() => revertReorder(), ); }; const onDragEnd = (result: DropResult) => { // dropped outside the list? if (!result.destination) { return; } 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); if (categoryToEdit === -1) { requestManager.createCategory({ name: dialogName, default: dialogDefault }); } else { const category = categories[categoryToEdit]; requestManager.updateCategory(category.id, { name: dialogName, default: dialogDefault }); } }; if (loading) { return ; } if (error) { return ( refetch().catch(defaultPromiseErrorHandler('CategorySettings::refetch'))} /> ); } return ( <> {(droppableProvided) => ( {categories.map((category, index) => ( {(draggableProvided) => ( handleEditDialogOpen(index)} /> )} ))} {droppableProvided.placeholder} )} {categoryToEdit === -1 ? t('category.dialog.title.new_category') : t('category.dialog.title.edit_category')} setDialogName(e.target.value)} /> setDialogDefault(e.target.checked)} /> } label={t('category.label.use_as_default_category')} /> ); }