From 24e9a1529df273968cd1f4443afe490dcc07c424 Mon Sep 17 00:00:00 2001 From: Hampus Kraft Date: Sat, 21 Feb 2026 01:32:04 +0000 Subject: [PATCH] fix: various fixes to sentry-reported errors --- .../ChannelDetailsBottomSheet.tsx | 2 +- .../components/channel/ChannelIndexPage.tsx | 16 ++++-- .../src/components/channel/ChannelMembers.tsx | 2 +- .../components/channel/MessageActionUtils.tsx | 8 ++- .../channel/direct_message/DMList.tsx | 2 +- .../message_search_bar/MessageSearchBar.tsx | 4 +- .../utils/ChannelMoveOperation.test.tsx | 35 ++++++++++++ .../components/modals/BackupCodesModal.tsx | 8 +-- .../modals/BackupCodesRegenerateModal.tsx | 11 +++- .../modals/BackupCodesViewModal.tsx | 9 ++- .../components/modals/EmailChangeModal.tsx | 9 ++- .../modals/FluxerTagChangeModal.tsx | 11 ++-- .../src/components/modals/ForwardModal.tsx | 23 +++++--- .../components/modals/MfaTotpEnableModal.tsx | 11 ++-- .../components/modals/MobileVideoViewer.tsx | 34 ++++++----- .../components/modals/tabs/MyProfileTab.tsx | 2 +- .../tabs/account_security_tab/AccountTab.tsx | 5 +- .../tabs/account_security_tab/SecurityTab.tsx | 7 ++- .../tabs/my_profile_tab/UsernameSection.tsx | 9 +-- .../src/components/search/UserFilterSheet.tsx | 2 +- fluxer_app/src/index.tsx | 8 +++ .../repositories/GuildRoleRepository.tsx | 2 +- .../repositories/IGuildRoleRepository.tsx | 2 +- .../src/guild/services/GuildRoleService.tsx | 32 +++++++---- .../guild/services/channel/ChannelHelpers.tsx | 4 ++ .../channel/ChannelOperationsService.tsx | 9 ++- .../tests/GuildChannelPositions.test.tsx | 56 +++++++++++++++++++ .../guild/tests/GuildRoleOperations.test.tsx | 41 ++++++++++++++ .../api/src/worker/WorkerDependencies.tsx | 1 + 29 files changed, 290 insertions(+), 75 deletions(-) diff --git a/fluxer_app/src/components/bottomsheets/ChannelDetailsBottomSheet.tsx b/fluxer_app/src/components/bottomsheets/ChannelDetailsBottomSheet.tsx index 18fbd8c5..d0a0bc26 100644 --- a/fluxer_app/src/components/bottomsheets/ChannelDetailsBottomSheet.tsx +++ b/fluxer_app/src/components/bottomsheets/ChannelDetailsBottomSheet.tsx @@ -894,7 +894,7 @@ export const ChannelDetailsBottomSheet: React.FC } } - const users = memberIds.map((id) => UserStore.getUser(id)).filter((u): u is UserRecord => u !== null); + const users = memberIds.map((id) => UserStore.getUser(id)).filter((u): u is UserRecord => u != null); return MemberListUtils.getGroupDMMemberGroups(users); })(); diff --git a/fluxer_app/src/components/channel/ChannelIndexPage.tsx b/fluxer_app/src/components/channel/ChannelIndexPage.tsx index e07830df..197e82e7 100644 --- a/fluxer_app/src/components/channel/ChannelIndexPage.tsx +++ b/fluxer_app/src/components/channel/ChannelIndexPage.tsx @@ -39,15 +39,15 @@ export const ChannelIndexPage = observer(() => { messageId?: string; }; - if (!channelId) { - return null; - } - - const channel = ChannelStore.getChannel(channelId); + const channel = channelId ? ChannelStore.getChannel(channelId) : undefined; const isInFavorites = location.pathname.startsWith('/channels/@favorites'); const derivedGuildId = isInFavorites ? channel?.guildId : routeGuildId || channel?.guildId; useEffect(() => { + if (!channelId) { + return; + } + if (!channel) { return; } @@ -62,7 +62,11 @@ export const ChannelIndexPage = observer(() => { } NavigationActionCreators.selectChannel(fallbackGuildId, undefined, undefined, 'replace'); - }, [channel, routeGuildId, isInFavorites]); + }, [channelId, channel, routeGuildId, isInFavorites]); + + if (!channelId) { + return null; + } if (channel && (channel.type === ChannelTypes.GUILD_CATEGORY || channel.type === ChannelTypes.GUILD_LINK)) { return null; diff --git a/fluxer_app/src/components/channel/ChannelMembers.tsx b/fluxer_app/src/components/channel/ChannelMembers.tsx index ab71ed68..200d9437 100644 --- a/fluxer_app/src/components/channel/ChannelMembers.tsx +++ b/fluxer_app/src/components/channel/ChannelMembers.tsx @@ -328,7 +328,7 @@ export const ChannelMembers = observer(function ChannelMembers({guild = null, ch if (channel.type === ChannelTypes.GROUP_DM) { const currentUserId = AuthenticationStore.currentUserId; const allUserIds = currentUserId ? [currentUserId, ...channel.recipientIds] : channel.recipientIds; - const users = allUserIds.map((id) => UserStore.getUser(id)).filter((user): user is UserRecord => user !== null); + const users = allUserIds.map((id) => UserStore.getUser(id)).filter((user): user is UserRecord => user != null); const memberGroups = MemberListUtils.getGroupDMMemberGroups(users); return ( diff --git a/fluxer_app/src/components/channel/MessageActionUtils.tsx b/fluxer_app/src/components/channel/MessageActionUtils.tsx index 93f2e141..aa81caa5 100644 --- a/fluxer_app/src/components/channel/MessageActionUtils.tsx +++ b/fluxer_app/src/components/channel/MessageActionUtils.tsx @@ -42,6 +42,7 @@ import MobileLayoutStore from '@app/stores/MobileLayoutStore'; import PermissionStore from '@app/stores/PermissionStore'; import RelationshipStore from '@app/stores/RelationshipStore'; import SavedMessagesStore from '@app/stores/SavedMessagesStore'; +import UserStore from '@app/stores/UserStore'; import type {UnicodeEmoji} from '@app/types/EmojiTypes'; import {isSystemDmChannel} from '@app/utils/ChannelUtils'; import {buildMessageJumpLink} from '@app/utils/MessageLinkUtils'; @@ -450,7 +451,12 @@ export function requestMessageForward(message: MessageRecord): void { return; } - ModalActionCreators.push(modal(() => )); + const currentUser = UserStore.currentUser; + if (!currentUser) { + return; + } + + ModalActionCreators.push(modal(() => )); } export function requestCopyMessageText(message: MessageRecord, i18n: I18n): void { diff --git a/fluxer_app/src/components/channel/direct_message/DMList.tsx b/fluxer_app/src/components/channel/direct_message/DMList.tsx index 3f956e69..325605f0 100644 --- a/fluxer_app/src/components/channel/direct_message/DMList.tsx +++ b/fluxer_app/src/components/channel/direct_message/DMList.tsx @@ -186,7 +186,7 @@ const DMListItem = observer(({channel, isSelected}: {channel: ChannelRecord; isS }, []); const contextMenuOpen = useContextMenuHoverState(scrollTargetRef); const closeAllSheets = useCallback(() => { - closeAllSheets(); + setMenuOpen(false); setNestedSheet(null); }, []); const openNestedSheet = useCallback((title: string, groups: Array) => { diff --git a/fluxer_app/src/components/channel/message_search_bar/MessageSearchBar.tsx b/fluxer_app/src/components/channel/message_search_bar/MessageSearchBar.tsx index 8828ae77..bd3c00a9 100644 --- a/fluxer_app/src/components/channel/message_search_bar/MessageSearchBar.tsx +++ b/fluxer_app/src/components/channel/message_search_bar/MessageSearchBar.tsx @@ -408,7 +408,7 @@ export const MessageSearchBar = observer( useEffect(() => { const context = MemberSearchStore.getSearchContext((results) => { - const users = results.map((result) => UserStore.getUser(result.id)).filter((u): u is UserRecord => u !== null); + const users = results.map((result) => UserStore.getUser(result.id)).filter((u): u is UserRecord => u != null); setMemberSearchResults(users); }, 25); @@ -660,7 +660,7 @@ export const MessageSearchBar = observer( if (channel) { const users = channel.recipientIds .map((id) => UserStore.getUser(id)) - .filter((u): u is UserRecord => u !== null); + .filter((u): u is UserRecord => u != null); return matchSorter(users, searchTerm, {keys: ['username', 'tag']}).slice(0, 12); } diff --git a/fluxer_app/src/components/layout/utils/ChannelMoveOperation.test.tsx b/fluxer_app/src/components/layout/utils/ChannelMoveOperation.test.tsx index 520c1350..0e879eda 100644 --- a/fluxer_app/src/components/layout/utils/ChannelMoveOperation.test.tsx +++ b/fluxer_app/src/components/layout/utils/ChannelMoveOperation.test.tsx @@ -150,6 +150,41 @@ describe('ChannelMoveOperation', () => { }); }); + it('moves a top-level category above another category with root-level preceding sibling', () => { + const milsims = createChannel({id: 'milsims', type: ChannelTypes.GUILD_CATEGORY, position: 3}); + const coopGames = createChannel({id: 'coop-games', type: ChannelTypes.GUILD_CATEGORY, position: 11}); + const frontDoor = createChannel({id: 'front-door', type: ChannelTypes.GUILD_CATEGORY, position: 30}); + const coopVoice = createChannel({ + id: 'coop-voice', + type: ChannelTypes.GUILD_VOICE, + position: 12, + parentId: coopGames.id, + }); + const coopText = createChannel({ + id: 'coop-text', + type: ChannelTypes.GUILD_TEXT, + position: 13, + parentId: coopGames.id, + }); + + const operation = createChannelMoveOperation({ + channels: [milsims, coopGames, frontDoor, coopVoice, coopText], + dragItem: createDragItem(frontDoor), + dropResult: { + targetId: coopGames.id, + position: 'before', + targetParentId: null, + }, + }); + + expect(operation).toEqual({ + channelId: frontDoor.id, + newParentId: null, + precedingSiblingId: milsims.id, + position: 1, + }); + }); + it('returns null when dropping to the same effective placement', () => { const category = createChannel({id: 'category', type: ChannelTypes.GUILD_CATEGORY, position: 0}); const textOne = createChannel({ diff --git a/fluxer_app/src/components/modals/BackupCodesModal.tsx b/fluxer_app/src/components/modals/BackupCodesModal.tsx index 0475311b..85ea78bb 100644 --- a/fluxer_app/src/components/modals/BackupCodesModal.tsx +++ b/fluxer_app/src/components/modals/BackupCodesModal.tsx @@ -24,7 +24,7 @@ import styles from '@app/components/modals/BackupCodesModal.module.css'; import {BackupCodesRegenerateModal} from '@app/components/modals/BackupCodesRegenerateModal'; import * as Modal from '@app/components/modals/Modal'; import {Button} from '@app/components/uikit/button/Button'; -import UserStore from '@app/stores/UserStore'; +import type {UserRecord} from '@app/records/UserRecord'; import type {BackupCode} from '@fluxer/schema/src/domains/user/UserResponseSchemas'; import {Trans, useLingui} from '@lingui/react/macro'; import {CheckIcon, ClipboardIcon, DownloadIcon} from '@phosphor-icons/react'; @@ -32,11 +32,11 @@ import {observer} from 'mobx-react-lite'; interface BackupCodesModalProps { backupCodes: ReadonlyArray; + user: UserRecord; } -export const BackupCodesModal = observer(({backupCodes}: BackupCodesModalProps) => { +export const BackupCodesModal = observer(({backupCodes, user}: BackupCodesModalProps) => { const {t, i18n} = useLingui(); - const user = UserStore.getCurrentUser()!; return ( @@ -89,7 +89,7 @@ export const BackupCodesModal = observer(({backupCodes}: BackupCodesModalProps) diff --git a/fluxer_app/src/components/modals/BackupCodesRegenerateModal.tsx b/fluxer_app/src/components/modals/BackupCodesRegenerateModal.tsx index e3854cdd..c6b8e651 100644 --- a/fluxer_app/src/components/modals/BackupCodesRegenerateModal.tsx +++ b/fluxer_app/src/components/modals/BackupCodesRegenerateModal.tsx @@ -27,6 +27,7 @@ import {BackupCodesModal} from '@app/components/modals/BackupCodesModal'; import * as Modal from '@app/components/modals/Modal'; import {Button} from '@app/components/uikit/button/Button'; import {useFormSubmit} from '@app/hooks/useFormSubmit'; +import type {UserRecord} from '@app/records/UserRecord'; import {Trans, useLingui} from '@lingui/react/macro'; import {observer} from 'mobx-react-lite'; import {useForm} from 'react-hook-form'; @@ -35,14 +36,20 @@ interface FormInputs { form: string; } -export const BackupCodesRegenerateModal = observer(() => { +interface BackupCodesRegenerateModalProps { + user: UserRecord; +} + +export const BackupCodesRegenerateModal = observer(({user}: BackupCodesRegenerateModalProps) => { const {t} = useLingui(); const form = useForm(); const onSubmit = async () => { const backupCodes = await MfaActionCreators.getBackupCodes(true); ModalActionCreators.pop(); - ModalActionCreators.update('backup-codes', () => modal(() => )); + ModalActionCreators.update('backup-codes', () => + modal(() => ), + ); ToastActionCreators.createToast({ type: 'success', children: t`Backup codes regenerated`, diff --git a/fluxer_app/src/components/modals/BackupCodesViewModal.tsx b/fluxer_app/src/components/modals/BackupCodesViewModal.tsx index f6cfb349..61e4c2ab 100644 --- a/fluxer_app/src/components/modals/BackupCodesViewModal.tsx +++ b/fluxer_app/src/components/modals/BackupCodesViewModal.tsx @@ -26,6 +26,7 @@ import {BackupCodesModal} from '@app/components/modals/BackupCodesModal'; import * as Modal from '@app/components/modals/Modal'; import {Button} from '@app/components/uikit/button/Button'; import {useFormSubmit} from '@app/hooks/useFormSubmit'; +import type {UserRecord} from '@app/records/UserRecord'; import {Trans, useLingui} from '@lingui/react/macro'; import {observer} from 'mobx-react-lite'; import {useForm} from 'react-hook-form'; @@ -34,7 +35,11 @@ interface FormInputs { form: string; } -export const BackupCodesViewModal = observer(() => { +interface BackupCodesViewModalProps { + user: UserRecord; +} + +export const BackupCodesViewModal = observer(({user}: BackupCodesViewModalProps) => { const {t} = useLingui(); const form = useForm(); @@ -42,7 +47,7 @@ export const BackupCodesViewModal = observer(() => { const backupCodes = await MfaActionCreators.getBackupCodes(); ModalActionCreators.pop(); ModalActionCreators.pushWithKey( - modal(() => ), + modal(() => ), 'backup-codes', ); }; diff --git a/fluxer_app/src/components/modals/EmailChangeModal.tsx b/fluxer_app/src/components/modals/EmailChangeModal.tsx index 4e058a09..f7be2f65 100644 --- a/fluxer_app/src/components/modals/EmailChangeModal.tsx +++ b/fluxer_app/src/components/modals/EmailChangeModal.tsx @@ -26,7 +26,7 @@ import styles from '@app/components/modals/EmailChangeModal.module.css'; import * as Modal from '@app/components/modals/Modal'; import {Button} from '@app/components/uikit/button/Button'; import {useFormSubmit} from '@app/hooks/useFormSubmit'; -import UserStore from '@app/stores/UserStore'; +import type {UserRecord} from '@app/records/UserRecord'; import {Trans, useLingui} from '@lingui/react/macro'; import {observer} from 'mobx-react-lite'; import {useEffect, useMemo, useState} from 'react'; @@ -38,9 +38,12 @@ interface NewEmailForm { email: string; } -export const EmailChangeModal = observer(() => { +interface EmailChangeModalProps { + user: UserRecord; +} + +export const EmailChangeModal = observer(({user}: EmailChangeModalProps) => { const {t} = useLingui(); - const user = UserStore.getCurrentUser()!; const newEmailForm = useForm({defaultValues: {email: ''}}); const [stage, setStage] = useState('intro'); const [ticket, setTicket] = useState(null); diff --git a/fluxer_app/src/components/modals/FluxerTagChangeModal.tsx b/fluxer_app/src/components/modals/FluxerTagChangeModal.tsx index 6e49dc9c..e7075e1a 100644 --- a/fluxer_app/src/components/modals/FluxerTagChangeModal.tsx +++ b/fluxer_app/src/components/modals/FluxerTagChangeModal.tsx @@ -33,7 +33,7 @@ import FocusRing from '@app/components/uikit/focus_ring/FocusRing'; import {PlutoniumUpsell} from '@app/components/uikit/plutonium_upsell/PlutoniumUpsell'; import {Tooltip} from '@app/components/uikit/tooltip/Tooltip'; import {useFormSubmit} from '@app/hooks/useFormSubmit'; -import UserStore from '@app/stores/UserStore'; +import type {UserRecord} from '@app/records/UserRecord'; import {LimitResolver} from '@app/utils/limits/LimitResolverAdapter'; import {isLimitToggleEnabled} from '@app/utils/limits/LimitUtils'; import {shouldShowPremiumFeatures} from '@app/utils/PremiumUtils'; @@ -47,9 +47,12 @@ interface FormInputs { discriminator: string; } -export const FluxerTagChangeModal = observer(() => { +interface FluxerTagChangeModalProps { + user: UserRecord; +} + +export const FluxerTagChangeModal = observer(({user}: FluxerTagChangeModalProps) => { const {t} = useLingui(); - const user = UserStore.getCurrentUser()!; const usernameRef = useRef(null); const hasCustomDiscriminator = isLimitToggleEnabled( {feature_custom_discriminator: LimitResolver.resolve({key: 'feature_custom_discriminator', fallback: 0})}, @@ -143,7 +146,7 @@ export const FluxerTagChangeModal = observer(() => { ModalActionCreators.pop(); ToastActionCreators.createToast({type: 'success', children: t`FluxerTag updated`}); }, - [hasCustomDiscriminator, user.username, user.discriminator], + [hasCustomDiscriminator], ); const {handleSubmit, isSubmitting} = useFormSubmit({ diff --git a/fluxer_app/src/components/modals/ForwardModal.tsx b/fluxer_app/src/components/modals/ForwardModal.tsx index b0c13fde..2332bccc 100644 --- a/fluxer_app/src/components/modals/ForwardModal.tsx +++ b/fluxer_app/src/components/modals/ForwardModal.tsx @@ -52,6 +52,7 @@ import {Logger} from '@app/lib/Logger'; import {TextareaAutosize} from '@app/lib/TextareaAutosize'; import type {ChannelRecord} from '@app/records/ChannelRecord'; import type {MessageRecord} from '@app/records/MessageRecord'; +import type {UserRecord} from '@app/records/UserRecord'; import ChannelStore from '@app/stores/ChannelStore'; import MobileLayoutStore from '@app/stores/MobileLayoutStore'; import UserStore from '@app/stores/UserStore'; @@ -66,7 +67,12 @@ import {useCallback, useMemo, useRef, useState} from 'react'; const logger = new Logger('ForwardModal'); -export const ForwardModal = observer(({message}: {message: MessageRecord}) => { +interface ForwardModalProps { + message: MessageRecord; + user: UserRecord; +} + +export const ForwardModal = observer(({message, user}: ForwardModalProps) => { const {t} = useLingui(); const {filteredChannels, handleToggleChannel, isChannelDisabled, searchQuery, selectedChannelIds, setSearchQuery} = useForwardChannelSelection({excludedChannelId: message.channelId}); @@ -75,7 +81,6 @@ export const ForwardModal = observer(({message}: {message: MessageRecord}) => { const [expressionPickerOpen, setExpressionPickerOpen] = useState(false); const textareaRef = useRef(null); const containerRef = useRef(null); - const currentUser = UserStore.currentUser!; const premiumMaxLength = Limits.getPremiumValue('max_message_length', MAX_MESSAGE_LENGTH_PREMIUM); const mobileLayout = MobileLayoutStore; @@ -88,7 +93,7 @@ export const ForwardModal = observer(({message}: {message: MessageRecord}) => { textareaRef, segmentManagerRef, previousValueRef, - maxActualLength: currentUser.maxMessageLength, + maxActualLength: user.maxMessageLength, onExceedMaxLength: handleOptionalMessageExceedsLimit, }); @@ -109,7 +114,7 @@ export const ForwardModal = observer(({message}: {message: MessageRecord}) => { textareaRef, segmentManagerRef, previousValueRef, - maxActualLength: currentUser.maxMessageLength, + maxActualLength: user.maxMessageLength, onExceedMaxLength: handleOptionalMessageExceedsLimit, }); @@ -119,14 +124,14 @@ export const ForwardModal = observer(({message}: {message: MessageRecord}) => { segmentManagerRef, setValue: setOptionalMessage, previousValueRef, - maxMessageLength: currentUser.maxMessageLength, + maxMessageLength: user.maxMessageLength, onPasteExceedsLimit: () => handleOptionalMessageExceedsLimit(), }); const actualOptionalMessage = useMemo(() => displayToActual(optionalMessage), [displayToActual, optionalMessage]); const optionalMessageDisplayMaxLength = useMemo(() => { - return Math.max(0, optionalMessage.length + (currentUser.maxMessageLength - actualOptionalMessage.length)); - }, [actualOptionalMessage.length, currentUser.maxMessageLength, optionalMessage.length]); + return Math.max(0, optionalMessage.length + (user.maxMessageLength - actualOptionalMessage.length)); + }, [actualOptionalMessage.length, user.maxMessageLength, optionalMessage.length]); const handleForward = async () => { if (selectedChannelIds.size === 0 || isForwarding) return; @@ -310,8 +315,8 @@ export const ForwardModal = observer(({message}: {message: MessageRecord}) => { />
diff --git a/fluxer_app/src/components/modals/MfaTotpEnableModal.tsx b/fluxer_app/src/components/modals/MfaTotpEnableModal.tsx index f1352ee9..9a74cdf3 100644 --- a/fluxer_app/src/components/modals/MfaTotpEnableModal.tsx +++ b/fluxer_app/src/components/modals/MfaTotpEnableModal.tsx @@ -29,7 +29,7 @@ import * as Modal from '@app/components/modals/Modal'; import {Button} from '@app/components/uikit/button/Button'; import {QRCodeCanvas} from '@app/components/uikit/QRCodeCanvas'; import {useFormSubmit} from '@app/hooks/useFormSubmit'; -import UserStore from '@app/stores/UserStore'; +import type {UserRecord} from '@app/records/UserRecord'; import * as MfaUtils from '@app/utils/MfaUtils'; import {Trans, useLingui} from '@lingui/react/macro'; import {observer} from 'mobx-react-lite'; @@ -40,9 +40,12 @@ interface FormInputs { code: string; } -export const MfaTotpEnableModal = observer(() => { +interface MfaTotpEnableModalProps { + user: UserRecord; +} + +export const MfaTotpEnableModal = observer(({user}: MfaTotpEnableModalProps) => { const {t} = useLingui(); - const user = UserStore.getCurrentUser()!; const form = useForm(); const [secret] = useState(() => MfaUtils.generateTotpSecret()); @@ -54,7 +57,7 @@ export const MfaTotpEnableModal = observer(() => { ModalActionCreators.pop(); ToastActionCreators.createToast({type: 'success', children: Two-factor authentication enabled}); ModalActionCreators.pushWithKey( - modal(() => ), + modal(() => ), 'backup-codes', ); }; diff --git a/fluxer_app/src/components/modals/MobileVideoViewer.tsx b/fluxer_app/src/components/modals/MobileVideoViewer.tsx index 448d2fc1..b056a207 100644 --- a/fluxer_app/src/components/modals/MobileVideoViewer.tsx +++ b/fluxer_app/src/components/modals/MobileVideoViewer.tsx @@ -61,6 +61,11 @@ export const MobileVideoViewer = observer(function MobileVideoViewer({ const hudTimerRef = useRef | null>(null); const [hasInitialized, setHasInitialized] = useState(false); + const safelyPlayVideo = useCallback((video: HTMLVideoElement) => { + const playPromise = video.play(); + void playPromise?.catch(() => {}); + }, []); + const progress = duration > 0 ? currentTime / duration : 0; const scheduleHudHide = useCallback(() => { @@ -86,18 +91,21 @@ export const MobileVideoViewer = observer(function MobileVideoViewer({ setZoomScale(state.scale); }, []); - const handlePlayPause = useCallback((e: React.MouseEvent) => { - e.stopPropagation(); - const video = videoRef.current; - if (!video) return; + const handlePlayPause = useCallback( + (e: React.MouseEvent) => { + e.stopPropagation(); + const video = videoRef.current; + if (!video) return; - if (video.paused) { - video.play(); - transformRef.current?.resetTransform(); - } else { - video.pause(); - } - }, []); + if (video.paused) { + safelyPlayVideo(video); + transformRef.current?.resetTransform(); + } else { + video.pause(); + } + }, + [safelyPlayVideo], + ); const handleToggleMute = useCallback((e: React.MouseEvent) => { e.stopPropagation(); @@ -139,7 +147,7 @@ export const MobileVideoViewer = observer(function MobileVideoViewer({ if (initialTime && !hasInitialized) { video.currentTime = initialTime; setHasInitialized(true); - video.play(); + safelyPlayVideo(video); } }; const handleDurationChange = () => setDuration(video.duration); @@ -157,7 +165,7 @@ export const MobileVideoViewer = observer(function MobileVideoViewer({ video.removeEventListener('loadedmetadata', handleLoadedMetadata); video.removeEventListener('durationchange', handleDurationChange); }; - }, [initialTime, hasInitialized, scheduleHudHide]); + }, [initialTime, hasInitialized, scheduleHudHide, safelyPlayVideo]); useEffect(() => { const video = videoRef.current; diff --git a/fluxer_app/src/components/modals/tabs/MyProfileTab.tsx b/fluxer_app/src/components/modals/tabs/MyProfileTab.tsx index 0ccf3e1f..3e787f4c 100644 --- a/fluxer_app/src/components/modals/tabs/MyProfileTab.tsx +++ b/fluxer_app/src/components/modals/tabs/MyProfileTab.tsx @@ -672,7 +672,7 @@ const MyProfileTabComponent = observer(function MyProfileTabComponent({ ) : (
- {!isPerGuildProfile && } + {!isPerGuildProfile && } {isPerGuildProfile && (
diff --git a/fluxer_app/src/components/modals/tabs/account_security_tab/AccountTab.tsx b/fluxer_app/src/components/modals/tabs/account_security_tab/AccountTab.tsx index 604c74b1..419844c5 100644 --- a/fluxer_app/src/components/modals/tabs/account_security_tab/AccountTab.tsx +++ b/fluxer_app/src/components/modals/tabs/account_security_tab/AccountTab.tsx @@ -77,7 +77,10 @@ export const AccountTabContent: React.FC = observer(
-
diff --git a/fluxer_app/src/components/modals/tabs/account_security_tab/SecurityTab.tsx b/fluxer_app/src/components/modals/tabs/account_security_tab/SecurityTab.tsx index 8a1dbff8..e0f91cbe 100644 --- a/fluxer_app/src/components/modals/tabs/account_security_tab/SecurityTab.tsx +++ b/fluxer_app/src/components/modals/tabs/account_security_tab/SecurityTab.tsx @@ -240,7 +240,10 @@ export const SecurityTabContent: React.FC = observer( Disable ) : ( - )} @@ -260,7 +263,7 @@ export const SecurityTabContent: React.FC = observer( diff --git a/fluxer_app/src/components/modals/tabs/my_profile_tab/UsernameSection.tsx b/fluxer_app/src/components/modals/tabs/my_profile_tab/UsernameSection.tsx index 6da51f6d..d60267cb 100644 --- a/fluxer_app/src/components/modals/tabs/my_profile_tab/UsernameSection.tsx +++ b/fluxer_app/src/components/modals/tabs/my_profile_tab/UsernameSection.tsx @@ -24,6 +24,7 @@ import {FluxerTagChangeModal} from '@app/components/modals/FluxerTagChangeModal' import styles from '@app/components/modals/tabs/my_profile_tab/UsernameSection.module.css'; import {Button} from '@app/components/uikit/button/Button'; import {Tooltip} from '@app/components/uikit/tooltip/Tooltip'; +import type {UserRecord} from '@app/records/UserRecord'; import {LimitResolver} from '@app/utils/limits/LimitResolverAdapter'; import {isLimitToggleEnabled} from '@app/utils/limits/LimitUtils'; import {shouldShowPremiumFeatures} from '@app/utils/PremiumUtils'; @@ -34,10 +35,10 @@ import {observer} from 'mobx-react-lite'; interface UsernameSectionProps { isClaimed: boolean; - discriminator: string; + user: UserRecord; } -export const UsernameSection = observer(({isClaimed, discriminator}: UsernameSectionProps) => { +export const UsernameSection = observer(({isClaimed, user}: UsernameSectionProps) => { const {t} = useLingui(); const hasCustomDiscriminator = isLimitToggleEnabled( @@ -64,14 +65,14 @@ export const UsernameSection = observer(({isClaimed, discriminator}: UsernameSec )} {!hasCustomDiscriminator && shouldShowPremiumFeatures() && ( - +