import { memo, useEffect, useState, } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; import type { ApiPasskey } from '../../../api/types'; import { IS_WEBAUTHN_SUPPORTED } from '../../../util/browser/windowEnvironment'; import buildClassName from '../../../util/buildClassName'; import { formatPastDatetime } from '../../../util/dates/dateFormat'; import { getNextArrowReplacement } from '../../../util/localization/format'; import { LOCAL_TGS_PREVIEW_URLS, LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets'; import { REM } from '../../common/helpers/mediaDimensions'; import useHistoryBack from '../../../hooks/useHistoryBack'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview'; import CustomEmoji from '../../common/CustomEmoji'; import Icon from '../../common/icons/Icon'; import Button from '../../ui/Button'; import ConfirmDialog from '../../ui/ConfirmDialog'; import Link from '../../ui/Link'; import ListItem from '../../ui/ListItem'; import styles from './SettingsPasskeys.module.scss'; type OwnProps = { isActive?: boolean; onReset: () => void; }; type StateProps = { passkeys?: ApiPasskey[]; maxPasskeysCount: number; }; const TOP_STICKER_SIZE = 120; const ICON_SIZE = 2 * REM; const SettingsPasskeys = ({ isActive, passkeys, maxPasskeysCount, onReset, }: OwnProps & StateProps) => { const { startPasskeyRegistration, deletePasskey, openPasskeyModal, } = getActions(); const lang = useLang(); const [deleteModalId, setDeleteModalId] = useState(); const canAddPasskey = IS_WEBAUTHN_SUPPORTED && (passkeys?.length ?? 0) < maxPasskeysCount; const handleCreatePasskey = useLastCallback(() => { startPasskeyRegistration(); }); const handleOpenPasskeyModal = useLastCallback(() => { openPasskeyModal(); }); const confirmDeletePasskey = useLastCallback(() => { if (!deleteModalId) return; deletePasskey({ id: deleteModalId }); setDeleteModalId(undefined); }); useEffect(() => { if (!passkeys || passkeys.length || !isActive) return; onReset(); // Autoclose when last passkey is deleted }, [passkeys, onReset, isActive]); useHistoryBack({ isActive, onBack: onReset, }); function renderPasskey(passkey: ApiPasskey) { const { softwareEmojiId, id, name, date, lastUsageDate } = passkey; return ( { setDeleteModalId(id); }, }]} leftElement={softwareEmojiId ? ( ) : ( )} >
{formatPastDatetime(lang, date)} {name || lang('SettingsPasskeyFallbackTitle')} {Boolean(lastUsageDate) && ( {lang('SettingsPasskeyUsedAt', { date: formatPastDatetime(lang, lastUsageDate), })} )}
); } return (

{lang('SettingsPasskeyInfo')}

{passkeys?.map(renderPasskey)} {canAddPasskey && ( )}

{lang('SettingsPasskeysFooter', { link: ( {lang('SettingsPasskeysFooterLink', undefined, { withNodes: true, specialReplacement: getNextArrowReplacement() })} ), }, { withNodes: true })}

setDeleteModalId(undefined)} />
); }; export default memo(withGlobal( (global): Complete => { return { passkeys: global.settings.passkeys, maxPasskeysCount: global.appConfig.passkeysMaxCount, }; }, )(SettingsPasskeys));