import { SNApplication, SessionStrings, UuidString, SessionListEntry, isErrorResponse, getErrorFromErrorResponse, } from '@standardnotes/snjs' import { FunctionComponent, useState, useEffect, useRef, useMemo } from 'react' import { WebApplication } from '@/Application/WebApplication' import { observer } from 'mobx-react-lite' import Spinner from '@/Components/Spinner/Spinner' import Button from '@/Components/Button/Button' import Icon from '../Icon/Icon' import Modal, { ModalAction } from '../Modal/Modal' import ModalOverlay from '../Modal/ModalOverlay' import AlertDialog from '../AlertDialog/AlertDialog' type Session = SessionListEntry & { revoking?: true } function useSessions( application: SNApplication, ): [Session[], () => void, boolean, (uuid: UuidString) => Promise, string] { const [sessions, setSessions] = useState([]) const [lastRefreshDate, setLastRefreshDate] = useState(Date.now()) const [refreshing, setRefreshing] = useState(true) const [errorMessage, setErrorMessage] = useState('') useEffect(() => { ;(async () => { setRefreshing(true) const response = await application.getSessions() if (isErrorResponse(response)) { if (response.data?.error?.message) { setErrorMessage(response.data?.error.message) } else { setErrorMessage('An unknown error occured while loading sessions.') } } else { const sessions = response.data as SessionListEntry[] setSessions(sessions) setErrorMessage('') } setRefreshing(false) })().catch(console.error) }, [application, lastRefreshDate]) function refresh() { setLastRefreshDate(Date.now()) } async function revokeSession(uuid: UuidString) { const sessionsBeforeRevoke = sessions const responsePromise = application.revokeSession(uuid) const sessionsDuringRevoke = sessions.slice() const toRemoveIndex = sessions.findIndex((session) => session.uuid === uuid) sessionsDuringRevoke[toRemoveIndex] = { ...sessionsDuringRevoke[toRemoveIndex], revoking: true, } setSessions(sessionsDuringRevoke) const response = await responsePromise if (!response) { setSessions(sessionsBeforeRevoke) } else if (isErrorResponse(response)) { setErrorMessage( getErrorFromErrorResponse(response).message || 'An unknown error occured while revoking the session.', ) setSessions(sessionsBeforeRevoke) } else { setSessions(sessions.filter((session) => session.uuid !== uuid)) } } return [sessions, refresh, refreshing, revokeSession, errorMessage] } const SessionsModalContent: FunctionComponent<{ application: WebApplication }> = ({ application }) => { const [sessions, refresh, refreshing, revokeSession, errorMessage] = useSessions(application) const [confirmRevokingSessionUuid, setRevokingSessionUuid] = useState('') const closeRevokeSessionAlert = () => setRevokingSessionUuid('') const cancelRevokeRef = useRef(null) const formatter = useMemo( () => new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long', hour: 'numeric', minute: 'numeric', }), [], ) const closeRevokeConfirmationDialog = () => { setRevokingSessionUuid('') } const sessionModalActions = useMemo( (): ModalAction[] => [ { label: 'Close', onClick: application.closeSessionsModal, type: 'cancel', mobileSlot: 'left', }, { label: 'Refresh', onClick: refresh, type: 'primary', mobileSlot: 'right', }, ], [refresh, application.closeSessionsModal], ) return ( <>
{refreshing ? (

Loading sessions

) : ( <> {errorMessage && (
{errorMessage}
)} {sessions.length > 0 && (
    {sessions.map((session) => (
  • {session.device_info}

    {session.current ? ( Current session ) : ( <>

    Signed in on {formatter.format(new Date(session.created_at))}

    )}
  • ))}
)} )}
{confirmRevokingSessionUuid && (
{SessionStrings.RevokeTitle}

{SessionStrings.RevokeText}

)} ) } const SessionsModal: FunctionComponent<{ application: WebApplication }> = ({ application }) => { return ( ) } export default observer(SessionsModal)