/* * 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 { useEffect, useState } from 'react'; import Card from '@mui/material/Card'; import Button from '@mui/material/Button'; import Typography from '@mui/material/Typography'; import { useTranslation } from 'react-i18next'; import IconButton from '@mui/material/IconButton'; import SettingsIcon from '@mui/icons-material/Settings'; import Stack from '@mui/material/Stack'; import { Link } from 'react-router-dom'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { ExtensionAction, ExtensionState, InstalledState, InstalledStates, TExtension, } from '@/modules/extension/Extensions.types.ts'; import { EXTENSION_ACTION_TO_NEXT_ACTION_MAP, EXTENSION_ACTION_TO_STATE_MAP, INSTALLED_STATE_TO_TRANSLATION_KEY_MAP, } from '@/modules/extension/Extensions.constants.ts'; import { getInstalledState, updateExtension } from '@/modules/extension/Extensions.utils.ts'; import { CustomTooltip } from '@/modules/core/components/CustomTooltip'; import { ListCardAvatar } from '@/modules/core/components/lists/cards/ListCardAvatar.tsx'; import { ListCardContent } from '@/modules/core/components/lists/cards/ListCardContent.tsx'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { MUIUtil } from '@/lib/mui/MUI.util.ts'; import { OptionalCardActionAreaLink } from '@/modules/core/components/lists/cards/OptionalCardActionAreaLink.tsx'; import { languageCodeToName } from '@/modules/core/utils/Languages.ts'; interface IProps { extension: TExtension; handleUpdate: () => void; showSourceRepo: boolean; forcedState?: ExtensionState; } export function ExtensionCard(props: IProps) { const { t } = useTranslation(); const { extension: { name, lang, versionName, isInstalled, hasUpdate, isObsolete, pkgName, iconUrl, isNsfw, repo }, handleUpdate, showSourceRepo, forcedState, } = props; const [localInstalledState, setInstalledState] = useState( getInstalledState(isInstalled, isObsolete, hasUpdate), ); const installedState = forcedState ?? localInstalledState; useEffect(() => { setInstalledState(getInstalledState(isInstalled, isObsolete, hasUpdate)); }, [getInstalledState(isInstalled, isObsolete, hasUpdate)]); const requestExtensionAction = async (action: ExtensionAction): Promise => { const nextAction = EXTENSION_ACTION_TO_NEXT_ACTION_MAP[action]; const state = EXTENSION_ACTION_TO_STATE_MAP[action]; try { setInstalledState(state); await updateExtension(pkgName, isObsolete, action); setInstalledState(nextAction); handleUpdate(); } catch (_) { setInstalledState(getInstalledState(isInstalled, isObsolete, hasUpdate)); } }; function handleButtonClick() { switch (installedState) { case ExtensionAction.INSTALL: case ExtensionAction.UPDATE: case ExtensionAction.UNINSTALL: requestExtensionAction(installedState).catch( defaultPromiseErrorHandler(`ExtensionCard:handleButtonClick(${installedState})`), ); break; case ExtensionState.OBSOLETE: requestExtensionAction(ExtensionAction.UNINSTALL).catch( defaultPromiseErrorHandler(`ExtensionCard:handleButtonClick(${installedState})`), ); break; default: break; } } return ( {name} {isInstalled ? `${languageCodeToName(lang)} ` : ''} {versionName} {isNsfw && ( {' 18+'} )} {showSourceRepo && {repo}} {isInstalled && ( )} ); }