TelegramPWA/src/components/left/settings/SettingsPrivacyActiveSessions.tsx
2021-06-19 00:25:27 +03:00

153 lines
4.8 KiB
TypeScript

import React, {
FC, memo, useCallback, useEffect, useMemo,
} from '../../../lib/teact/teact';
import { withGlobal } from '../../../lib/teact/teactn';
import { GlobalActions } from '../../../global/types';
import { ApiSession } from '../../../api/types';
import { pick } from '../../../util/iteratees';
import { formatPastTimeShort } from '../../../util/dateFormat';
import useFlag from '../../../hooks/useFlag';
import useLang from '../../../hooks/useLang';
import ListItem from '../../ui/ListItem';
import ConfirmDialog from '../../ui/ConfirmDialog';
type StateProps = {
activeSessions: ApiSession[];
};
type DispatchProps = Pick<GlobalActions, (
'loadAuthorizations' | 'terminateAuthorization' | 'terminateAllAuthorizations'
)>;
const SettingsPrivacyActiveSessions: FC<StateProps & DispatchProps> = ({
activeSessions,
loadAuthorizations,
terminateAuthorization,
terminateAllAuthorizations,
}) => {
const [isConfirmTerminateAllDialogOpen, openConfirmTerminateAllDialog, closeConfirmTerminateAllDialog] = useFlag();
useEffect(() => {
loadAuthorizations();
}, [loadAuthorizations]);
const handleTerminateSessionClick = useCallback((hash: string) => {
terminateAuthorization({ hash });
}, [terminateAuthorization]);
const handleTerminateAllSessions = useCallback(() => {
closeConfirmTerminateAllDialog();
terminateAllAuthorizations();
}, [closeConfirmTerminateAllDialog, terminateAllAuthorizations]);
const currentSession = useMemo(() => {
return activeSessions.find((session) => session.isCurrent);
}, [activeSessions]);
const otherSessions = useMemo(() => {
return activeSessions.filter((session) => !session.isCurrent);
}, [activeSessions]);
const lang = useLang();
function renderCurrentSession(session: ApiSession) {
return (
<div className="settings-item">
<h4 className="settings-item-header mb-4" dir={lang.isRtl ? 'rtl' : undefined}>
{lang('AuthSessions.CurrentSession')}
</h4>
<ListItem narrow inactive>
<div className="multiline-menu-item" dir="auto">
<span className="title" dir="auto">{session.appName}</span>
<span className="subtitle black tight">{getDeviceEnvironment(session)}</span>
<span className="subtitle">{session.ip} - {getLocation(session)}</span>
</div>
</ListItem>
<ListItem
className="destructive mb-0"
icon="stop"
ripple
narrow
onClick={openConfirmTerminateAllDialog}
>
{lang('TerminateAllSessions')}
</ListItem>
</div>
);
}
function renderOtherSessions(sessions: ApiSession[]) {
return (
<div className="settings-item">
<h4 className="settings-item-header mb-4" dir={lang.isRtl ? 'rtl' : undefined}>Other Sessions</h4>
{sessions.map(renderSession)}
</div>
);
}
function renderSession(session: ApiSession) {
return (
<ListItem
key={session.hash}
ripple
narrow
contextActions={[{
title: 'Terminate',
icon: 'stop',
handler: () => {
handleTerminateSessionClick(session.hash);
},
}]}
>
<div className="multiline-menu-item full-size" dir="auto">
<span className="date">{formatPastTimeShort(lang, session.dateActive * 1000)}</span>
<span className="title">{session.appName}</span>
<span className="subtitle black tight">{getDeviceEnvironment(session)}</span>
<span className="subtitle">{session.ip} - {getLocation(session)}</span>
</div>
</ListItem>
);
}
return (
<div className="settings-content custom-scroll">
{currentSession && renderCurrentSession(currentSession)}
{otherSessions && renderOtherSessions(otherSessions)}
{otherSessions && (
<ConfirmDialog
isOpen={isConfirmTerminateAllDialogOpen}
onClose={closeConfirmTerminateAllDialog}
text="Are you sure you want to terminate all other sessions?"
confirmLabel="Terminate All Other Sessions"
confirmHandler={handleTerminateAllSessions}
confirmIsDestructive
/>
)}
</div>
);
};
function getLocation(session: ApiSession) {
return [session.region, session.country].filter(Boolean).join(', ');
}
function getDeviceEnvironment(session: ApiSession) {
return `${session.deviceModel}${session.deviceModel ? ', ' : ''} ${session.platform} ${session.systemVersion}`;
}
export default memo(withGlobal(
(global): StateProps => {
return {
activeSessions: global.activeSessions,
};
},
(setGlobal, actions): DispatchProps => pick(actions, [
'loadAuthorizations', 'terminateAuthorization', 'terminateAllAuthorizations',
]),
)(SettingsPrivacyActiveSessions));