/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see .
*/
import {Plural, Trans, useLingui} from '@lingui/react/macro';
import {
CaretDownIcon,
ChatTeardropIcon,
CheckCircleIcon,
ClockCounterClockwiseIcon,
DotsThreeIcon,
PencilIcon,
ProhibitIcon,
UserMinusIcon,
UserPlusIcon,
UsersThreeIcon,
} from '@phosphor-icons/react';
import {clsx} from 'clsx';
import {autorun} from 'mobx';
import {observer} from 'mobx-react-lite';
import React, {useId} from 'react';
import type {PressEvent} from 'react-aria-components';
import * as ContextMenuActionCreators from '~/actions/ContextMenuActionCreators';
import * as ModalActionCreators from '~/actions/ModalActionCreators';
import {modal} from '~/actions/ModalActionCreators';
import * as NavigationActionCreators from '~/actions/NavigationActionCreators';
import * as PrivateChannelActionCreators from '~/actions/PrivateChannelActionCreators';
import * as TextCopyActionCreators from '~/actions/TextCopyActionCreators';
import * as UserNoteActionCreators from '~/actions/UserNoteActionCreators';
import * as UserProfileActionCreators from '~/actions/UserProfileActionCreators';
import {DEFAULT_ACCENT_COLOR, Permissions, RelationshipTypes} from '~/Constants';
import {UserTag} from '~/components/channel/UserTag';
import {CustomStatusDisplay} from '~/components/common/CustomStatusDisplay/CustomStatusDisplay';
import {GroupDMAvatar} from '~/components/common/GroupDMAvatar';
import {CustomStatusModal} from '~/components/modals/CustomStatusModal';
import type {IARContext} from '~/components/modals/IARModal';
import {IARModal} from '~/components/modals/IARModal';
import * as Modal from '~/components/modals/Modal';
import {UserSettingsModal} from '~/components/modals/UserSettingsModal';
import {GuildIcon} from '~/components/popouts/GuildIcon';
import {UserProfileBadges} from '~/components/popouts/UserProfileBadges';
import {UserProfileDataWarning} from '~/components/popouts/UserProfileDataWarning';
import {UserProfileBio, UserProfileMembershipInfo, UserProfileRoles} from '~/components/popouts/UserProfileShared';
import {Button} from '~/components/uikit/Button/Button';
import {
BlockUserIcon,
CopyFluxerTagIcon,
CopyUserIdIcon,
ReportUserIcon,
VideoCallIcon,
ViewGlobalProfileIcon,
VoiceCallIcon,
} from '~/components/uikit/ContextMenu/ContextMenuIcons';
import {GroupDMContextMenu} from '~/components/uikit/ContextMenu/GroupDMContextMenu';
import {GuildContextMenu} from '~/components/uikit/ContextMenu/GuildContextMenu';
import {GuildMemberContextMenu} from '~/components/uikit/ContextMenu/GuildMemberContextMenu';
import {MenuGroup} from '~/components/uikit/ContextMenu/MenuGroup';
import {MenuItem} from '~/components/uikit/ContextMenu/MenuItem';
import {MenuItemRadio} from '~/components/uikit/ContextMenu/MenuItemRadio';
import {UserContextMenu} from '~/components/uikit/ContextMenu/UserContextMenu';
import {Scroller} from '~/components/uikit/Scroller';
import {Spinner} from '~/components/uikit/Spinner';
import {StatusAwareAvatar} from '~/components/uikit/StatusAwareAvatar';
import {Tabs} from '~/components/uikit/Tabs/Tabs';
import {Tooltip} from '~/components/uikit/Tooltip/Tooltip';
import {useAutoplayExpandedProfileAnimations} from '~/hooks/useAutoplayExpandedProfileAnimations';
import {TextareaAutosize} from '~/lib/TextareaAutosize';
import {Routes} from '~/Routes';
import type {ChannelRecord} from '~/records/ChannelRecord';
import type {GuildRecord} from '~/records/GuildRecord';
import type {ProfileRecord} from '~/records/ProfileRecord';
import {type UserPartial, UserRecord} from '~/records/UserRecord';
import AuthenticationStore from '~/stores/AuthenticationStore';
import ChannelStore from '~/stores/ChannelStore';
import type {ContextMenuTargetElement} from '~/stores/ContextMenuStore';
import ContextMenuStore, {isContextMenuNodeTarget} from '~/stores/ContextMenuStore';
import DeveloperOptionsStore from '~/stores/DeveloperOptionsStore';
import GuildMemberStore from '~/stores/GuildMemberStore';
import MemberPresenceSubscriptionStore from '~/stores/MemberPresenceSubscriptionStore';
import ModalStore from '~/stores/ModalStore';
import PermissionStore from '~/stores/PermissionStore';
import RelationshipStore from '~/stores/RelationshipStore';
import SelectedChannelStore from '~/stores/SelectedChannelStore';
import UserNoteStore from '~/stores/UserNoteStore';
import UserProfileStore from '~/stores/UserProfileStore';
import UserStore from '~/stores/UserStore';
import * as CallUtils from '~/utils/CallUtils';
import * as ChannelUtils from '~/utils/ChannelUtils';
import * as ColorUtils from '~/utils/ColorUtils';
import * as NicknameUtils from '~/utils/NicknameUtils';
import * as ProfileDisplayUtils from '~/utils/ProfileDisplayUtils';
import {createMockProfile} from '~/utils/ProfileUtils';
import * as RelationshipActionUtils from '~/utils/RelationshipActionUtils';
import * as RouterUtils from '~/utils/RouterUtils';
import modalRootStyles from './Modal.module.css';
import userProfileModalStyles from './UserProfileModal.module.css';
export interface UserProfileModalProps {
userId: string;
guildId?: string;
autoFocusNote?: boolean;
disableEditProfile?: boolean;
previewOverrides?: ProfileDisplayUtils.ProfilePreviewOverrides;
previewUser?: UserRecord;
}
interface UserInfoProps {
user: UserRecord;
profile: ProfileRecord;
guildId?: string;
warningIndicator?: React.ReactNode;
isCurrentUser?: boolean;
onEditCustomStatus?: () => void;
}
interface UserNoteEditorProps {
userId: string;
initialNote: string | null;
autoFocus?: boolean;
noteRef?: React.RefObject;
}
interface ProfileContentProps {
profile: ProfileRecord;
user: UserRecord;
userNote: string | null;
autoFocusNote?: boolean;
noteRef?: React.RefObject;
}
type UserProfileModalComponent = React.FC;
interface ProfileModalContentProps {
profile: ProfileRecord;
user: UserRecord;
userNote: string | null;
autoFocusNote?: boolean;
noteRef?: React.RefObject;
renderActionButtons: () => React.ReactNode;
previewOverrides?: ProfileDisplayUtils.ProfilePreviewOverrides;
warningIndicator?: React.ReactNode;
}
const UserInfo: React.FC = observer(
({user, profile, guildId, warningIndicator, isCurrentUser, onEditCustomStatus}) => {
const displayName = NicknameUtils.getNickname(user, guildId);
const effectiveProfile = profile?.getEffectiveProfile() ?? null;
const shouldAutoplayProfileAnimations = useAutoplayExpandedProfileAnimations();
return (