summaryrefslogtreecommitdiff
path: root/frontend/src/components/modals/MultiplePluginsInstallModal.tsx
blob: bfbff08c1647ac9892ec026855e2d287861dd0a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import { ConfirmModal, Navigation, QuickAccessTab } from 'decky-frontend-lib';
import { FC, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { InstallType } from '../../plugin';

interface MultiplePluginsInstallModalProps {
  requests: { name: string; version: string; hash: string; install_type: InstallType }[];
  onOK(): void | Promise<void>;
  onCancel(): void | Promise<void>;
  closeModal?(): void;
}

// values are the JSON keys used in the translation file
const InstallTypeTranslationMapping = {
  [InstallType.INSTALL]: 'install',
  [InstallType.REINSTALL]: 'reinstall',
  [InstallType.UPDATE]: 'update',
} as const satisfies Record<InstallType, string>;

type TitleTranslationMapping = 'mixed' | (typeof InstallTypeTranslationMapping)[InstallType];

const MultiplePluginsInstallModal: FC<MultiplePluginsInstallModalProps> = ({
  requests,
  onOK,
  onCancel,
  closeModal,
}) => {
  const [loading, setLoading] = useState<boolean>(false);
  const { t } = useTranslation();

  // used as part of the title translation
  // if we know all operations are of a specific type, we can show so in the title to make decision easier
  const installTypeGrouped = useMemo((): TitleTranslationMapping => {
    if (requests.every(({ install_type }) => install_type === InstallType.INSTALL)) return 'install';
    if (requests.every(({ install_type }) => install_type === InstallType.REINSTALL)) return 'reinstall';
    if (requests.every(({ install_type }) => install_type === InstallType.UPDATE)) return 'update';
    return 'mixed';
  }, [requests]);

  return (
    <ConfirmModal
      bOKDisabled={loading}
      closeModal={closeModal}
      onOK={async () => {
        setLoading(true);
        await onOK();
        setTimeout(() => Navigation.OpenQuickAccessMenu(QuickAccessTab.Decky), 250);
        setTimeout(() => DeckyPluginLoader.checkPluginUpdates(), 1000);
      }}
      onCancel={async () => {
        await onCancel();
      }}
      strTitle={<div>{t(`MultiplePluginsInstallModal.title.${installTypeGrouped}`, { count: requests.length })}</div>}
      strOKButtonText={t(`MultiplePluginsInstallModal.ok_button.${loading ? 'loading' : 'idle'}`)}
    >
      <div>
        {t('MultiplePluginsInstallModal.confirm')}
        <ul style={{ listStyle: 'none', display: 'flex', flexDirection: 'column', gap: '4px' }}>
          {requests.map(({ name, version, install_type, hash }, i) => {
            const installTypeStr = InstallTypeTranslationMapping[install_type];
            const description = t(`MultiplePluginsInstallModal.description.${installTypeStr}`, {
              name,
              version,
            });

            return (
              <li key={i} style={{ display: 'flex', flexDirection: 'column' }}>
                <div>{description}</div>
                {hash === 'False' && (
                  <div style={{ color: 'red', paddingLeft: '10px' }}>{t('PluginInstallModal.no_hash')}</div>
                )}
              </li>
            );
          })}
        </ul>
      </div>
    </ConfirmModal>
  );
};

export default MultiplePluginsInstallModal;