/* * 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 Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; import Avatar from '@mui/material/Avatar'; import { useTranslation } from 'react-i18next'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; 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 Divider from '@mui/material/Divider'; import FormGroup from '@mui/material/FormGroup'; import IconButton from '@mui/material/IconButton'; import Link from '@mui/material/Link'; import ListItemButton from '@mui/material/ListItemButton'; import MenuItem from '@mui/material/MenuItem'; import Stack from '@mui/material/Stack'; import Tooltip from '@mui/material/Tooltip'; import Typography from '@mui/material/Typography'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import PopupState, { bindDialog, bindMenu, bindTrigger } from 'material-ui-popup-state'; import { useMemo, useState } from 'react'; import { requestManager } from '@/lib/requests/requests/RequestManager.ts'; import { Trackers, TTrackerBind, TTrackRecordBind, UNSET_DATE } from '@/modules/tracker/services/Trackers.ts'; import { ListPreference } from '@/modules/source/components/sourceConfiguration/ListPreference.tsx'; import { NumberSetting } from '@/modules/core/components/settings/NumberSetting.tsx'; import { DateSetting } from '@/modules/core/components/settings/DateSetting.tsx'; import { makeToast } from '@/modules/core/utils/Toast.ts'; import { Menu } from '@/modules/core/components/menu/Menu.tsx'; import { CARD_STYLING } from '@/modules/tracker/Tracker.constants.ts'; import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines.tsx'; import { SelectSetting, SelectSettingValue } from '@/modules/core/components/settings/SelectSetting.tsx'; import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.tsx'; import { TrackRecordType } from '@/lib/graphql/generated/graphql.ts'; const TrackerActiveLink = ({ children, url }: { children: React.ReactNode; url: string }) => ( {children} ); type TTrackerActive = Pick; type TTrackRecordActive = Pick; const TrackerActiveRemoveBind = ({ trackerRecordId, tracker, onClick, onClose, }: { trackerRecordId: TrackRecordType['id']; tracker: TTrackerActive; onClick: () => void; onClose: () => void; }) => { const { t } = useTranslation(); const [removeRemoteTracking, setRemoveRemoteTracking] = useState(false); const removeBind = () => { onClose(); requestManager .unbindTracker(trackerRecordId, removeRemoteTracking) .response.then(() => makeToast(t('manga.action.track.remove.label.success'), 'success')) .catch(() => makeToast(t('manga.action.track.remove.label.error'), 'error')); }; return ( {(popupState) => ( <> { onClick(); popupState.open(); }} onTouchStart={() => { onClick(); popupState.open(); }} > {t('global.button.remove')} { onClose(); popupState.close(); }} > {t('manga.action.track.remove.dialog.label.title', { tracker: tracker.name })} {t('manga.action.track.remove.dialog.label.description')} {tracker.supportsTrackDeletion && ( setRemoveRemoteTracking(checked)} /> )} )} ); }; const TrackerActiveHeader = ({ trackRecord, tracker, openSearch, }: { trackRecord: TTrackRecordActive; tracker: TTrackerActive; openSearch: () => void; }) => { const { t } = useTranslation(); return ( {trackRecord.title} {(popupState) => ( <> {(onClose, setHideMenu) => [ onClose()}> {t('global.label.open_in_browser')} , setHideMenu(true)} onClose={onClose} />, ]} )} ); }; const TrackerActiveCardInfoRow = ({ children }: { children: React.ReactNode }) => ( {children} ); const isUnsetScore = (score: string | number): boolean => !Math.trunc(Number(score)); export const TrackerActiveCard = ({ trackRecord, tracker, onClick, }: { trackRecord: TTrackRecordBind; tracker: TTrackerBind; onClick: () => void; }) => { const { t } = useTranslation(); const isScoreUnset = isUnsetScore(trackRecord.displayScore); const currentScore = isScoreUnset ? tracker.scores[0] : trackRecord.displayScore; const selectSettingValues = useMemo( () => tracker.scores.map( (score) => [score, { text: isUnsetScore(score) ? '-' : score }] satisfies SelectSettingValue< TTrackerBind['scores'][number] >, ), [tracker.scores], ); const updateTrackerBind = (patch: Parameters[1]) => { requestManager .updateTrackerBind(trackRecord.id, patch) .response.catch(() => makeToast(t('global.error.label.failed_to_save_changes'), 'error')); }; return ( status.name)} key="status" type="ListPreference" entryValues={tracker.statuses.map((status) => `${status.value}`)} ListPreferenceCurrentValue={`${trackRecord.status}`} updateValue={(_, status) => updateTrackerBind({ status: status as unknown as number }) } summary="%s" /> updateTrackerBind({ lastChapterRead })} /> settingName={t('tracking.track_record.label.score')} value={currentScore} values={selectSettingValues} handleChange={(score) => updateTrackerBind({ scoreString: score })} /> updateTrackerBind({ startDate: startDate ?? UNSET_DATE }) } /> updateTrackerBind({ finishDate: finishDate ?? UNSET_DATE }) } /> ); };