stremio-web/src/routes/Settings/General/General.tsx
2025-06-18 09:48:12 +02:00

182 lines
6.2 KiB
TypeScript

import React, { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, MultiselectMenu, Toggle } from 'stremio/components';
import { useServices } from 'stremio/services';
import { usePlatform, useToast } from 'stremio/common';
import { Section, Option, Link } from '../components';
import User from './User';
import useDataExport from './useDataExport';
import styles from './General.less';
import useGeneralOptions from './useGeneralOptions';
type Props = {
profile: Profile,
};
const General = forwardRef<HTMLDivElement, Props>(({ profile }: Props, ref) => {
const { t } = useTranslation();
const { core, shell } = useServices();
const platform = usePlatform();
const toast = useToast();
const [dataExport, loadDataExport] = useDataExport();
const {
interfaceLanguageSelect,
quitOnCloseToggle,
escExitFullscreenToggle,
hideSpoilersToggle,
} = useGeneralOptions(profile);
const [traktAuthStarted, setTraktAuthStarted] = useState(false);
const isTraktAuthenticated = useMemo(() => {
const trakt = profile?.auth?.user?.trakt;
return trakt && (Date.now() / 1000) < (trakt.created_at + trakt.expires_in);
}, [profile.auth]);
const onExportData = useCallback(() => {
loadDataExport();
}, []);
const onCalendarSubscribe = useCallback(() => {
if (!profile.auth) return;
const protocol = platform.name === 'ios' ? 'webcal' : 'https';
const url = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`;
platform.openExternal(url);
toast.show({
type: 'success',
title: platform.name === 'ios' ?
t('SETTINGS_SUBSCRIBE_CALENDAR_IOS_TOAST') :
t('SETTINGS_SUBSCRIBE_CALENDAR_TOAST'),
timeout: 25000
});
// Stremio 4 emits not documented event subscribeCalendar
}, [profile.auth]);
const onToggleTrakt = useCallback(() => {
if (!isTraktAuthenticated && profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user._id === 'string') {
platform.openExternal(`https://www.strem.io/trakt/auth/${profile.auth.user._id}`);
setTraktAuthStarted(true);
} else {
core.transport.dispatch({
action: 'Ctx',
args: {
action: 'LogoutTrakt'
}
});
}
}, [isTraktAuthenticated, profile.auth]);
useEffect(() => {
if (dataExport.exportUrl) {
platform.openExternal(dataExport.exportUrl);
}
}, [dataExport.exportUrl]);
useEffect(() => {
if (isTraktAuthenticated && traktAuthStarted) {
core.transport.dispatch({
action: 'Ctx',
args: {
action: 'InstallTraktAddon'
}
});
setTraktAuthStarted(false);
}
}, [isTraktAuthenticated, traktAuthStarted]);
return <>
<Section ref={ref}>
<User profile={profile} />
</Section>
<Section>
{
profile?.auth?.user &&
<Link
label={t('SETTINGS_DATA_EXPORT')}
onClick={onExportData}
/>
}
{
profile?.auth?.user &&
<Link
label={t('SETTINGS_SUBSCRIBE_CALENDAR')}
onClick={onCalendarSubscribe}
/>
}
<Link
label={t('SETTINGS_SUPPORT')}
href={'https://stremio.zendesk.com/hc/en-us'}
/>
<Link
label={'Source Code'}
href={`https://github.com/stremio/stremio-web/tree/${process.env.COMMIT_HASH}`}
/>
<Link
label={t('TERMS_OF_SERVICE')}
href={'https://www.stremio.com/tos'}
/>
<Link
label={t('PRIVACY_POLICY')}
href={'https://www.stremio.com/privacy'}
/>
{
profile?.auth?.user &&
<Link
label={t('SETTINGS_ACC_DELETE')}
href={'https://stremio.zendesk.com/hc/en-us/articles/360021428911-How-to-delete-my-account'}
/>
}
{
profile?.auth?.user?.email &&
<Link
label={t('SETTINGS_CHANGE_PASSWORD')}
href={`https://www.strem.io/reset-password/${profile.auth.user.email}`}
/>
}
<Option className={styles['trakt-container']} icon={'trakt'} label={'Trakt Scrobbling'}>
<Button className={'button'} title={'Authenticate'} disabled={profile.auth === null} tabIndex={-1} onClick={onToggleTrakt}>
{isTraktAuthenticated ? t('LOG_OUT') : t('SETTINGS_TRAKT_AUTHENTICATE')}
</Button>
</Option>
</Section>
<Section>
<Option label={'SETTINGS_UI_LANGUAGE'}>
<MultiselectMenu
className={'multiselect'}
{...interfaceLanguageSelect}
/>
</Option>
{
shell.active &&
<Option label={'SETTINGS_QUIT_ON_CLOSE'}>
<Toggle
tabIndex={-1}
{...quitOnCloseToggle}
/>
</Option>
}
{
shell.active &&
<Option label={'SETTINGS_FULLSCREEN_EXIT'}>
<Toggle
tabIndex={-1}
{...escExitFullscreenToggle}
/>
</Option>
}
<Option label={'SETTINGS_BLUR_UNWATCHED_IMAGE'}>
<Toggle
tabIndex={-1}
{...hideSpoilersToggle}
/>
</Option>
</Section>
</>;
});
export default General;