Support member tags (#6749)
This commit is contained in:
parent
cdebd3b479
commit
cbce577dab
@ -345,6 +345,7 @@ export function buildChatMember(
|
||||
|
||||
return {
|
||||
userId,
|
||||
rank: 'rank' in member ? member.rank : undefined,
|
||||
inviterId: 'inviterId' in member && member.inviterId
|
||||
? buildApiPeerId(member.inviterId, 'user')
|
||||
: undefined,
|
||||
@ -355,7 +356,6 @@ export function buildChatMember(
|
||||
: undefined,
|
||||
bannedRights: 'bannedRights' in member ? omitVirtualClassFields(member.bannedRights) : undefined,
|
||||
adminRights: 'adminRights' in member ? omitVirtualClassFields(member.adminRights) : undefined,
|
||||
customTitle: 'rank' in member ? member.rank : undefined,
|
||||
isViaRequest: 'viaRequest' in member ? member.viaRequest : undefined,
|
||||
...((member instanceof GramJs.ChannelParticipantAdmin || member instanceof GramJs.ChatParticipantAdmin) && {
|
||||
isAdmin: true,
|
||||
|
||||
@ -297,6 +297,7 @@ export function buildApiMessageWithChatId(
|
||||
paidMessageStars: toJSNumber(mtpMessage.paidMessageStars),
|
||||
restrictionReasons,
|
||||
summaryLanguageCode: mtpMessage.summaryFromLanguage,
|
||||
fromRank: mtpMessage.fromRank,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1411,8 +1411,8 @@ export function updateChatMemberBannedRights({
|
||||
}
|
||||
|
||||
export function updateChatAdmin({
|
||||
chat, user, adminRights, customTitle = DEFAULT_PRIMITIVES.STRING,
|
||||
}: { chat: ApiChat; user: ApiUser; adminRights: ApiChatAdminRights; customTitle?: string }) {
|
||||
chat, user, adminRights, rank,
|
||||
}: { chat: ApiChat; user: ApiUser; adminRights: ApiChatAdminRights; rank?: string }) {
|
||||
const channel = buildInputChannel(chat.id, chat.accessHash);
|
||||
const userId = buildInputUser(user.id, user.accessHash);
|
||||
|
||||
@ -1420,7 +1420,7 @@ export function updateChatAdmin({
|
||||
channel,
|
||||
userId,
|
||||
adminRights: buildChatAdminRights(adminRights),
|
||||
rank: customTitle,
|
||||
rank,
|
||||
}), {
|
||||
shouldReturnTrue: true,
|
||||
});
|
||||
|
||||
@ -1112,6 +1112,24 @@ export async function deleteParticipantHistory({
|
||||
}
|
||||
}
|
||||
|
||||
export function editChatParticipantRank({
|
||||
chat, peer, rank,
|
||||
}: {
|
||||
chat: ApiChat;
|
||||
peer: ApiPeer;
|
||||
rank: string;
|
||||
}) {
|
||||
const participant = buildInputPeer(peer.id, peer.accessHash);
|
||||
|
||||
return invokeRequest(new GramJs.messages.EditChatParticipantRank({
|
||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||
participant,
|
||||
rank,
|
||||
}), {
|
||||
shouldReturnTrue: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteScheduledMessages({
|
||||
chat, messageIds,
|
||||
}: {
|
||||
|
||||
@ -654,6 +654,13 @@ export function updater(update: Update) {
|
||||
id: buildApiPeerId(update.chatId, 'chat'),
|
||||
deletedMemberId: buildApiPeerId(update.userId, 'user'),
|
||||
});
|
||||
} else if (update instanceof GramJs.UpdateChatParticipantRank) {
|
||||
sendApiUpdate({
|
||||
'@type': 'updateChatParticipantRank',
|
||||
id: buildApiPeerId(update.chatId, 'chat'),
|
||||
userId: buildApiPeerId(update.userId, 'user'),
|
||||
rank: update.rank,
|
||||
});
|
||||
} else if (
|
||||
update instanceof GramJs.UpdatePinnedMessages
|
||||
|| update instanceof GramJs.UpdatePinnedChannelMessages
|
||||
|
||||
@ -160,13 +160,13 @@ export interface ApiChatFullInfo {
|
||||
|
||||
export interface ApiChatMember {
|
||||
userId: string;
|
||||
rank?: string;
|
||||
inviterId?: string;
|
||||
joinedDate?: number;
|
||||
kickedByUserId?: string;
|
||||
promotedByUserId?: string;
|
||||
bannedRights?: ApiChatBannedRights;
|
||||
adminRights?: ApiChatAdminRights;
|
||||
customTitle?: string;
|
||||
isAdmin?: true;
|
||||
isOwner?: true;
|
||||
isViaRequest?: true;
|
||||
@ -188,6 +188,7 @@ export interface ApiChatAdminRights {
|
||||
editStories?: true;
|
||||
deleteStories?: true;
|
||||
manageDirectMessages?: true;
|
||||
manageRanks?: true;
|
||||
}
|
||||
|
||||
export interface ApiChatBannedRights {
|
||||
@ -211,6 +212,7 @@ export interface ApiChatBannedRights {
|
||||
sendVoices?: true;
|
||||
sendDocs?: true;
|
||||
sendPlain?: true;
|
||||
editRank?: true;
|
||||
untilDate?: number;
|
||||
}
|
||||
|
||||
|
||||
@ -698,6 +698,7 @@ export interface ApiMessage {
|
||||
paidMessageStars?: number;
|
||||
restrictionReasons?: ApiRestrictionReason[];
|
||||
summaryLanguageCode?: string;
|
||||
fromRank?: string;
|
||||
|
||||
isTypingDraft?: boolean; // Local field
|
||||
}
|
||||
|
||||
@ -179,6 +179,13 @@ export type ApiUpdateChatMembers = {
|
||||
deletedMemberId?: string;
|
||||
};
|
||||
|
||||
export type ApiUpdateChatParticipantRank = {
|
||||
'@type': 'updateChatParticipantRank';
|
||||
id: string;
|
||||
userId: string;
|
||||
rank: string;
|
||||
};
|
||||
|
||||
export type ApiUpdatePinnedChatIds = {
|
||||
'@type': 'updatePinnedChatIds';
|
||||
ids?: string[];
|
||||
@ -924,7 +931,8 @@ export type ApiUpdate = (
|
||||
ApiUpdateReady | ApiUpdateSession | ApiUpdateWebAuthTokenFailed | ApiUpdateRequestUserUpdate |
|
||||
ApiUpdateAuthorizationState | ApiUpdateAuthorizationError | ApiUpdateConnectionState | ApiUpdateCurrentUser |
|
||||
ApiUpdateChat | ApiUpdateChatTypingStatus | ApiUpdateChatFullInfo | ApiUpdatePinnedChatIds |
|
||||
ApiUpdateChatMembers | ApiUpdateChatJoin | ApiUpdateChatLeave | ApiUpdateChatPinned | ApiUpdatePinnedMessageIds |
|
||||
ApiUpdateChatMembers | ApiUpdateChatParticipantRank | ApiUpdateChatJoin | ApiUpdateChatLeave
|
||||
| ApiUpdateChatPinned | ApiUpdatePinnedMessageIds |
|
||||
ApiUpdateChatListType | ApiUpdateChatFolder | ApiUpdateChatFoldersOrder | ApiUpdateRecommendedChatFolders |
|
||||
ApiUpdateNewMessage | ApiUpdateMessage | ApiUpdateThreadInfo | ApiUpdateCommonBoxMessages | ApiUpdatePasskeyOption |
|
||||
ApiUpdateDeleteMessages | ApiUpdateMessagePoll | ApiUpdateMessagePollVote | ApiUpdateDeleteHistory |
|
||||
|
||||
1
src/assets/font-icons/user-tag.svg
Normal file
1
src/assets/font-icons/user-tag.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 32 32"><path d="M14.98 14.686a6.31 6.31 0 1 0 .003-12.62h-.002a6.31 6.31 0 0 0 0 12.62m-.224 11.128a4.4 4.4 0 0 1-.555-.708l-.153-.228-.1-.28a3.7 3.7 0 0 1-.206-1.16v-4.972c0-.202.023-.4.06-.594-6.067.298-9.243 2.86-10.606 4.377-.613.683-.837 1.595-.837 2.513a4.123 4.123 0 0 0 4.123 4.123h11.344z"/><path d="M29.64 24.56c0 .16-.053.321-.106.535-.054.214-.16.32-.321.48l-4.971 4.972c-.16.16-.268.214-.481.32-.214.108-.321.054-.481.054s-.321-.053-.535-.107c-.214-.053-.32-.16-.481-.32L16.17 24.4a3 3 0 0 1-.32-.428 2 2 0 0 1-.107-.534v-4.971c0-.374.16-.695.427-.962s.588-.428.963-.428h4.97c.161 0 .375.053.535.107.16.053.32.16.428.32l6.147 6.094q.24.24.32.481c.054.16.107.321.107.481m-9.728-4.383c0-.267-.107-.534-.32-.748-.214-.16-.428-.267-.749-.267s-.534.107-.748.32-.321.428-.321.749c0 .267.107.534.32.748s.428.32.75.32.534-.106.747-.32c.214-.267.321-.481.321-.802"/></svg>
|
||||
|
After Width: | Height: | Size: 950 B |
@ -130,6 +130,7 @@
|
||||
"UserRestrictionsNoChangeInfo" = "can't change Info";
|
||||
"UserRestrictionsInviteUsers" = "Add Users";
|
||||
"UserRestrictionsPinMessages" = "Pin Messages";
|
||||
"UserRestrictionsEditRank" = "Edit Own Tags";
|
||||
"ChatPermissionNotAvailable" = "This permission is not available in public groups.";
|
||||
"StatsMessageInteractionsTitle" = "INTERACTIONS";
|
||||
"StatsGroupGrowthTitle" = "GROWTH";
|
||||
@ -541,6 +542,7 @@
|
||||
"PrivacyExceptions" = "Exceptions";
|
||||
"AlwaysAllow" = "Always Allow";
|
||||
"EditAdminAddUsers" = "Add Users";
|
||||
"EditAdminEditRank" = "Edit Member Tags";
|
||||
"NeverAllow" = "Never Allow";
|
||||
"AlwaysAllowPlaceholder" = "Always allow...";
|
||||
"NeverAllowPlaceholder" = "Never allow...";
|
||||
@ -966,7 +968,7 @@
|
||||
"StartVoipChatPermission" = "Manage Video Chats";
|
||||
"EditAdminSendAnonymously" = "Remain Anonymous";
|
||||
"ChannelEditAdminCannotEdit" = "You can't edit the rights of this admin.";
|
||||
"EditAdminRank" = "Custom title";
|
||||
"EditAdminRank" = "Member tag";
|
||||
"EditAdminRemoveAdmin" = "Dismiss Admin";
|
||||
"EditAdminTransferChannelOwnership" = "Transfer Channel Ownership";
|
||||
"EditAdminTransferGroupOwnership" = "Transfer Group Ownership";
|
||||
@ -2732,4 +2734,19 @@
|
||||
"GiftPreviewToggleRegularModels" = "View Primary Models >";
|
||||
"AriaGiftPreviewPlay" = "Play random previews";
|
||||
"AriaGiftPreviewStop" = "Pause random previews";
|
||||
"RankModalEdit" = "Edit Tag";
|
||||
"RankModalEditMy" = "Edit My Tag";
|
||||
"MemberContextEditRank" = "Edit Tag";
|
||||
"RankMemberTag" = "Member Tag";
|
||||
"RankAdminTag" = "Admin Tag";
|
||||
"RankOwnerTag" = "Owner Tag";
|
||||
"RankModalMemberTagTitle" = "Member Tag";
|
||||
"RankModalAdminTagTitle" = "Admin Tag";
|
||||
"RankModalOwnerTagTitle" = "Owner Tag";
|
||||
"RankModalMemberText" = "This gray tag {tag} is **{author}**'s member tag in **{group}**.";
|
||||
"RankModalAdminText" = "This green tag {tag} is **{author}**'s admin tag in **{group}**.";
|
||||
"RankModalOwnerText" = "This purple tag {tag} is **{author}**'s owner tag in **{group}**.";
|
||||
"RankEditSave" = "Edit Tag";
|
||||
"RankEditTextOwn" = "Share your role, title or how you're known in this group. Your tag is visible to all members.";
|
||||
"RankEditText" = "Add a short tag next to {user}'s name.";
|
||||
"MenuAddCaption" = "Add Caption";
|
||||
|
||||
@ -105,6 +105,8 @@ export { default as OneTimeMediaModal } from '../components/modals/oneTimeMedia/
|
||||
export { default as WebAppsCloseConfirmationModal } from '../components/main/WebAppsCloseConfirmationModal';
|
||||
export { default as FrozenAccountModal } from '../components/modals/frozenAccount/FrozenAccountModal';
|
||||
export { default as ProfileRatingModal } from '../components/modals/profileRating/ProfileRatingModal';
|
||||
export { default as EditRankModal } from '../components/modals/rank/EditRankModal';
|
||||
export { default as RankModal } from '../components/modals/rank/RankModal';
|
||||
export { default as QuickPreviewModal } from '../components/modals/quickPreview/QuickPreviewModal';
|
||||
export { default as StealthModeModal } from '../components/modals/storyStealthMode/StealthModeModal';
|
||||
export { default as LeaveGroupModal } from '../components/modals/leaveGroup/LeaveGroupModal';
|
||||
|
||||
@ -254,7 +254,7 @@ const GroupCallParticipantVideo: FC<OwnProps & StateProps> = ({
|
||||
)}
|
||||
>
|
||||
{isLoading && (
|
||||
<Skeleton className={buildClassName(styles.video, styles.loader)} />
|
||||
<Skeleton className={buildClassName(styles.video, styles.loader)} animation="wave" />
|
||||
)}
|
||||
{stream && (
|
||||
<video
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
.root {
|
||||
padding: 0.25em 0.5em;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 1em;
|
||||
|
||||
font-size: 0.75rem;
|
||||
@ -12,6 +12,11 @@
|
||||
transition: 150ms filter ease-in;
|
||||
}
|
||||
|
||||
.plain {
|
||||
color: rgba(var(--color-text-meta-rgb), 0.75);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: var(--custom-cursor, pointer);
|
||||
|
||||
@ -19,3 +24,7 @@
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import type React from '../../lib/teact/teact';
|
||||
import { type TeactNode } from '../../lib/teact/teact';
|
||||
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
import styles from './BadgeButton.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
children: React.ReactNode;
|
||||
children: TeactNode;
|
||||
className?: string;
|
||||
isPlain?: boolean;
|
||||
inline?: boolean;
|
||||
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
};
|
||||
@ -14,12 +16,20 @@ type OwnProps = {
|
||||
const BadgeButton = ({
|
||||
children,
|
||||
className,
|
||||
isPlain,
|
||||
inline,
|
||||
onClick,
|
||||
onMouseDown,
|
||||
}: OwnProps) => {
|
||||
return (
|
||||
<div
|
||||
className={buildClassName(styles.root, onClick && styles.clickable, className)}
|
||||
className={buildClassName(
|
||||
styles.root,
|
||||
isPlain && styles.plain,
|
||||
onClick && styles.clickable,
|
||||
inline && styles.inline,
|
||||
className,
|
||||
)}
|
||||
onClick={onClick}
|
||||
onMouseDown={onMouseDown}
|
||||
>
|
||||
|
||||
132
src/components/common/PreviewBlock.module.scss
Normal file
132
src/components/common/PreviewBlock.module.scss
Normal file
@ -0,0 +1,132 @@
|
||||
.root {
|
||||
--preview-background-overscan: 50%;
|
||||
|
||||
isolation: isolate;
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
border-radius: 1.5rem;
|
||||
|
||||
background-color: var(--theme-background-color);
|
||||
}
|
||||
|
||||
.background {
|
||||
&::before,
|
||||
&::after {
|
||||
inset: calc(var(--preview-background-overscan) * -1);
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
min-height: 100%;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.message,
|
||||
.bubble {
|
||||
--preview-message-background: var(--color-background);
|
||||
--preview-message-sender-color: var(--accent-color);
|
||||
--preview-message-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
padding: 0.375rem 0.5rem 0.4375rem 0.625rem;
|
||||
border-radius: 1.125rem;
|
||||
|
||||
background: var(--preview-message-background);
|
||||
box-shadow: var(--preview-message-shadow);
|
||||
}
|
||||
|
||||
.message {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.messageWithAvatar {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: flex-end;
|
||||
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.bubble {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
user-select: none;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
min-width: 0;
|
||||
height: 1.25rem;
|
||||
margin-bottom: 0.375rem;
|
||||
|
||||
font-size: calc(var(--message-text-size, 1rem) - 0.125rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sender {
|
||||
overflow: hidden;
|
||||
flex: 0 1 auto;
|
||||
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--preview-message-sender-color);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0.5rem;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
margin-inline-start: 0.5rem;
|
||||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.375rem;
|
||||
|
||||
min-width: 0;
|
||||
|
||||
font-size: var(--message-text-size, 1rem);
|
||||
}
|
||||
|
||||
.footer {
|
||||
user-select: none;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 0.375rem;
|
||||
}
|
||||
|
||||
.time {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: flex-end;
|
||||
|
||||
font-size: 0.75rem;
|
||||
line-height: 1;
|
||||
color: rgba(var(--color-text-meta-rgb), 0.75);
|
||||
white-space: nowrap;
|
||||
}
|
||||
241
src/components/common/PreviewBlock.tsx
Normal file
241
src/components/common/PreviewBlock.tsx
Normal file
@ -0,0 +1,241 @@
|
||||
import type { FC, TeactNode } from '../../lib/teact/teact';
|
||||
import { memo } from '../../lib/teact/teact';
|
||||
import { withGlobal } from '../../global';
|
||||
|
||||
import type { ThemeKey } from '../../types';
|
||||
|
||||
import { selectTheme, selectThemeValues } from '../../global/selectors';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import buildStyle from '../../util/buildStyle';
|
||||
|
||||
import useCustomBackground from '../../hooks/useCustomBackground';
|
||||
|
||||
import backgroundStyles from '../../styles/_patternBackground.module.scss';
|
||||
import styles from './PreviewBlock.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
children: TeactNode;
|
||||
className?: string;
|
||||
style?: string;
|
||||
contentClassName?: string;
|
||||
backgroundClassName?: string;
|
||||
backgroundStyle?: string;
|
||||
backgroundColor?: string;
|
||||
patternColor?: string;
|
||||
customBackground?: string;
|
||||
isBackgroundBlurred?: boolean;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
theme: ThemeKey;
|
||||
themeBackgroundColor?: string;
|
||||
themePatternColor?: string;
|
||||
themeCustomBackground?: string;
|
||||
themeIsBackgroundBlurred?: boolean;
|
||||
};
|
||||
|
||||
type MessageProps = {
|
||||
children?: TeactNode;
|
||||
className?: string;
|
||||
style?: string;
|
||||
bubbleClassName?: string;
|
||||
bubbleStyle?: string;
|
||||
headerClassName?: string;
|
||||
bodyClassName?: string;
|
||||
footerClassName?: string;
|
||||
avatar?: TeactNode;
|
||||
sender?: TeactNode;
|
||||
badge?: TeactNode;
|
||||
footer?: TeactNode;
|
||||
time?: TeactNode;
|
||||
senderColor?: string;
|
||||
backgroundColor?: string;
|
||||
};
|
||||
|
||||
type MessageTimeProps = {
|
||||
children?: TeactNode;
|
||||
className?: string;
|
||||
style?: string;
|
||||
};
|
||||
|
||||
type PreviewBlockMessageComponent = FC<MessageProps> & {
|
||||
Time: FC<MessageTimeProps>;
|
||||
};
|
||||
|
||||
type PreviewBlockComponent = FC<OwnProps> & {
|
||||
Message: PreviewBlockMessageComponent;
|
||||
};
|
||||
|
||||
const PreviewBlockBase = ({
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
contentClassName,
|
||||
backgroundClassName,
|
||||
backgroundStyle,
|
||||
backgroundColor,
|
||||
patternColor,
|
||||
customBackground,
|
||||
isBackgroundBlurred,
|
||||
theme,
|
||||
themeBackgroundColor,
|
||||
themePatternColor,
|
||||
themeCustomBackground,
|
||||
themeIsBackgroundBlurred,
|
||||
}: OwnProps & StateProps) => {
|
||||
const resolvedBackgroundColor = backgroundColor ?? themeBackgroundColor;
|
||||
const resolvedPatternColor = patternColor ?? themePatternColor;
|
||||
const resolvedCustomBackground = customBackground ?? themeCustomBackground;
|
||||
const resolvedIsBackgroundBlurred = isBackgroundBlurred ?? themeIsBackgroundBlurred;
|
||||
const customBackgroundValue = useCustomBackground(theme, resolvedCustomBackground);
|
||||
|
||||
const backgroundClassNames = buildClassName(
|
||||
styles.background,
|
||||
backgroundStyles.background,
|
||||
resolvedCustomBackground && backgroundStyles.customBgImage,
|
||||
resolvedBackgroundColor && backgroundStyles.customBgColor,
|
||||
resolvedCustomBackground && resolvedIsBackgroundBlurred && backgroundStyles.blurred,
|
||||
backgroundClassName,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={buildClassName(styles.root, className)}
|
||||
style={buildStyle(
|
||||
resolvedPatternColor && `--pattern-color: ${resolvedPatternColor}`,
|
||||
resolvedBackgroundColor && `--theme-background-color: ${resolvedBackgroundColor}`,
|
||||
style,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={backgroundClassNames}
|
||||
style={buildStyle(
|
||||
customBackgroundValue && `--custom-background: ${customBackgroundValue}`,
|
||||
backgroundStyle,
|
||||
)}
|
||||
/>
|
||||
<div className={buildClassName(styles.content, contentClassName)}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const PreviewBlockMessage: FC<MessageProps> = ({
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
bubbleClassName,
|
||||
bubbleStyle,
|
||||
headerClassName,
|
||||
bodyClassName,
|
||||
footerClassName,
|
||||
avatar,
|
||||
sender,
|
||||
badge,
|
||||
footer,
|
||||
time,
|
||||
senderColor,
|
||||
backgroundColor,
|
||||
}) => {
|
||||
const hasAvatar = avatar !== undefined;
|
||||
const hasSender = sender !== undefined;
|
||||
const hasBadge = badge !== undefined;
|
||||
const hasChildren = children !== undefined;
|
||||
const hasFooterContent = footer !== undefined;
|
||||
const hasTime = time !== undefined;
|
||||
const hasHeader = hasSender || hasBadge;
|
||||
const hasFooter = hasFooterContent || hasTime;
|
||||
const bubbleStyles = buildStyle(
|
||||
senderColor && `--preview-message-sender-color: ${senderColor}`,
|
||||
backgroundColor && `--preview-message-background: ${backgroundColor}`,
|
||||
bubbleStyle,
|
||||
);
|
||||
const content = (
|
||||
<>
|
||||
{hasHeader ? (
|
||||
<div className={buildClassName(styles.header, headerClassName)}>
|
||||
{hasSender ? <span className={styles.sender}>{sender}</span> : undefined}
|
||||
<span className={styles.spacer} />
|
||||
{hasBadge ? <span className={styles.badge}>{badge}</span> : undefined}
|
||||
</div>
|
||||
) : undefined}
|
||||
{hasChildren ? (
|
||||
<div className={buildClassName(styles.body, bodyClassName)}>
|
||||
{children}
|
||||
</div>
|
||||
) : undefined}
|
||||
{hasFooter ? (
|
||||
<div className={buildClassName(styles.footer, footerClassName)}>
|
||||
{hasFooterContent ? footer : <PreviewBlockMessageTime>{time}</PreviewBlockMessageTime>}
|
||||
</div>
|
||||
) : undefined}
|
||||
</>
|
||||
);
|
||||
|
||||
if (hasAvatar) {
|
||||
return (
|
||||
<div
|
||||
className={buildClassName(styles.messageWithAvatar, className)}
|
||||
style={style}
|
||||
>
|
||||
<div className={styles.avatar}>{avatar}</div>
|
||||
<div
|
||||
className={buildClassName(styles.bubble, bubbleClassName)}
|
||||
style={bubbleStyles}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={buildClassName(styles.message, className, bubbleClassName)}
|
||||
style={buildStyle(
|
||||
senderColor && `--preview-message-sender-color: ${senderColor}`,
|
||||
backgroundColor && `--preview-message-background: ${backgroundColor}`,
|
||||
bubbleStyle,
|
||||
style,
|
||||
)}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const PreviewBlockMessageTime: FC<MessageTimeProps> = ({
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
}) => (
|
||||
<span className={buildClassName(styles.time, className)} style={style}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
const PreviewBlockMessageMemo = memo(PreviewBlockMessage) as PreviewBlockMessageComponent;
|
||||
PreviewBlockMessageMemo.Time = memo(PreviewBlockMessageTime);
|
||||
|
||||
const PreviewBlock = memo(withGlobal<OwnProps>((global) => {
|
||||
const theme = selectTheme(global);
|
||||
const {
|
||||
isBlurred: themeIsBackgroundBlurred,
|
||||
background: themeCustomBackground,
|
||||
backgroundColor: themeBackgroundColor,
|
||||
patternColor: themePatternColor,
|
||||
} = selectThemeValues(global, theme) || {};
|
||||
|
||||
return {
|
||||
theme,
|
||||
themeBackgroundColor,
|
||||
themePatternColor,
|
||||
themeCustomBackground,
|
||||
themeIsBackgroundBlurred,
|
||||
};
|
||||
})(PreviewBlockBase)) as PreviewBlockComponent;
|
||||
|
||||
PreviewBlock.Message = PreviewBlockMessageMemo;
|
||||
|
||||
export default PreviewBlock;
|
||||
@ -19,6 +19,7 @@ import {
|
||||
} from '../../global/selectors';
|
||||
import { selectThreadMessagesCount } from '../../global/selectors/threads';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { hasRank } from './helpers/chatMember';
|
||||
import { REM } from './helpers/mediaDimensions';
|
||||
import renderText from './helpers/renderText';
|
||||
|
||||
@ -33,6 +34,7 @@ import Avatar from './Avatar';
|
||||
import DotAnimation from './DotAnimation';
|
||||
import FullNameTitle from './FullNameTitle';
|
||||
import Icon from './icons/Icon';
|
||||
import RankBadge from './RankBadge';
|
||||
import TopicIcon from './TopicIcon';
|
||||
import TypingStatus from './TypingStatus';
|
||||
|
||||
@ -58,7 +60,8 @@ type BaseOwnProps = {
|
||||
emojiStatusSize?: number;
|
||||
noStatusOrTyping?: boolean;
|
||||
noRtl?: boolean;
|
||||
adminMember?: ApiChatMember;
|
||||
chatMemberOriginId?: string;
|
||||
chatMember?: ApiChatMember;
|
||||
isSavedDialog?: boolean;
|
||||
noAvatar?: boolean;
|
||||
className?: string;
|
||||
@ -118,7 +121,8 @@ const PrivateChatInfo = ({
|
||||
isSavedMessages,
|
||||
isSavedDialog,
|
||||
areMessagesLoaded,
|
||||
adminMember,
|
||||
chatMember,
|
||||
chatMemberOriginId,
|
||||
ripple,
|
||||
className,
|
||||
storyViewerOrigin,
|
||||
@ -237,10 +241,6 @@ const PrivateChatInfo = ({
|
||||
);
|
||||
}
|
||||
|
||||
const customTitle = adminMember
|
||||
? adminMember.customTitle || oldLang(adminMember.isOwner ? 'GroupInfo.LabelOwner' : 'GroupInfo.LabelAdmin')
|
||||
: undefined;
|
||||
|
||||
function renderNameTitle() {
|
||||
if (isTopic) {
|
||||
return (
|
||||
@ -248,18 +248,27 @@ const PrivateChatInfo = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (customTitle) {
|
||||
if (chatMember && hasRank(chatMember)) {
|
||||
return (
|
||||
<div className="info-name-title">
|
||||
<FullNameTitle
|
||||
peer={user!}
|
||||
peer={customPeer || user!}
|
||||
noFake={noFake}
|
||||
noVerified={noVerified}
|
||||
withEmojiStatus={!noEmojiStatus}
|
||||
emojiStatusSize={emojiStatusSize}
|
||||
isSavedMessages={isSavedMessages}
|
||||
isSavedDialog={isSavedDialog}
|
||||
iconElement={iconElement}
|
||||
onEmojiStatusClick={onEmojiStatusClick}
|
||||
/>
|
||||
{customTitle && <span className="custom-title">{customTitle}</span>}
|
||||
<RankBadge
|
||||
chatId={chatMemberOriginId!}
|
||||
userId={chatMember.userId}
|
||||
isAdmin={chatMember.isAdmin}
|
||||
isOwner={chatMember.isOwner}
|
||||
rank={chatMember.rank}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
58
src/components/common/RankBadge.tsx
Normal file
58
src/components/common/RankBadge.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { memo } from '@teact';
|
||||
import { getActions } from '../../global';
|
||||
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import { getPeerColorClass } from '../../hooks/usePeerColor';
|
||||
|
||||
import BadgeButton from './BadgeButton';
|
||||
|
||||
type OwnProps = {
|
||||
chatId: string;
|
||||
userId: string;
|
||||
isAdmin?: boolean;
|
||||
isOwner?: boolean;
|
||||
className?: string;
|
||||
rank?: string;
|
||||
isClickable?: boolean;
|
||||
};
|
||||
|
||||
const OWNER_PEER_COLOR = 2;
|
||||
const ADMIN_PEER_COLOR = 3;
|
||||
|
||||
const RankBadge = ({
|
||||
chatId, className, userId, isAdmin, isOwner, rank, isClickable,
|
||||
}: OwnProps) => {
|
||||
const { openRankModal } = getActions();
|
||||
const lang = useLang();
|
||||
const hasCustomColor = isOwner || isAdmin;
|
||||
|
||||
const rankText = rank || (isOwner && lang('ChannelCreator')) || (isAdmin && lang('ChannelAdmin'));
|
||||
|
||||
const handleClick = useLastCallback(() => {
|
||||
if (!chatId) return;
|
||||
openRankModal({ chatId, userId, isAdmin, isOwner, rank });
|
||||
});
|
||||
|
||||
if (!rankText) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<BadgeButton
|
||||
className={buildClassName(
|
||||
hasCustomColor && getPeerColorClass(isOwner ? OWNER_PEER_COLOR : ADMIN_PEER_COLOR),
|
||||
className,
|
||||
)}
|
||||
isPlain={!hasCustomColor}
|
||||
inline
|
||||
onClick={isClickable ? handleClick : undefined}
|
||||
>
|
||||
{rankText}
|
||||
</BadgeButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(RankBadge);
|
||||
5
src/components/common/helpers/chatMember.ts
Normal file
5
src/components/common/helpers/chatMember.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import type { ApiChatMember } from '../../../api/types';
|
||||
|
||||
export function hasRank(member?: ApiChatMember): boolean {
|
||||
return Boolean(member && (member.rank || member.isOwner || member.isAdmin));
|
||||
}
|
||||
@ -201,7 +201,7 @@ const ChatExtra = ({
|
||||
return <img src={locationBlobUrl} alt="" className={styles.businessLocation} />;
|
||||
}
|
||||
|
||||
return <Skeleton className={styles.businessLocation} />;
|
||||
return <Skeleton className={styles.businessLocation} animation="wave" />;
|
||||
}, [businessLocation, locationBlobUrl]);
|
||||
|
||||
const isTopicInfo = Boolean(topicId && topicId !== MAIN_THREAD_ID);
|
||||
|
||||
@ -249,6 +249,17 @@ const PermissionCheckboxList = ({
|
||||
onChange={handlePermissionChange}
|
||||
/>
|
||||
</div>
|
||||
<div className={buildClassName('ListItem', withCheckbox && 'with-checkbox')}>
|
||||
<Checkbox
|
||||
name="editRank"
|
||||
checked={!permissions.editRank}
|
||||
label={lang('UserRestrictionsEditRank')}
|
||||
blocking
|
||||
permissionGroup={permissionGroup}
|
||||
onChange={handlePermissionChange}
|
||||
disabled={getControlIsDisabled && getControlIsDisabled('editRank')}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={buildClassName('ListItem', withCheckbox && 'with-checkbox')}
|
||||
onClick={shouldDisablePermissionForPublicGroup ? handleDisabledClick : undefined}
|
||||
|
||||
@ -208,6 +208,7 @@ const MessageListAccountInfo: FC<OwnProps & StateProps> = ({
|
||||
width={width}
|
||||
height={height}
|
||||
forceAspectRatio
|
||||
animation="pulse"
|
||||
/>
|
||||
)}
|
||||
{isVerifyCodes && (
|
||||
|
||||
@ -57,7 +57,7 @@ const Game: FC<OwnProps> = ({
|
||||
onClick={handleGameClick}
|
||||
>
|
||||
{!photoBlobUrl && !videoBlobUrl && (
|
||||
<Skeleton className="skeleton preview-content" />
|
||||
<Skeleton className="skeleton preview-content" animation="pulse" />
|
||||
)}
|
||||
{photoBlobUrl && (
|
||||
<img
|
||||
|
||||
@ -116,6 +116,7 @@ const Invoice: FC<OwnProps> = ({
|
||||
width={width}
|
||||
height={photo.dimensions?.height}
|
||||
forceAspectRatio
|
||||
animation="pulse"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -24,7 +24,7 @@ function LastEditTimeMenuItem({
|
||||
|
||||
return (
|
||||
<MenuItem icon="clock-edit" className={styles.item}>
|
||||
{shouldRenderSkeleton ? <Skeleton className={styles.skeleton} /> : Boolean(editDate)
|
||||
{shouldRenderSkeleton ? <Skeleton className={styles.skeleton} animation="wave" /> : Boolean(editDate)
|
||||
&& lang('Chat.PrivateMessageEditTimestamp.Date', formatDateAtTime(lang, editDate * 1000))}
|
||||
</MenuItem>
|
||||
);
|
||||
|
||||
@ -184,7 +184,7 @@ const Location: FC<OwnProps> = ({
|
||||
}
|
||||
|
||||
function renderMap() {
|
||||
if (!mapBlobUrl) return <Skeleton width={width} height={height} />;
|
||||
if (!mapBlobUrl) return <Skeleton width={width} height={height} animation="pulse" />;
|
||||
return (
|
||||
<img
|
||||
className="full-media map"
|
||||
|
||||
@ -174,6 +174,7 @@ import Icon from '../../common/icons/Icon';
|
||||
import StarIcon from '../../common/icons/StarIcon';
|
||||
import MessageText from '../../common/MessageText';
|
||||
import PeerColorWrapper from '../../common/PeerColorWrapper';
|
||||
import RankBadge from '../../common/RankBadge';
|
||||
import ReactionStaticEmoji from '../../common/reactions/ReactionStaticEmoji';
|
||||
import Sparkles from '../../common/Sparkles';
|
||||
import TopicChip from '../../common/TopicChip';
|
||||
@ -302,7 +303,7 @@ type StateProps = {
|
||||
isTranscribing?: boolean;
|
||||
transcribedText?: string;
|
||||
isPremium: boolean;
|
||||
senderAdminMember?: ApiChatMember;
|
||||
senderChatMember?: ApiChatMember;
|
||||
messageTopic?: ApiTopic;
|
||||
hasTopicChip?: boolean;
|
||||
chatTranslations?: ChatTranslatedMessages;
|
||||
@ -429,7 +430,7 @@ const Message = ({
|
||||
repliesThreadInfo,
|
||||
hasUnreadReaction,
|
||||
memoFirstUnreadIdRef,
|
||||
senderAdminMember,
|
||||
senderChatMember,
|
||||
messageTopic,
|
||||
hasTopicChip,
|
||||
chatTranslations,
|
||||
@ -542,7 +543,7 @@ const Message = ({
|
||||
|
||||
const {
|
||||
id: messageId, chatId, forwardInfo, viaBotId, isTranscriptionError, factCheck,
|
||||
isTypingDraft,
|
||||
isTypingDraft, fromRank,
|
||||
} = message;
|
||||
const hasSummary = Boolean(message.summaryLanguageCode);
|
||||
|
||||
@ -1677,7 +1678,6 @@ const Message = ({
|
||||
const senderIsPremium = senderPeer && 'isPremium' in senderPeer && senderPeer.isPremium;
|
||||
|
||||
const shouldRenderForwardAvatar = asForwarded && senderPeer;
|
||||
const hasBotSenderUsername = botSender?.hasUsername;
|
||||
return (
|
||||
<div className="message-title" dir="ltr">
|
||||
{(senderTitle || asForwarded) ? (
|
||||
@ -1733,16 +1733,20 @@ const Message = ({
|
||||
</span>
|
||||
)}
|
||||
<div className="title-spacer" />
|
||||
{!shouldSkipRenderAdminTitle && !hasBotSenderUsername ? (forwardInfo?.isLinkedChannelPost ? (
|
||||
{(!shouldSkipRenderAdminTitle && !signature) ? (forwardInfo?.isLinkedChannelPost ? (
|
||||
<span className="admin-title" dir="auto">{oldLang('DiscussChannel')}</span>
|
||||
) : message.postAuthorTitle && isGroup && !asForwarded ? (
|
||||
<span className="admin-title" dir="auto">{message.postAuthorTitle}</span>
|
||||
) : senderAdminMember && !asForwarded && !viaBotId ? (
|
||||
<span className="admin-title" dir="auto">
|
||||
{senderAdminMember.customTitle || oldLang(
|
||||
senderAdminMember.isOwner ? 'GroupInfo.LabelOwner' : 'GroupInfo.LabelAdmin',
|
||||
)}
|
||||
</span>
|
||||
) : (senderChatMember || fromRank) && !asForwarded ? (
|
||||
<RankBadge
|
||||
chatId={chatId}
|
||||
userId={(senderChatMember?.userId || sender?.id)!}
|
||||
isAdmin={senderChatMember?.isAdmin}
|
||||
isOwner={senderChatMember?.isOwner}
|
||||
rank={senderChatMember?.rank || fromRank}
|
||||
className="admin-title-badge"
|
||||
isClickable
|
||||
/>
|
||||
) : undefined) : undefined}
|
||||
{canShowSenderBoosts && (
|
||||
<span className="sender-boosts" aria-hidden>
|
||||
@ -2020,6 +2024,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isChannel = chat && isChatChannel(chat);
|
||||
const isGroup = chat && isChatGroup(chat);
|
||||
const chatFullInfo = !isChatWithUser ? selectChatFullInfo(global, chatId) : undefined;
|
||||
const { adminMembersById, members, boostsApplied } = chatFullInfo || {};
|
||||
const webPageStoryData = webPage?.story;
|
||||
const webPageStory = webPageStoryData
|
||||
? selectPeerStory(global, webPageStoryData.peerId, webPageStoryData.id)
|
||||
@ -2031,8 +2036,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
const sender = selectSender(global, message);
|
||||
const originSender = selectForwardedSender(global, message);
|
||||
const botSender = viaBotId ? selectUser(global, viaBotId) : undefined;
|
||||
const senderAdminMember = sender?.id && isGroup
|
||||
? chatFullInfo?.adminMembersById?.[sender?.id]
|
||||
const senderChatMember = sender?.id
|
||||
? (adminMembersById?.[sender?.id] || members?.find((member) => member.userId === sender?.id))
|
||||
: undefined;
|
||||
|
||||
const isThreadTop = message.id === threadId;
|
||||
@ -2119,7 +2124,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
const isPremium = selectIsCurrentUserPremium(global);
|
||||
const senderBoosts = sender && selectIsChatWithSelf(global, sender.id)
|
||||
? (chatFullInfo?.boostsApplied ?? message.senderBoosts) : message.senderBoosts;
|
||||
? (boostsApplied ?? message.senderBoosts) : message.senderBoosts;
|
||||
|
||||
const chatLevel = chat?.boostLevel || 0;
|
||||
const transcribeMinLevel = global.appConfig.groupTranscribeLevelMin;
|
||||
@ -2202,7 +2207,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
isTranscribing: transcriptionId !== undefined && global.transcriptions[transcriptionId]?.isPending,
|
||||
transcribedText: transcriptionId !== undefined ? global.transcriptions[transcriptionId]?.text : undefined,
|
||||
isPremium,
|
||||
senderAdminMember,
|
||||
senderChatMember,
|
||||
messageTopic,
|
||||
hasTopicChip,
|
||||
chatTranslations,
|
||||
|
||||
@ -462,8 +462,8 @@ const MessageContextMenu: FC<OwnProps> = ({
|
||||
<MenuSeparator size="thick" />
|
||||
{!customEmojiSets && (
|
||||
<>
|
||||
<Skeleton inline className="menu-loading-row" />
|
||||
<Skeleton inline className="menu-loading-row" />
|
||||
<Skeleton inline className="menu-loading-row" animation="wave" />
|
||||
<Skeleton inline className="menu-loading-row" animation="wave" />
|
||||
</>
|
||||
)}
|
||||
{customEmojiSets && customEmojiSets.length === 1 && (
|
||||
|
||||
@ -36,7 +36,7 @@ function ReadTimeMenuItem({
|
||||
return (
|
||||
<MenuItem icon="message-read" className={styles.item}>
|
||||
<Transition name="fade" activeKey={shouldRenderSkeleton ? 1 : 2} className={styles.transition}>
|
||||
{shouldRenderSkeleton ? <Skeleton className={styles.skeleton} /> : (
|
||||
{shouldRenderSkeleton ? <Skeleton className={styles.skeleton} animation="wave" /> : (
|
||||
<>
|
||||
{Boolean(readDate) && lang('PmReadAt', formatDateAtTime(lang, readDate * 1000))}
|
||||
{!readDate && shouldRenderShowWhen && (
|
||||
|
||||
@ -154,7 +154,7 @@ const SimilarChannels = ({
|
||||
|
||||
return (
|
||||
<div className={buildClassName(styles.root)}>
|
||||
{shouldRenderSkeleton && <Skeleton className={styles.skeleton} />}
|
||||
{shouldRenderSkeleton && <Skeleton className={styles.skeleton} animation="wave" />}
|
||||
{shouldRenderChannels && (
|
||||
<div
|
||||
className={buildClassName(
|
||||
|
||||
@ -303,7 +303,6 @@
|
||||
user-select: none;
|
||||
|
||||
unicode-bidi: plaintext;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
font-size: calc(var(--message-text-size, 1rem) - 0.125rem);
|
||||
@ -399,11 +398,12 @@
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.admin-title {
|
||||
.admin-title-badge, .admin-title {
|
||||
user-select: none;
|
||||
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.admin-title {
|
||||
font-size: 0.75rem;
|
||||
font-weight: var(--font-weight-normal);
|
||||
color: rgba(var(--color-text-meta-rgb), 0.75);
|
||||
@ -414,6 +414,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.admin-title-badge {
|
||||
margin-right: -0.1875rem;
|
||||
}
|
||||
|
||||
.sender-boosts {
|
||||
user-select: none;
|
||||
|
||||
@ -540,23 +544,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.voice,
|
||||
&.audio,
|
||||
&.document {
|
||||
.text-content {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.voice,
|
||||
&.audio {
|
||||
.message-title,
|
||||
.Embedded {
|
||||
margin-top: -0.1875rem;
|
||||
margin-bottom: 0.1875rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.audio {
|
||||
min-width: 20rem;
|
||||
|
||||
|
||||
@ -58,6 +58,8 @@ import PriceConfirmModal from './priceConfirm/PriceConfirmModal.async';
|
||||
import ProfileRatingModal from './profileRating/ProfileRatingModal.async';
|
||||
import QuickChatPickerModal from './quickChatPicker/QuickChatPickerModal.async';
|
||||
import QuickPreviewModal from './quickPreview/QuickPreviewModal.async';
|
||||
import EditRankModal from './rank/EditRankModal.async';
|
||||
import RankModal from './rank/RankModal.async';
|
||||
import ReportAdModal from './reportAd/ReportAdModal.async';
|
||||
import ReportModal from './reportModal/ReportModal.async';
|
||||
import SharePreparedMessageModal from './sharePreparedMessage/SharePreparedMessageModal.async';
|
||||
@ -144,7 +146,9 @@ type ModalKey = keyof Pick<TabState,
|
||||
'leaveGroupModal' |
|
||||
'isTwoFaCheckModalOpen' |
|
||||
'isQuickChatPickerOpen' |
|
||||
'isCocoonModalOpen'
|
||||
'isCocoonModalOpen' |
|
||||
'editRankModal' |
|
||||
'rankModal'
|
||||
>;
|
||||
|
||||
type StateProps = {
|
||||
@ -228,6 +232,8 @@ const MODALS: ModalRegistry = {
|
||||
isTwoFaCheckModalOpen: TwoFaCheckModal,
|
||||
isQuickChatPickerOpen: QuickChatPickerModal,
|
||||
isCocoonModalOpen: CocoonModal,
|
||||
editRankModal: EditRankModal,
|
||||
rankModal: RankModal,
|
||||
};
|
||||
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
||||
const MODAL_ENTRIES = Object.entries(MODALS) as Entries<ModalRegistry>;
|
||||
|
||||
14
src/components/modals/rank/EditRankModal.async.tsx
Normal file
14
src/components/modals/rank/EditRankModal.async.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import type { OwnProps } from './EditRankModal';
|
||||
|
||||
import { Bundles } from '../../../util/moduleLoader';
|
||||
|
||||
import useModuleLoader from '../../../hooks/useModuleLoader';
|
||||
|
||||
const EditRankModalAsync = (props: OwnProps) => {
|
||||
const { modal } = props;
|
||||
const EditRankModal = useModuleLoader(Bundles.Extra, 'EditRankModal', !modal);
|
||||
|
||||
return EditRankModal ? <EditRankModal {...props} /> : undefined;
|
||||
};
|
||||
|
||||
export default EditRankModalAsync;
|
||||
31
src/components/modals/rank/EditRankModal.module.scss
Normal file
31
src/components/modals/rank/EditRankModal.module.scss
Normal file
@ -0,0 +1,31 @@
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.previewMessage {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.previewBlock {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.previewRankBadge {
|
||||
max-width: 10rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.previewLine {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
177
src/components/modals/rank/EditRankModal.tsx
Normal file
177
src/components/modals/rank/EditRankModal.tsx
Normal file
@ -0,0 +1,177 @@
|
||||
import { memo, useEffect, useState } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiChat, ApiUser } from '../../../api/types';
|
||||
import type { TabState } from '../../../global/types';
|
||||
|
||||
import { getUserFirstOrLastName } from '../../../global/helpers';
|
||||
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||
import { selectCanEditRank, selectChat, selectUser } from '../../../global/selectors';
|
||||
|
||||
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
|
||||
import Avatar from '../../common/Avatar';
|
||||
import PreviewBlock from '../../common/PreviewBlock';
|
||||
import RankBadge from '../../common/RankBadge';
|
||||
import Button from '../../ui/Button';
|
||||
import InputText from '../../ui/InputText';
|
||||
import Modal from '../../ui/Modal';
|
||||
import Skeleton from '../../ui/placeholder/Skeleton';
|
||||
|
||||
import styles from './EditRankModal.module.scss';
|
||||
|
||||
export type OwnProps = {
|
||||
modal: TabState['editRankModal'];
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
user?: ApiUser;
|
||||
chat?: ApiChat;
|
||||
canEditRank?: boolean;
|
||||
isOwn?: boolean;
|
||||
};
|
||||
|
||||
const MAX_RANK_LENGTH = 16;
|
||||
const PREVIEW_TIME = '9:37';
|
||||
|
||||
const EditRankModal = ({
|
||||
modal, user, chat, canEditRank, isOwn,
|
||||
}: OwnProps & StateProps) => {
|
||||
const { closeEditRankModal, editChatParticipantRank } = getActions();
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const isOpen = Boolean(modal);
|
||||
const renderingModal = useCurrentOrPrev(modal);
|
||||
const [rank, setRank] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
setRank((renderingModal?.rank || '').slice(0, MAX_RANK_LENGTH));
|
||||
}, [renderingModal?.chatId, renderingModal?.rank, renderingModal?.userId, isOpen]);
|
||||
|
||||
const handleClose = useLastCallback(() => {
|
||||
closeEditRankModal();
|
||||
});
|
||||
|
||||
const handleInputChange = useLastCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setRank(e.target.value);
|
||||
});
|
||||
|
||||
const {
|
||||
userId, chatId, isAdmin, isOwner,
|
||||
} = renderingModal || {};
|
||||
const initialRank = (renderingModal?.rank || '').slice(0, MAX_RANK_LENGTH);
|
||||
const shouldShowBadge = Boolean(rank || isAdmin || isOwner);
|
||||
const isSubmitDisabled = !canEditRank || rank === initialRank;
|
||||
|
||||
const handleSubmit = useLastCallback(() => {
|
||||
if (isSubmitDisabled) return;
|
||||
|
||||
if (!chatId || !userId) return;
|
||||
|
||||
editChatParticipantRank({
|
||||
chatId,
|
||||
userId,
|
||||
rank,
|
||||
});
|
||||
|
||||
handleClose();
|
||||
});
|
||||
|
||||
const handleKeyDown = useLastCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key !== 'Enter') return;
|
||||
|
||||
e.preventDefault();
|
||||
handleSubmit();
|
||||
});
|
||||
|
||||
if (!chatId || !userId) return undefined;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
title={lang(isOwn ? 'RankModalEditMy' : 'RankModalEdit')}
|
||||
contentClassName={styles.content}
|
||||
isSlim
|
||||
hasCloseButton
|
||||
onClose={handleClose}
|
||||
>
|
||||
<PreviewBlock className={styles.previewBlock} contentClassName={styles.previewBlockContent}>
|
||||
<PreviewBlock.Message
|
||||
className={styles.previewMessage}
|
||||
avatar={user ? <Avatar peer={user} size="small" /> : undefined}
|
||||
sender={user && getPeerTitle(lang, user)}
|
||||
badge={shouldShowBadge ? (
|
||||
<RankBadge
|
||||
chatId={chatId}
|
||||
userId={userId}
|
||||
className={styles.previewRankBadge}
|
||||
isAdmin={isAdmin}
|
||||
isOwner={isOwner}
|
||||
rank={rank || undefined}
|
||||
/>
|
||||
) : undefined}
|
||||
time={PREVIEW_TIME}
|
||||
>
|
||||
{renderPreviewContent()}
|
||||
</PreviewBlock.Message>
|
||||
</PreviewBlock>
|
||||
|
||||
<InputText
|
||||
id="edit-rank"
|
||||
label={lang('EditAdminRank')}
|
||||
className={styles.input}
|
||||
value={rank}
|
||||
maxLength={MAX_RANK_LENGTH}
|
||||
disabled={!chat || !user || !canEditRank}
|
||||
teactExperimentControlled
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<p className={styles.description}>
|
||||
{isOwn ? lang('RankEditTextOwn') : lang('RankEditText', {
|
||||
user: user && getUserFirstOrLastName(user),
|
||||
})}
|
||||
</p>
|
||||
|
||||
<Button
|
||||
disabled={isSubmitDisabled}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{lang('RankEditSave')}
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
function renderPreviewContent() {
|
||||
return (
|
||||
<>
|
||||
<span className={styles.previewLine}>
|
||||
<Skeleton variant="rounded-rect" height={10} inline />
|
||||
</span>
|
||||
<span className={styles.previewLine}>
|
||||
<Skeleton variant="rounded-rect" width={128} height={10} inline />
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global, { modal }): StateProps => {
|
||||
return {
|
||||
user: modal?.userId ? selectUser(global, modal.userId) : undefined,
|
||||
chat: modal?.chatId ? selectChat(global, modal.chatId) : undefined,
|
||||
canEditRank: modal && selectCanEditRank(global, {
|
||||
chatId: modal.chatId,
|
||||
userId: modal.userId,
|
||||
isAdmin: modal.isAdmin,
|
||||
isOwner: modal.isOwner,
|
||||
}),
|
||||
isOwn: modal && modal.userId === global.currentUserId,
|
||||
};
|
||||
},
|
||||
)(EditRankModal));
|
||||
14
src/components/modals/rank/RankModal.async.tsx
Normal file
14
src/components/modals/rank/RankModal.async.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import type { OwnProps } from './RankModal';
|
||||
|
||||
import { Bundles } from '../../../util/moduleLoader';
|
||||
|
||||
import useModuleLoader from '../../../hooks/useModuleLoader';
|
||||
|
||||
const RankModalAsync = (props: OwnProps) => {
|
||||
const { modal } = props;
|
||||
const RankModal = useModuleLoader(Bundles.Extra, 'RankModal', !modal);
|
||||
|
||||
return RankModal ? <RankModal {...props} /> : undefined;
|
||||
};
|
||||
|
||||
export default RankModalAsync;
|
||||
102
src/components/modals/rank/RankModal.module.scss
Normal file
102
src/components/modals/rank/RankModal.module.scss
Normal file
@ -0,0 +1,102 @@
|
||||
@use "../../../styles/mixins";
|
||||
|
||||
.root {
|
||||
:global(.modal-dialog) {
|
||||
overflow: hidden;
|
||||
width: 26.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 1rem 1rem !important;
|
||||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
|
||||
padding-top: 2rem;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.previewGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.previewBlockContent {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.previewMessage {
|
||||
--preview-crop-left: 1.5rem;
|
||||
--preview-crop-fade-width: 1.5rem;
|
||||
|
||||
@include mixins.gradient-border-left(
|
||||
calc(var(--preview-crop-left) + var(--preview-crop-fade-width)),
|
||||
0.75rem
|
||||
);
|
||||
|
||||
width: calc(100% + var(--preview-crop-left));
|
||||
max-width: none;
|
||||
margin-top: auto;
|
||||
margin-left: calc(var(--preview-crop-left) * -1);
|
||||
}
|
||||
|
||||
.previewLine,
|
||||
.previewMetaLine {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.previewMetaLine {
|
||||
gap: 0.375rem;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.memberTag {
|
||||
padding: 0.25rem 0.625rem;
|
||||
border-radius: 999px;
|
||||
|
||||
font-size: 0.75rem;
|
||||
line-height: 1;
|
||||
color: rgba(var(--color-text-meta-rgb), 0.8);
|
||||
|
||||
background: rgb(var(--color-text-meta-rgb) / 12%);
|
||||
}
|
||||
|
||||
.previewRankBadge {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
align-self: stretch;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.understoodIcon {
|
||||
font-size: 1.1875rem;
|
||||
}
|
||||
|
||||
.topIcon {
|
||||
display: grid;
|
||||
flex-shrink: 0;
|
||||
place-items: center;
|
||||
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
border-radius: 50%;
|
||||
|
||||
font-size: 4rem;
|
||||
color: var(--color-white);
|
||||
|
||||
background: var(--color-primary);
|
||||
}
|
||||
190
src/components/modals/rank/RankModal.tsx
Normal file
190
src/components/modals/rank/RankModal.tsx
Normal file
@ -0,0 +1,190 @@
|
||||
import { memo, useMemo } from '@teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiChat, ApiChatMember, ApiUser } from '../../../api/types';
|
||||
import type { TabState } from '../../../global/types';
|
||||
|
||||
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||
import {
|
||||
selectCanEditOwnRank, selectCanEditRank, selectChat, selectChatFullInfo, selectUser,
|
||||
} from '../../../global/selectors';
|
||||
|
||||
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import PreviewBlock from '../../common/PreviewBlock';
|
||||
import RankBadge from '../../common/RankBadge';
|
||||
import Button from '../../ui/Button';
|
||||
import Modal from '../../ui/Modal';
|
||||
import Skeleton from '../../ui/placeholder/Skeleton';
|
||||
|
||||
import styles from './RankModal.module.scss';
|
||||
|
||||
export type OwnProps = {
|
||||
modal: TabState['rankModal'];
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
user?: ApiUser;
|
||||
chat?: ApiChat;
|
||||
canEditRank?: boolean;
|
||||
canEditOwnRank?: boolean;
|
||||
currentUserMember?: ApiChatMember;
|
||||
};
|
||||
|
||||
const PLACEHOLDER_ID = 'placeholder';
|
||||
|
||||
const RankModal = ({
|
||||
modal, user, chat, canEditRank, canEditOwnRank, currentUserMember,
|
||||
}: OwnProps & StateProps) => {
|
||||
const { closeRankModal, openEditRankModal } = getActions();
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const isOpen = Boolean(modal);
|
||||
const renderingModal = useCurrentOrPrev(modal);
|
||||
const isOwn = renderingModal?.userId === currentUserMember?.userId;
|
||||
|
||||
const handleClose = useLastCallback(() => {
|
||||
closeRankModal();
|
||||
});
|
||||
|
||||
const handleActionClick = useLastCallback(() => {
|
||||
if (!renderingModal) return;
|
||||
if (canEditRank) {
|
||||
openEditRankModal(renderingModal);
|
||||
} else if (canEditOwnRank && currentUserMember) {
|
||||
openEditRankModal({
|
||||
chatId: renderingModal.chatId,
|
||||
userId: currentUserMember.userId,
|
||||
isAdmin: currentUserMember.isAdmin,
|
||||
isOwner: currentUserMember.isOwner,
|
||||
rank: currentUserMember.rank,
|
||||
});
|
||||
}
|
||||
|
||||
closeRankModal();
|
||||
});
|
||||
|
||||
const mainButtonText = useMemo(() => {
|
||||
if (canEditRank) return isOwn ? lang('RankModalEditMy') : lang('RankModalEdit');
|
||||
if (canEditOwnRank) return lang('RankModalEditMy');
|
||||
return lang('ButtonUnderstood');
|
||||
}, [canEditRank, canEditOwnRank, isOwn, lang]);
|
||||
|
||||
if (!renderingModal) return undefined;
|
||||
|
||||
const { userId, chatId, isAdmin, isOwner, rank } = renderingModal;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
className={styles.root}
|
||||
contentClassName={styles.content}
|
||||
hasAbsoluteCloseButton
|
||||
onClose={handleClose}
|
||||
>
|
||||
<div className={styles.body}>
|
||||
<div className={styles.topIcon}>
|
||||
<Icon name="user-tag" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={styles.previewTitle}>
|
||||
{lang(
|
||||
isOwner ? 'RankModalOwnerTagTitle' : isAdmin ? 'RankModalAdminTagTitle' : 'RankModalMemberTagTitle',
|
||||
)}
|
||||
</h3>
|
||||
<div className={styles.previewText}>
|
||||
{lang(
|
||||
isOwner ? 'RankModalOwnerText' : isAdmin ? 'RankModalAdminText' : 'RankModalMemberText',
|
||||
{
|
||||
tag: <RankBadge chatId={chatId} userId={userId} isAdmin={isAdmin} isOwner={isOwner} rank={rank} />,
|
||||
author: user && getPeerTitle(lang, user),
|
||||
group: chat && getPeerTitle(lang, chat),
|
||||
},
|
||||
{ withNodes: true, withMarkdown: true },
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.previewGrid}>
|
||||
<PreviewBlock contentClassName={styles.previewBlockContent}>
|
||||
<PreviewBlock.Message
|
||||
className={styles.previewMessage}
|
||||
badge={(
|
||||
<RankBadge
|
||||
chatId={PLACEHOLDER_ID}
|
||||
userId={PLACEHOLDER_ID}
|
||||
className={styles.previewRankBadge}
|
||||
rank={lang('RankMemberTag')}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
{renderPreviewContent()}
|
||||
</PreviewBlock.Message>
|
||||
</PreviewBlock>
|
||||
<PreviewBlock contentClassName={styles.previewBlockContent}>
|
||||
<PreviewBlock.Message
|
||||
className={styles.previewMessage}
|
||||
badge={(
|
||||
<RankBadge
|
||||
className={styles.previewRankBadge}
|
||||
chatId={PLACEHOLDER_ID}
|
||||
userId={PLACEHOLDER_ID}
|
||||
isAdmin
|
||||
rank={lang('RankAdminTag')}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
{renderPreviewContent()}
|
||||
</PreviewBlock.Message>
|
||||
</PreviewBlock>
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<Button
|
||||
iconName={!canEditRank ? 'understood' : undefined}
|
||||
iconClassName={styles.understoodIcon}
|
||||
onClick={handleActionClick}
|
||||
>
|
||||
{mainButtonText}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
function renderPreviewContent() {
|
||||
return (
|
||||
<>
|
||||
<span className={styles.previewLine}>
|
||||
<Skeleton variant="rounded-rect" width={168} height={10} inline />
|
||||
</span>
|
||||
<span className={styles.previewMetaLine}>
|
||||
<Skeleton variant="rounded-rect" width={104} height={10} inline />
|
||||
<PreviewBlock.Message.Time>9:37</PreviewBlock.Message.Time>
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global, { modal }): StateProps => {
|
||||
const chatFullInfo = modal?.chatId ? selectChatFullInfo(global, modal.chatId) : undefined;
|
||||
const currentUserMember = chatFullInfo?.adminMembersById?.[global.currentUserId!]
|
||||
|| chatFullInfo?.members?.find((member) => member.userId === global.currentUserId);
|
||||
return {
|
||||
user: modal?.userId ? selectUser(global, modal.userId) : undefined,
|
||||
chat: modal?.chatId ? selectChat(global, modal.chatId) : undefined,
|
||||
canEditRank: modal && selectCanEditRank(global, {
|
||||
chatId: modal.chatId,
|
||||
userId: modal.userId,
|
||||
isAdmin: modal.isAdmin,
|
||||
isOwner: modal.isOwner,
|
||||
}),
|
||||
canEditOwnRank: modal && selectCanEditOwnRank(global, modal.chatId),
|
||||
currentUserMember,
|
||||
};
|
||||
},
|
||||
)(RankModal));
|
||||
@ -188,6 +188,7 @@ const Checkout: FC<OwnProps> = ({
|
||||
width={photo.dimensions?.width}
|
||||
height={photo.dimensions?.height}
|
||||
className={styles.checkoutPicture}
|
||||
animation="pulse"
|
||||
forceAspectRatio
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -41,6 +41,7 @@ import {
|
||||
import { getSavedGiftKey } from '../../global/helpers/stars';
|
||||
import {
|
||||
selectActiveDownloads,
|
||||
selectCanEditRank,
|
||||
selectCanUpdateMainTab,
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
@ -74,6 +75,7 @@ import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { captureEvents, SwipeDirection } from '../../util/captureEvents';
|
||||
import { isUserId } from '../../util/entities/ids';
|
||||
import { buildCollectionByKey } from '../../util/iteratees.ts';
|
||||
import { resolveTransitionName } from '../../util/resolveTransitionName.ts';
|
||||
import { LOCAL_TGS_URLS } from '../common/helpers/animatedAssets';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
@ -301,6 +303,7 @@ const Profile = ({
|
||||
resetSelectedStoryAlbum,
|
||||
changeProfileTab,
|
||||
setMainProfileTab,
|
||||
openEditRankModal,
|
||||
} = getActions();
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>();
|
||||
@ -481,6 +484,10 @@ const Profile = ({
|
||||
const { startViewTransition } = useViewTransition();
|
||||
const { createVtnStyle } = useVtn();
|
||||
|
||||
const membersById = useMemo(() => {
|
||||
return members && buildCollectionByKey(members, 'userId');
|
||||
}, [members]);
|
||||
|
||||
const giftIds = useMemo(() => renderingGifts?.map((gift) => getSavedGiftKey(gift)), [renderingGifts]);
|
||||
|
||||
const activeTabIndex = useMemo(() => {
|
||||
@ -724,13 +731,48 @@ const Profile = ({
|
||||
activeTabIndex, activeCollectionId, selectedStoryAlbumId], renderingDelay);
|
||||
|
||||
function getMemberContextAction(memberId: string): MenuItemContextAction[] | undefined {
|
||||
return memberId === currentUserId || !canDeleteMembers ? undefined : [{
|
||||
title: oldLang('lng_context_remove_from_group'),
|
||||
icon: 'stop',
|
||||
handler: () => {
|
||||
setDeletingUserId(memberId);
|
||||
},
|
||||
}];
|
||||
const global = getGlobal();
|
||||
const member = adminMembersById?.[memberId] || membersById?.[memberId];
|
||||
const canEditRank = member && selectCanEditRank(global, {
|
||||
chatId,
|
||||
userId: memberId,
|
||||
isAdmin: member?.isAdmin,
|
||||
isOwner: member?.isOwner,
|
||||
});
|
||||
|
||||
const actions: MenuItemContextAction[] = [];
|
||||
|
||||
if (memberId !== currentUserId && canDeleteMembers) {
|
||||
actions.push({
|
||||
title: oldLang('lng_context_remove_from_group'),
|
||||
icon: 'stop',
|
||||
handler: () => {
|
||||
setDeletingUserId(memberId);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (canEditRank) {
|
||||
actions.push({
|
||||
title: lang('MemberContextEditRank'),
|
||||
icon: 'tag',
|
||||
handler: () => {
|
||||
openEditRankModal({
|
||||
chatId,
|
||||
userId: memberId,
|
||||
isAdmin: member?.isAdmin,
|
||||
isOwner: member?.isOwner,
|
||||
rank: member?.rank,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (actions.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
function renderNothingFoundGiftsWithFilter() {
|
||||
@ -978,8 +1020,15 @@ const Profile = ({
|
||||
|
||||
onClick={() => handleMemberClick(id)}
|
||||
contextActions={getMemberContextAction(id)}
|
||||
withPortalForMenu
|
||||
>
|
||||
<PrivateChatInfo userId={id} adminMember={adminMembersById?.[id]} forceShowSelf withStory />
|
||||
<PrivateChatInfo
|
||||
userId={id}
|
||||
chatMemberOriginId={chatId}
|
||||
chatMember={adminMembersById?.[id] || membersById?.[id]}
|
||||
forceShowSelf
|
||||
withStory
|
||||
/>
|
||||
</ListItem>
|
||||
))
|
||||
) : resultType === 'commonChats' ? (
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {
|
||||
memo, useCallback, useEffect, useMemo, useState,
|
||||
memo, useEffect, useMemo, useState,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||
|
||||
@ -9,7 +9,7 @@ import type {
|
||||
import { ManagementScreens } from '../../../types';
|
||||
|
||||
import { getUserFullName, isChatBasicGroup, isChatChannel, isUserBot } from '../../../global/helpers';
|
||||
import { selectChat, selectChatFullInfo } from '../../../global/selectors';
|
||||
import { selectCanEditRank, selectChat, selectChatFullInfo } from '../../../global/selectors';
|
||||
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
@ -37,11 +37,12 @@ type OwnProps = {
|
||||
type StateProps = {
|
||||
chat: ApiChat;
|
||||
usersById: Record<string, ApiUser>;
|
||||
adminMembersById?: Record<string, ApiChatMember>;
|
||||
selectedAdminMember?: ApiChatMember;
|
||||
hasFullInfo: boolean;
|
||||
currentUserId?: string;
|
||||
isFormFullyDisabled: boolean;
|
||||
defaultRights?: ApiChatAdminRights;
|
||||
canEditRank?: boolean;
|
||||
};
|
||||
|
||||
const CUSTOM_TITLE_MAX_LENGTH = 16;
|
||||
@ -54,9 +55,10 @@ const ManageGroupAdminRights = ({
|
||||
chat,
|
||||
usersById,
|
||||
currentUserId,
|
||||
adminMembersById,
|
||||
selectedAdminMember,
|
||||
hasFullInfo,
|
||||
isFormFullyDisabled,
|
||||
canEditRank,
|
||||
onClose,
|
||||
onScreenSelect,
|
||||
}: OwnProps & StateProps) => {
|
||||
@ -71,7 +73,7 @@ const ManageGroupAdminRights = ({
|
||||
const [isDismissConfirmationDialogOpen, openDismissConfirmationDialog, closeDismissConfirmationDialog] = useFlag();
|
||||
const [isTransferDialogOpen, openTransferDialog, closeTransferDialog] = useFlag();
|
||||
const [isPasswordModalOpen, openPasswordModal, closePasswordModal] = useFlag();
|
||||
const [customTitle, setCustomTitle] = useState('');
|
||||
const [rank, setRank] = useState('');
|
||||
const lang = useLang();
|
||||
|
||||
const isChannel = isChatChannel(chat);
|
||||
@ -83,9 +85,7 @@ const ManageGroupAdminRights = ({
|
||||
onBack: onClose,
|
||||
});
|
||||
|
||||
const selectedChatMember = useMemo(() => {
|
||||
const selectedAdminMember = selectedUserId ? adminMembersById?.[selectedUserId] : undefined;
|
||||
|
||||
const selectedChatMember: ApiChatMember | undefined = useMemo(() => {
|
||||
// If `selectedAdminMember` variable is filled with a value, then we have already saved the administrator,
|
||||
// so now we need to return to the list of administrators
|
||||
if (isNewAdmin && (selectedAdminMember || !selectedUserId)) {
|
||||
@ -98,14 +98,14 @@ const ManageGroupAdminRights = ({
|
||||
return user ? {
|
||||
userId: user.id,
|
||||
adminRights: defaultRights,
|
||||
customTitle: lang('ChannelAdmin'),
|
||||
isOwner: false,
|
||||
rank: lang('ChannelAdmin'),
|
||||
isOwner: undefined,
|
||||
promotedByUserId: undefined,
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
return selectedAdminMember;
|
||||
}, [adminMembersById, defaultRights, isNewAdmin, lang, selectedUserId]);
|
||||
}, [selectedAdminMember, defaultRights, isNewAdmin, lang, selectedUserId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasFullInfo && selectedUserId && !selectedChatMember) {
|
||||
@ -115,12 +115,12 @@ const ManageGroupAdminRights = ({
|
||||
|
||||
useEffect(() => {
|
||||
setPermissions(selectedChatMember?.adminRights || {});
|
||||
setCustomTitle((selectedChatMember?.customTitle || '').substr(0, CUSTOM_TITLE_MAX_LENGTH));
|
||||
setRank((selectedChatMember?.rank || '').slice(0, CUSTOM_TITLE_MAX_LENGTH));
|
||||
setIsTouched(Boolean(isNewAdmin));
|
||||
setIsLoading(false);
|
||||
}, [defaultRights, isNewAdmin, selectedChatMember]);
|
||||
|
||||
const handlePermissionChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const handlePermissionChange = useLastCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name } = e.target;
|
||||
|
||||
function getUpdatedPermissionValue(value: true | undefined) {
|
||||
@ -132,23 +132,24 @@ const ManageGroupAdminRights = ({
|
||||
[name]: getUpdatedPermissionValue(p[name as keyof ApiChatAdminRights]),
|
||||
}));
|
||||
setIsTouched(true);
|
||||
}, []);
|
||||
});
|
||||
|
||||
const handleSavePermissions = useCallback(() => {
|
||||
const handleSavePermissions = useLastCallback(() => {
|
||||
if (!selectedUserId) {
|
||||
return;
|
||||
}
|
||||
const hasRankChanged = rank !== selectedAdminMember?.rank;
|
||||
|
||||
setIsLoading(true);
|
||||
updateChatAdmin({
|
||||
chatId: chat.id,
|
||||
userId: selectedUserId,
|
||||
adminRights: permissions,
|
||||
customTitle,
|
||||
rank: hasRankChanged ? rank : undefined,
|
||||
});
|
||||
}, [selectedUserId, updateChatAdmin, chat.id, permissions, customTitle]);
|
||||
});
|
||||
|
||||
const handleDismissAdmin = useCallback(() => {
|
||||
const handleDismissAdmin = useLastCallback(() => {
|
||||
if (!selectedUserId) {
|
||||
return;
|
||||
}
|
||||
@ -159,9 +160,9 @@ const ManageGroupAdminRights = ({
|
||||
adminRights: {},
|
||||
});
|
||||
closeDismissConfirmationDialog();
|
||||
}, [chat.id, closeDismissConfirmationDialog, selectedUserId, updateChatAdmin]);
|
||||
});
|
||||
|
||||
const getControlIsDisabled = useCallback((key: keyof ApiChatAdminRights) => {
|
||||
const getControlIsDisabled = useLastCallback((key: keyof ApiChatAdminRights) => {
|
||||
if (isChatBasicGroup(chat)) {
|
||||
return false;
|
||||
}
|
||||
@ -175,7 +176,7 @@ const ManageGroupAdminRights = ({
|
||||
}
|
||||
|
||||
return !chat.adminRights[key];
|
||||
}, [chat, isFormFullyDisabled]);
|
||||
});
|
||||
|
||||
const memberStatus = useMemo(() => {
|
||||
if (isNewAdmin || !selectedChatMember) {
|
||||
@ -197,11 +198,11 @@ const ManageGroupAdminRights = ({
|
||||
return lang('ChannelAdmin');
|
||||
}, [isNewAdmin, selectedChatMember, usersById, lang]);
|
||||
|
||||
const handleCustomTitleChange = useCallback((e) => {
|
||||
const handleRankChange = useLastCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = e.target;
|
||||
setCustomTitle(value);
|
||||
setRank(value);
|
||||
setIsTouched(true);
|
||||
}, []);
|
||||
});
|
||||
|
||||
const handleStartTransfer = useLastCallback(() => {
|
||||
if (!selectedUserId) return;
|
||||
@ -373,6 +374,16 @@ const ManageGroupAdminRights = ({
|
||||
onChange={handlePermissionChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="ListItem">
|
||||
<Checkbox
|
||||
name="editRank"
|
||||
checked={Boolean(permissions.manageRanks)}
|
||||
label={lang('EditAdminEditRank')}
|
||||
blocking
|
||||
disabled={getControlIsDisabled('manageRanks')}
|
||||
onChange={handlePermissionChange}
|
||||
/>
|
||||
</div>
|
||||
{!isChannel && (
|
||||
<div className="ListItem">
|
||||
<Checkbox
|
||||
@ -441,9 +452,9 @@ const ManageGroupAdminRights = ({
|
||||
id="admin-title"
|
||||
label={lang('EditAdminRank')}
|
||||
className="input-admin-title"
|
||||
onChange={handleCustomTitleChange}
|
||||
value={customTitle}
|
||||
disabled={isFormFullyDisabled}
|
||||
onChange={handleRankChange}
|
||||
value={rank}
|
||||
disabled={isFormFullyDisabled || !canEditRank}
|
||||
maxLength={CUSTOM_TITLE_MAX_LENGTH}
|
||||
/>
|
||||
)}
|
||||
@ -503,12 +514,21 @@ const ManageGroupAdminRights = ({
|
||||
};
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global, { chatId, isPromotedByCurrentUser }): Complete<StateProps> => {
|
||||
(global, { chatId, isPromotedByCurrentUser, selectedUserId }): Complete<StateProps> => {
|
||||
const chat = selectChat(global, chatId)!;
|
||||
const fullInfo = selectChatFullInfo(global, chatId);
|
||||
const { byId: usersById } = global.users;
|
||||
const { currentUserId } = global;
|
||||
const isFormFullyDisabled = !(chat.isCreator || isPromotedByCurrentUser);
|
||||
const adminMembersById = fullInfo?.adminMembersById;
|
||||
|
||||
const selectedAdminMember = selectedUserId ? adminMembersById?.[selectedUserId] : undefined;
|
||||
const canEditRank = selectedAdminMember && selectCanEditRank(global, {
|
||||
chatId,
|
||||
userId: selectedAdminMember.userId,
|
||||
isAdmin: selectedAdminMember.isAdmin,
|
||||
isOwner: selectedAdminMember.isOwner,
|
||||
});
|
||||
|
||||
return {
|
||||
chat,
|
||||
@ -517,7 +537,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
isFormFullyDisabled,
|
||||
defaultRights: chat.adminRights,
|
||||
hasFullInfo: Boolean(fullInfo),
|
||||
adminMembersById: fullInfo?.adminMembersById,
|
||||
selectedAdminMember,
|
||||
canEditRank,
|
||||
};
|
||||
},
|
||||
(global, { chatId }) => {
|
||||
|
||||
@ -808,7 +808,7 @@ function Story({
|
||||
/>
|
||||
)}
|
||||
{shouldRenderSkeleton && (
|
||||
<Skeleton className={buildClassName(skeletonTransitionClassNames, styles.fullSize)} />
|
||||
<Skeleton className={buildClassName(skeletonTransitionClassNames, styles.fullSize)} animation="pulse" />
|
||||
)}
|
||||
{!isVideo && fullMediaData && (
|
||||
<img
|
||||
|
||||
@ -45,7 +45,7 @@ const InputText = ({
|
||||
disabled,
|
||||
readOnly,
|
||||
placeholder,
|
||||
autoComplete,
|
||||
autoComplete = 'off',
|
||||
inputMode,
|
||||
maxLength,
|
||||
tabIndex,
|
||||
|
||||
@ -245,6 +245,7 @@
|
||||
.info-name-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.info-row,
|
||||
|
||||
@ -8,7 +8,7 @@ import './Skeleton.scss';
|
||||
|
||||
type OwnProps = {
|
||||
variant?: 'rectangular' | 'rounded-rect' | 'round';
|
||||
animation?: 'wave' | 'pulse';
|
||||
animation?: 'wave' | 'pulse' | 'none';
|
||||
width?: number;
|
||||
height?: number;
|
||||
forceAspectRatio?: boolean;
|
||||
@ -18,7 +18,7 @@ type OwnProps = {
|
||||
|
||||
const Skeleton: FC<OwnProps> = ({
|
||||
variant = 'rectangular',
|
||||
animation = 'wave',
|
||||
animation = 'none',
|
||||
width,
|
||||
height,
|
||||
forceAspectRatio,
|
||||
|
||||
@ -85,6 +85,7 @@ import {
|
||||
updateChatFullInfo,
|
||||
updateChatLastMessageId,
|
||||
updateChatListSecondaryInfo,
|
||||
updateChatParticipantRank,
|
||||
updateChats,
|
||||
updateChatsLastMessageId,
|
||||
updateListedTopicIds,
|
||||
@ -2081,7 +2082,7 @@ addActionHandler('updateChatAdmin', async (global, actions, payload): Promise<vo
|
||||
if (selectIsCurrentUserFrozen(global)) return;
|
||||
|
||||
const {
|
||||
chatId, userId, adminRights, customTitle,
|
||||
chatId, userId, adminRights, rank,
|
||||
tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
|
||||
@ -2095,7 +2096,7 @@ addActionHandler('updateChatAdmin', async (global, actions, payload): Promise<vo
|
||||
if (!chat) return;
|
||||
|
||||
await callApi('updateChatAdmin', {
|
||||
chat, user, adminRights, customTitle,
|
||||
chat, user, adminRights, rank,
|
||||
});
|
||||
|
||||
const chatAfterUpdate = await callApi('fetchFullChat', chat);
|
||||
@ -2116,7 +2117,7 @@ addActionHandler('updateChatAdmin', async (global, actions, payload): Promise<vo
|
||||
[userId]: {
|
||||
...adminMembersById[userId],
|
||||
adminRights,
|
||||
customTitle,
|
||||
rank,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -2129,6 +2130,31 @@ addActionHandler('updateChatAdmin', async (global, actions, payload): Promise<vo
|
||||
}
|
||||
});
|
||||
|
||||
addActionHandler('editChatParticipantRank', async (global, actions, payload): Promise<void> => {
|
||||
if (selectIsCurrentUserFrozen(global)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
chatId, userId, rank,
|
||||
} = payload;
|
||||
|
||||
const chat = selectChat(global, chatId);
|
||||
const peer = selectPeer(global, userId);
|
||||
if (!chat || !peer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isUpdated = await callApi('editChatParticipantRank', { chat, peer, rank });
|
||||
if (!isUpdated) {
|
||||
return;
|
||||
}
|
||||
|
||||
global = getGlobal();
|
||||
global = updateChatParticipantRank(global, chat.id, userId, rank);
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('updateChat', async (global, actions, payload): Promise<void> => {
|
||||
const {
|
||||
chatId, title, about, photo, tabId = getCurrentTabId(),
|
||||
|
||||
@ -23,6 +23,7 @@ import {
|
||||
updateChat,
|
||||
updateChatFullInfo,
|
||||
updateChatListType,
|
||||
updateChatParticipantRank,
|
||||
updatePeerStoriesHidden,
|
||||
updateTopic,
|
||||
} from '../../reducers';
|
||||
@ -444,6 +445,10 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case 'updateChatParticipantRank': {
|
||||
return updateChatParticipantRank(global, update.id, update.userId, update.rank);
|
||||
}
|
||||
|
||||
case 'draftMessage': {
|
||||
const {
|
||||
chatId, threadId, draft,
|
||||
|
||||
@ -77,3 +77,23 @@ addActionHandler('openProfileRatingModal', (global, actions, payload): ActionRet
|
||||
});
|
||||
|
||||
addTabStateResetterAction('closeProfileRatingModal', 'profileRatingModal');
|
||||
|
||||
addActionHandler('openRankModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId(), ...rest } = payload;
|
||||
|
||||
return updateTabState(global, {
|
||||
rankModal: rest,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addTabStateResetterAction('closeRankModal', 'rankModal');
|
||||
|
||||
addActionHandler('openEditRankModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId(), ...rest } = payload;
|
||||
|
||||
return updateTabState(global, {
|
||||
editRankModal: rest,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addTabStateResetterAction('closeEditRankModal', 'editRankModal');
|
||||
|
||||
@ -442,6 +442,55 @@ export function addChatMembers<T extends GlobalState>(global: T, chat: ApiChat,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateChatParticipantRank<T extends GlobalState>(
|
||||
global: T, chatId: string, userId: string, rank: string,
|
||||
): T {
|
||||
const fullInfo = selectChatFullInfo(global, chatId);
|
||||
if (!fullInfo) {
|
||||
return global;
|
||||
}
|
||||
|
||||
const { adminMembersById, members } = fullInfo;
|
||||
let fullInfoUpdate: Partial<ApiChatFullInfo> | undefined;
|
||||
|
||||
const currentAdminMember = adminMembersById?.[userId];
|
||||
if (currentAdminMember && currentAdminMember.rank !== rank) {
|
||||
fullInfoUpdate = {
|
||||
...fullInfoUpdate,
|
||||
adminMembersById: {
|
||||
...adminMembersById,
|
||||
[userId]: {
|
||||
...currentAdminMember,
|
||||
rank,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let shouldUpdateMembers = false;
|
||||
const updatedMembers = members?.map((member) => {
|
||||
if (member.userId !== userId || member.rank === rank) {
|
||||
return member;
|
||||
}
|
||||
|
||||
shouldUpdateMembers = true;
|
||||
|
||||
return {
|
||||
...member,
|
||||
rank,
|
||||
};
|
||||
});
|
||||
|
||||
if (shouldUpdateMembers) {
|
||||
fullInfoUpdate = {
|
||||
...fullInfoUpdate,
|
||||
members: updatedMembers,
|
||||
};
|
||||
}
|
||||
|
||||
return fullInfoUpdate ? updateChatFullInfo(global, chatId, fullInfoUpdate) : global;
|
||||
}
|
||||
|
||||
export function replaceSimilarChannels<T extends GlobalState>(
|
||||
global: T,
|
||||
chatId: string,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import type {
|
||||
ApiChat, ApiChatFullInfo, ApiChatType,
|
||||
} from '../../api/types';
|
||||
import type { ChatListType } from '../../types';
|
||||
import type { GlobalState, TabArgs } from '../types';
|
||||
import {
|
||||
type ApiChat, type ApiChatFullInfo, type ApiChatType,
|
||||
} from '../../api/types';
|
||||
|
||||
import {
|
||||
ALL_FOLDER_ID, ARCHIVED_FOLDER_ID, MEMBERS_LOAD_SLICE, SAVED_FOLDER_ID, SERVICE_NOTIFICATIONS_USER_ID,
|
||||
@ -12,12 +12,14 @@ import { isUserId } from '../../util/entities/ids';
|
||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||
import {
|
||||
getHasAdminRight,
|
||||
isChatAdmin,
|
||||
isChatChannel,
|
||||
isChatPublic,
|
||||
isChatSuperGroup,
|
||||
isHistoryClearMessage,
|
||||
isUserBot,
|
||||
isUserOnline,
|
||||
isUserRightBanned,
|
||||
} from '../helpers';
|
||||
import { selectActiveRestrictionReasons } from './messages';
|
||||
import { selectTabState } from './tabs';
|
||||
@ -378,3 +380,35 @@ export function selectAreFoldersPresent<T extends GlobalState>(global: T) {
|
||||
const ids = global.chatFolders.orderedIds;
|
||||
return Boolean(ids && ids.length > 1);
|
||||
}
|
||||
|
||||
export function selectCanEditRank<T extends GlobalState>(global: T, {
|
||||
chatId, userId, isAdmin, isOwner,
|
||||
}: {
|
||||
chatId: string;
|
||||
userId: string;
|
||||
isAdmin?: boolean;
|
||||
isOwner?: boolean;
|
||||
}) {
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat || chat.isNotJoined || chat.isRestricted) return false;
|
||||
|
||||
const isCurrentUserAdmin = isChatAdmin(chat);
|
||||
const hasAdminRight = getHasAdminRight(chat, 'manageRanks');
|
||||
if (!isCurrentUserAdmin) return userId === global.currentUserId && !isUserRightBanned(chat, 'editRank'); // Users can edit only their own rank
|
||||
if (!hasAdminRight) return false;
|
||||
|
||||
if (userId === global.currentUserId) return true; // Admin can edit own rank with permission
|
||||
|
||||
if (!chat.isCreator && (isOwner || isAdmin)) return false; // Admin can't edit rank of owner or another admin
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function selectCanEditOwnRank<T extends GlobalState>(global: T, chatId: string) {
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat || chat.isNotJoined || chat.isRestricted) return false;
|
||||
|
||||
const isCurrentUserAdmin = isChatAdmin(chat);
|
||||
if (!isCurrentUserAdmin) return !isUserRightBanned(chat, 'editRank'); // Users can edit only their own rank
|
||||
return getHasAdminRight(chat, 'manageRanks');
|
||||
}
|
||||
|
||||
@ -182,8 +182,13 @@ export interface ActionPayloads {
|
||||
chatId: string;
|
||||
userId: string;
|
||||
adminRights: ApiChatAdminRights;
|
||||
customTitle?: string;
|
||||
rank?: string;
|
||||
} & WithTabId;
|
||||
editChatParticipantRank: {
|
||||
chatId: string;
|
||||
userId: string;
|
||||
rank: string;
|
||||
};
|
||||
|
||||
checkChatInvite: {
|
||||
hash: string;
|
||||
@ -1938,6 +1943,22 @@ export interface ActionPayloads {
|
||||
level: number;
|
||||
} & WithTabId;
|
||||
closeProfileRatingModal: WithTabId | undefined;
|
||||
openRankModal: {
|
||||
chatId: string;
|
||||
userId: string;
|
||||
isAdmin?: boolean;
|
||||
isOwner?: boolean;
|
||||
rank?: string;
|
||||
} & WithTabId;
|
||||
closeRankModal: WithTabId | undefined;
|
||||
openEditRankModal: {
|
||||
chatId: string;
|
||||
userId: string;
|
||||
isAdmin?: boolean;
|
||||
isOwner?: boolean;
|
||||
rank?: string;
|
||||
} & WithTabId;
|
||||
closeEditRankModal: WithTabId | undefined;
|
||||
loadMoreProfilePhotos: {
|
||||
peerId: string;
|
||||
isPreload?: boolean;
|
||||
|
||||
@ -1035,5 +1035,19 @@ export type TabState = {
|
||||
|
||||
isCocoonModalOpen?: boolean;
|
||||
|
||||
rankModal?: {
|
||||
chatId: string;
|
||||
userId: string;
|
||||
isAdmin?: boolean;
|
||||
isOwner?: boolean;
|
||||
rank?: string;
|
||||
};
|
||||
editRankModal?: {
|
||||
chatId: string;
|
||||
userId: string;
|
||||
isAdmin?: boolean;
|
||||
isOwner?: boolean;
|
||||
rank?: string;
|
||||
};
|
||||
shouldOpenMessageMediaEditor?: boolean;
|
||||
};
|
||||
|
||||
@ -1794,6 +1794,7 @@ messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.Af
|
||||
messages.summarizeText#9d4104e2 flags:# peer:InputPeer id:int to_lang:flags.0?string = TextWithEntities;
|
||||
messages.editChatCreator#f743b857 peer:InputPeer user_id:InputUser password:InputCheckPasswordSRP = Updates;
|
||||
messages.getFutureChatCreatorAfterLeave#3b7d0ea6 peer:InputPeer = User;
|
||||
messages.editChatParticipantRank#a00f32b0 peer:InputPeer participant:InputPeer rank:string = Updates;
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference;
|
||||
updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
|
||||
|
||||
@ -248,6 +248,7 @@
|
||||
"messages.summarizeText",
|
||||
"messages.editChatCreator",
|
||||
"messages.getFutureChatCreatorAfterLeave",
|
||||
"messages.editChatParticipantRank",
|
||||
"updates.getState",
|
||||
"updates.getDifference",
|
||||
"updates.getChannelDifference",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -16,326 +16,327 @@
|
||||
}
|
||||
|
||||
$icons-map: (
|
||||
"zoom-out": "\f101",
|
||||
"zoom-in": "\f102",
|
||||
"word-wrap": "\f103",
|
||||
"webapp": "\f104",
|
||||
"web": "\f105",
|
||||
"warning": "\f106",
|
||||
"volume-3": "\f107",
|
||||
"volume-2": "\f108",
|
||||
"volume-1": "\f109",
|
||||
"voice-chat": "\f10a",
|
||||
"view-once": "\f10b",
|
||||
"video": "\f10c",
|
||||
"video-stop": "\f10d",
|
||||
"video-outlined": "\f10e",
|
||||
"user": "\f10f",
|
||||
"user-stars": "\f110",
|
||||
"user-online": "\f111",
|
||||
"user-filled": "\f112",
|
||||
"up": "\f113",
|
||||
"unread": "\f114",
|
||||
"unpin": "\f115",
|
||||
"unmute": "\f116",
|
||||
"unlock": "\f117",
|
||||
"unlock-badge": "\f118",
|
||||
"unlist": "\f119",
|
||||
"unlist-outline": "\f11a",
|
||||
"unique-profile": "\f11b",
|
||||
"undo": "\f11c",
|
||||
"understood": "\f11d",
|
||||
"underlined": "\f11e",
|
||||
"unarchive": "\f11f",
|
||||
"truck": "\f120",
|
||||
"transcribe": "\f121",
|
||||
"trade": "\f122",
|
||||
"topic-new": "\f123",
|
||||
"tools": "\f124",
|
||||
"toncoin": "\f125",
|
||||
"timer": "\f126",
|
||||
"tag": "\f127",
|
||||
"tag-name": "\f128",
|
||||
"tag-filter": "\f129",
|
||||
"tag-crossed": "\f12a",
|
||||
"tag-add": "\f12b",
|
||||
"strikethrough": "\f12c",
|
||||
"story-reply": "\f12d",
|
||||
"story-priority": "\f12e",
|
||||
"story-expired": "\f12f",
|
||||
"story-caption": "\f130",
|
||||
"stop": "\f131",
|
||||
"stop-raising-hand": "\f132",
|
||||
"stickers": "\f133",
|
||||
"stealth-past": "\f134",
|
||||
"stealth-future": "\f135",
|
||||
"stats": "\f136",
|
||||
"stars-refund": "\f137",
|
||||
"stars-lock": "\f138",
|
||||
"star": "\f139",
|
||||
"sport": "\f13a",
|
||||
"spoiler": "\f13b",
|
||||
"spoiler-disable": "\f13c",
|
||||
"speaker": "\f13d",
|
||||
"speaker-story": "\f13e",
|
||||
"speaker-outline": "\f13f",
|
||||
"speaker-muted-story": "\f140",
|
||||
"sort": "\f141",
|
||||
"sort-by-price": "\f142",
|
||||
"sort-by-number": "\f143",
|
||||
"sort-by-date": "\f144",
|
||||
"smile": "\f145",
|
||||
"smallscreen": "\f146",
|
||||
"skip-previous": "\f147",
|
||||
"skip-next": "\f148",
|
||||
"sidebar": "\f149",
|
||||
"show-message": "\f14a",
|
||||
"share-screen": "\f14b",
|
||||
"share-screen-stop": "\f14c",
|
||||
"share-screen-outlined": "\f14d",
|
||||
"share-filled": "\f14e",
|
||||
"settings": "\f14f",
|
||||
"settings-filled": "\f150",
|
||||
"send": "\f151",
|
||||
"send-outline": "\f152",
|
||||
"sell": "\f153",
|
||||
"sell-outline": "\f154",
|
||||
"select": "\f155",
|
||||
"search": "\f156",
|
||||
"sd-photo": "\f157",
|
||||
"scheduled": "\f158",
|
||||
"schedule": "\f159",
|
||||
"saved-messages": "\f15a",
|
||||
"save-story": "\f15b",
|
||||
"rotate": "\f15c",
|
||||
"revote": "\f15d",
|
||||
"revenue-split": "\f15e",
|
||||
"reply": "\f15f",
|
||||
"reply-filled": "\f160",
|
||||
"replies": "\f161",
|
||||
"replace": "\f162",
|
||||
"reorder-tabs": "\f163",
|
||||
"reopen-topic": "\f164",
|
||||
"remove": "\f165",
|
||||
"remove-quote": "\f166",
|
||||
"reload": "\f167",
|
||||
"refund": "\f168",
|
||||
"redo": "\f169",
|
||||
"recent": "\f16a",
|
||||
"readchats": "\f16b",
|
||||
"radial-badge": "\f16c",
|
||||
"quote": "\f16d",
|
||||
"quote-text": "\f16e",
|
||||
"proof-of-ownership": "\f16f",
|
||||
"privacy-policy": "\f170",
|
||||
"previous": "\f171",
|
||||
"poll": "\f172",
|
||||
"play": "\f173",
|
||||
"play-story": "\f174",
|
||||
"pip": "\f175",
|
||||
"pinned-message": "\f176",
|
||||
"pinned-chat": "\f177",
|
||||
"pin": "\f178",
|
||||
"pin-list": "\f179",
|
||||
"pin-badge": "\f17a",
|
||||
"photo": "\f17b",
|
||||
"phone": "\f17c",
|
||||
"phone-discard": "\f17d",
|
||||
"phone-discard-outline": "\f17e",
|
||||
"permissions": "\f17f",
|
||||
"pause": "\f180",
|
||||
"password-off": "\f181",
|
||||
"open-in-new-tab": "\f182",
|
||||
"one-filled": "\f183",
|
||||
"note": "\f184",
|
||||
"non-contacts": "\f185",
|
||||
"noise-suppression": "\f186",
|
||||
"nochannel": "\f187",
|
||||
"next": "\f188",
|
||||
"next-link": "\f189",
|
||||
"new-chat-filled": "\f18a",
|
||||
"my-notes": "\f18b",
|
||||
"muted": "\f18c",
|
||||
"mute": "\f18d",
|
||||
"move-caption-up": "\f18e",
|
||||
"move-caption-down": "\f18f",
|
||||
"more": "\f190",
|
||||
"more-circle": "\f191",
|
||||
"monospace": "\f192",
|
||||
"microphone": "\f193",
|
||||
"microphone-alt": "\f194",
|
||||
"message": "\f195",
|
||||
"message-succeeded": "\f196",
|
||||
"message-read": "\f197",
|
||||
"active-sessions": "\f101",
|
||||
"add-caption": "\f102",
|
||||
"add-filled": "\f103",
|
||||
"add-one-badge": "\f104",
|
||||
"add-user-filled": "\f105",
|
||||
"add-user": "\f106",
|
||||
"add": "\f107",
|
||||
"admin": "\f108",
|
||||
"allow-speak": "\f109",
|
||||
"animals": "\f10a",
|
||||
"animations": "\f10b",
|
||||
"archive-filled": "\f10c",
|
||||
"archive-from-main": "\f10d",
|
||||
"archive-to-main": "\f10e",
|
||||
"archive": "\f10f",
|
||||
"arrow-down-circle": "\f110",
|
||||
"arrow-down": "\f111",
|
||||
"arrow-left": "\f112",
|
||||
"arrow-right": "\f113",
|
||||
"ask-support": "\f114",
|
||||
"attach": "\f115",
|
||||
"auction-drop": "\f116",
|
||||
"auction-filled": "\f117",
|
||||
"auction-next-round": "\f118",
|
||||
"auction": "\f119",
|
||||
"author-hidden": "\f11a",
|
||||
"avatar-archived-chats": "\f11b",
|
||||
"avatar-deleted-account": "\f11c",
|
||||
"avatar-saved-messages": "\f11d",
|
||||
"bold": "\f11e",
|
||||
"boost-craft-chance": "\f11f",
|
||||
"boost-outline": "\f120",
|
||||
"boost": "\f121",
|
||||
"boostcircle": "\f122",
|
||||
"boosts": "\f123",
|
||||
"bot-command": "\f124",
|
||||
"bot-commands-filled": "\f125",
|
||||
"bots": "\f126",
|
||||
"brush": "\f127",
|
||||
"bug": "\f128",
|
||||
"calendar-filter": "\f129",
|
||||
"calendar": "\f12a",
|
||||
"camera-add": "\f12b",
|
||||
"camera": "\f12c",
|
||||
"car": "\f12d",
|
||||
"card": "\f12e",
|
||||
"cash-circle": "\f12f",
|
||||
"channel-filled": "\f130",
|
||||
"channel": "\f131",
|
||||
"channelviews": "\f132",
|
||||
"chat-badge": "\f133",
|
||||
"chats-badge": "\f134",
|
||||
"check": "\f135",
|
||||
"clock-edit": "\f136",
|
||||
"clock": "\f137",
|
||||
"close-circle": "\f138",
|
||||
"close-topic": "\f139",
|
||||
"close": "\f13a",
|
||||
"closed-gift": "\f13b",
|
||||
"cloud-download": "\f13c",
|
||||
"collapse-modal": "\f13d",
|
||||
"collapse": "\f13e",
|
||||
"colorize": "\f13f",
|
||||
"combine-craft": "\f140",
|
||||
"comments-sticker": "\f141",
|
||||
"comments": "\f142",
|
||||
"copy-media": "\f143",
|
||||
"copy": "\f144",
|
||||
"craft": "\f145",
|
||||
"crop": "\f146",
|
||||
"crown-take-off-outline": "\f147",
|
||||
"crown-take-off": "\f148",
|
||||
"crown-wear-outline": "\f149",
|
||||
"crown-wear": "\f14a",
|
||||
"darkmode": "\f14b",
|
||||
"data": "\f14c",
|
||||
"delete-filled": "\f14d",
|
||||
"delete-left": "\f14e",
|
||||
"delete-user": "\f14f",
|
||||
"delete": "\f150",
|
||||
"diamond": "\f151",
|
||||
"document": "\f152",
|
||||
"double-badge": "\f153",
|
||||
"down": "\f154",
|
||||
"download": "\f155",
|
||||
"dropdown-arrows": "\f156",
|
||||
"eats": "\f157",
|
||||
"edit": "\f158",
|
||||
"email": "\f159",
|
||||
"enter": "\f15a",
|
||||
"expand-modal": "\f15b",
|
||||
"expand": "\f15c",
|
||||
"eye-crossed-outline": "\f15d",
|
||||
"eye-crossed": "\f15e",
|
||||
"eye-outline": "\f15f",
|
||||
"eye": "\f160",
|
||||
"favorite-filled": "\f161",
|
||||
"favorite": "\f162",
|
||||
"file-badge": "\f163",
|
||||
"flag": "\f164",
|
||||
"flip": "\f165",
|
||||
"folder-badge": "\f166",
|
||||
"folder-tabs-bot": "\f167",
|
||||
"folder-tabs-channel": "\f168",
|
||||
"folder-tabs-chat": "\f169",
|
||||
"folder-tabs-chats": "\f16a",
|
||||
"folder-tabs-folder": "\f16b",
|
||||
"folder-tabs-group": "\f16c",
|
||||
"folder-tabs-star": "\f16d",
|
||||
"folder-tabs-user": "\f16e",
|
||||
"folder": "\f16f",
|
||||
"fontsize": "\f170",
|
||||
"forums": "\f171",
|
||||
"forward": "\f172",
|
||||
"fragment": "\f173",
|
||||
"frozen-time": "\f174",
|
||||
"fullscreen": "\f175",
|
||||
"gifs": "\f176",
|
||||
"gift-transfer-inline": "\f177",
|
||||
"gift": "\f178",
|
||||
"group-filled": "\f179",
|
||||
"group": "\f17a",
|
||||
"grouped-disable": "\f17b",
|
||||
"grouped": "\f17c",
|
||||
"hand-stop": "\f17d",
|
||||
"hashtag": "\f17e",
|
||||
"hd-photo": "\f17f",
|
||||
"heart-outline": "\f180",
|
||||
"heart": "\f181",
|
||||
"help": "\f182",
|
||||
"info-filled": "\f183",
|
||||
"info": "\f184",
|
||||
"install": "\f185",
|
||||
"italic": "\f186",
|
||||
"key": "\f187",
|
||||
"keyboard": "\f188",
|
||||
"lamp": "\f189",
|
||||
"language": "\f18a",
|
||||
"large-pause": "\f18b",
|
||||
"large-play": "\f18c",
|
||||
"link-badge": "\f18d",
|
||||
"link-broken": "\f18e",
|
||||
"link": "\f18f",
|
||||
"location": "\f190",
|
||||
"lock-badge": "\f191",
|
||||
"lock": "\f192",
|
||||
"logout": "\f193",
|
||||
"loop": "\f194",
|
||||
"mention": "\f195",
|
||||
"menu": "\f196",
|
||||
"message-failed": "\f197",
|
||||
"message-pending": "\f198",
|
||||
"message-failed": "\f199",
|
||||
"menu": "\f19a",
|
||||
"mention": "\f19b",
|
||||
"loop": "\f19c",
|
||||
"logout": "\f19d",
|
||||
"lock": "\f19e",
|
||||
"lock-badge": "\f19f",
|
||||
"location": "\f1a0",
|
||||
"link": "\f1a1",
|
||||
"link-broken": "\f1a2",
|
||||
"link-badge": "\f1a3",
|
||||
"large-play": "\f1a4",
|
||||
"large-pause": "\f1a5",
|
||||
"language": "\f1a6",
|
||||
"lamp": "\f1a7",
|
||||
"keyboard": "\f1a8",
|
||||
"key": "\f1a9",
|
||||
"italic": "\f1aa",
|
||||
"install": "\f1ab",
|
||||
"info": "\f1ac",
|
||||
"info-filled": "\f1ad",
|
||||
"help": "\f1ae",
|
||||
"heart": "\f1af",
|
||||
"heart-outline": "\f1b0",
|
||||
"hd-photo": "\f1b1",
|
||||
"hashtag": "\f1b2",
|
||||
"hand-stop": "\f1b3",
|
||||
"grouped": "\f1b4",
|
||||
"grouped-disable": "\f1b5",
|
||||
"group": "\f1b6",
|
||||
"group-filled": "\f1b7",
|
||||
"gift": "\f1b8",
|
||||
"gift-transfer-inline": "\f1b9",
|
||||
"gifs": "\f1ba",
|
||||
"fullscreen": "\f1bb",
|
||||
"frozen-time": "\f1bc",
|
||||
"fragment": "\f1bd",
|
||||
"forward": "\f1be",
|
||||
"forums": "\f1bf",
|
||||
"fontsize": "\f1c0",
|
||||
"folder": "\f1c1",
|
||||
"folder-badge": "\f1c2",
|
||||
"flip": "\f1c3",
|
||||
"flag": "\f1c4",
|
||||
"file-badge": "\f1c5",
|
||||
"favorite": "\f1c6",
|
||||
"favorite-filled": "\f1c7",
|
||||
"eye": "\f1c8",
|
||||
"eye-outline": "\f1c9",
|
||||
"eye-crossed": "\f1ca",
|
||||
"eye-crossed-outline": "\f1cb",
|
||||
"expand": "\f1cc",
|
||||
"expand-modal": "\f1cd",
|
||||
"enter": "\f1ce",
|
||||
"email": "\f1cf",
|
||||
"edit": "\f1d0",
|
||||
"eats": "\f1d1",
|
||||
"dropdown-arrows": "\f1d2",
|
||||
"download": "\f1d3",
|
||||
"down": "\f1d4",
|
||||
"double-badge": "\f1d5",
|
||||
"document": "\f1d6",
|
||||
"diamond": "\f1d7",
|
||||
"delete": "\f1d8",
|
||||
"delete-user": "\f1d9",
|
||||
"delete-left": "\f1da",
|
||||
"delete-filled": "\f1db",
|
||||
"data": "\f1dc",
|
||||
"darkmode": "\f1dd",
|
||||
"crown-wear": "\f1de",
|
||||
"crown-wear-outline": "\f1df",
|
||||
"crown-take-off": "\f1e0",
|
||||
"crown-take-off-outline": "\f1e1",
|
||||
"crop": "\f1e2",
|
||||
"craft": "\f1e3",
|
||||
"copy": "\f1e4",
|
||||
"copy-media": "\f1e5",
|
||||
"comments": "\f1e6",
|
||||
"comments-sticker": "\f1e7",
|
||||
"combine-craft": "\f1e8",
|
||||
"colorize": "\f1e9",
|
||||
"collapse": "\f1ea",
|
||||
"collapse-modal": "\f1eb",
|
||||
"cloud-download": "\f1ec",
|
||||
"closed-gift": "\f1ed",
|
||||
"close": "\f1ee",
|
||||
"close-topic": "\f1ef",
|
||||
"close-circle": "\f1f0",
|
||||
"clock": "\f1f1",
|
||||
"clock-edit": "\f1f2",
|
||||
"check": "\f1f3",
|
||||
"chats-badge": "\f1f4",
|
||||
"chat-badge": "\f1f5",
|
||||
"channelviews": "\f1f6",
|
||||
"channel": "\f1f7",
|
||||
"channel-filled": "\f1f8",
|
||||
"cash-circle": "\f1f9",
|
||||
"card": "\f1fa",
|
||||
"car": "\f1fb",
|
||||
"camera": "\f1fc",
|
||||
"camera-add": "\f1fd",
|
||||
"calendar": "\f1fe",
|
||||
"calendar-filter": "\f1ff",
|
||||
"bug": "\f200",
|
||||
"brush": "\f201",
|
||||
"bots": "\f202",
|
||||
"bot-commands-filled": "\f203",
|
||||
"bot-command": "\f204",
|
||||
"boosts": "\f205",
|
||||
"boostcircle": "\f206",
|
||||
"boost": "\f207",
|
||||
"boost-outline": "\f208",
|
||||
"boost-craft-chance": "\f209",
|
||||
"bold": "\f20a",
|
||||
"avatar-saved-messages": "\f20b",
|
||||
"avatar-deleted-account": "\f20c",
|
||||
"avatar-archived-chats": "\f20d",
|
||||
"author-hidden": "\f20e",
|
||||
"auction": "\f20f",
|
||||
"auction-next-round": "\f210",
|
||||
"auction-filled": "\f211",
|
||||
"auction-drop": "\f212",
|
||||
"attach": "\f213",
|
||||
"ask-support": "\f214",
|
||||
"arrow-right": "\f215",
|
||||
"arrow-left": "\f216",
|
||||
"arrow-down": "\f217",
|
||||
"arrow-down-circle": "\f218",
|
||||
"archive": "\f219",
|
||||
"archive-to-main": "\f21a",
|
||||
"archive-from-main": "\f21b",
|
||||
"archive-filled": "\f21c",
|
||||
"animations": "\f21d",
|
||||
"animals": "\f21e",
|
||||
"allow-speak": "\f21f",
|
||||
"admin": "\f220",
|
||||
"add": "\f221",
|
||||
"add-user": "\f222",
|
||||
"add-user-filled": "\f223",
|
||||
"add-one-badge": "\f224",
|
||||
"add-filled": "\f225",
|
||||
"add-caption": "\f226",
|
||||
"active-sessions": "\f227",
|
||||
"rating-icons-negative": "\f228",
|
||||
"rating-icons-level90": "\f229",
|
||||
"rating-icons-level9": "\f22a",
|
||||
"rating-icons-level80": "\f22b",
|
||||
"rating-icons-level8": "\f22c",
|
||||
"rating-icons-level70": "\f22d",
|
||||
"rating-icons-level7": "\f22e",
|
||||
"rating-icons-level60": "\f22f",
|
||||
"rating-icons-level6": "\f230",
|
||||
"rating-icons-level50": "\f231",
|
||||
"rating-icons-level5": "\f232",
|
||||
"rating-icons-level40": "\f233",
|
||||
"rating-icons-level4": "\f234",
|
||||
"rating-icons-level30": "\f235",
|
||||
"rating-icons-level3": "\f236",
|
||||
"rating-icons-level20": "\f237",
|
||||
"rating-icons-level2": "\f238",
|
||||
"rating-icons-level10": "\f239",
|
||||
"rating-icons-level1": "\f23a",
|
||||
"folder-tabs-user": "\f23b",
|
||||
"folder-tabs-star": "\f23c",
|
||||
"folder-tabs-group": "\f23d",
|
||||
"folder-tabs-folder": "\f23e",
|
||||
"folder-tabs-chats": "\f23f",
|
||||
"folder-tabs-chat": "\f240",
|
||||
"folder-tabs-channel": "\f241",
|
||||
"folder-tabs-bot": "\f242",
|
||||
"message-read": "\f199",
|
||||
"message-succeeded": "\f19a",
|
||||
"message": "\f19b",
|
||||
"microphone-alt": "\f19c",
|
||||
"microphone": "\f19d",
|
||||
"monospace": "\f19e",
|
||||
"more-circle": "\f19f",
|
||||
"more": "\f1a0",
|
||||
"move-caption-down": "\f1a1",
|
||||
"move-caption-up": "\f1a2",
|
||||
"mute": "\f1a3",
|
||||
"muted": "\f1a4",
|
||||
"my-notes": "\f1a5",
|
||||
"new-chat-filled": "\f1a6",
|
||||
"next-link": "\f1a7",
|
||||
"next": "\f1a8",
|
||||
"nochannel": "\f1a9",
|
||||
"noise-suppression": "\f1aa",
|
||||
"non-contacts": "\f1ab",
|
||||
"note": "\f1ac",
|
||||
"one-filled": "\f1ad",
|
||||
"open-in-new-tab": "\f1ae",
|
||||
"password-off": "\f1af",
|
||||
"pause": "\f1b0",
|
||||
"permissions": "\f1b1",
|
||||
"phone-discard-outline": "\f1b2",
|
||||
"phone-discard": "\f1b3",
|
||||
"phone": "\f1b4",
|
||||
"photo": "\f1b5",
|
||||
"pin-badge": "\f1b6",
|
||||
"pin-list": "\f1b7",
|
||||
"pin": "\f1b8",
|
||||
"pinned-chat": "\f1b9",
|
||||
"pinned-message": "\f1ba",
|
||||
"pip": "\f1bb",
|
||||
"play-story": "\f1bc",
|
||||
"play": "\f1bd",
|
||||
"poll": "\f1be",
|
||||
"previous": "\f1bf",
|
||||
"privacy-policy": "\f1c0",
|
||||
"proof-of-ownership": "\f1c1",
|
||||
"quote-text": "\f1c2",
|
||||
"quote": "\f1c3",
|
||||
"radial-badge": "\f1c4",
|
||||
"rating-icons-level1": "\f1c5",
|
||||
"rating-icons-level10": "\f1c6",
|
||||
"rating-icons-level2": "\f1c7",
|
||||
"rating-icons-level20": "\f1c8",
|
||||
"rating-icons-level3": "\f1c9",
|
||||
"rating-icons-level30": "\f1ca",
|
||||
"rating-icons-level4": "\f1cb",
|
||||
"rating-icons-level40": "\f1cc",
|
||||
"rating-icons-level5": "\f1cd",
|
||||
"rating-icons-level50": "\f1ce",
|
||||
"rating-icons-level6": "\f1cf",
|
||||
"rating-icons-level60": "\f1d0",
|
||||
"rating-icons-level7": "\f1d1",
|
||||
"rating-icons-level70": "\f1d2",
|
||||
"rating-icons-level8": "\f1d3",
|
||||
"rating-icons-level80": "\f1d4",
|
||||
"rating-icons-level9": "\f1d5",
|
||||
"rating-icons-level90": "\f1d6",
|
||||
"rating-icons-negative": "\f1d7",
|
||||
"readchats": "\f1d8",
|
||||
"recent": "\f1d9",
|
||||
"redo": "\f1da",
|
||||
"refund": "\f1db",
|
||||
"reload": "\f1dc",
|
||||
"remove-quote": "\f1dd",
|
||||
"remove": "\f1de",
|
||||
"reopen-topic": "\f1df",
|
||||
"reorder-tabs": "\f1e0",
|
||||
"replace": "\f1e1",
|
||||
"replies": "\f1e2",
|
||||
"reply-filled": "\f1e3",
|
||||
"reply": "\f1e4",
|
||||
"revenue-split": "\f1e5",
|
||||
"revote": "\f1e6",
|
||||
"rotate": "\f1e7",
|
||||
"save-story": "\f1e8",
|
||||
"saved-messages": "\f1e9",
|
||||
"schedule": "\f1ea",
|
||||
"scheduled": "\f1eb",
|
||||
"sd-photo": "\f1ec",
|
||||
"search": "\f1ed",
|
||||
"select": "\f1ee",
|
||||
"sell-outline": "\f1ef",
|
||||
"sell": "\f1f0",
|
||||
"send-outline": "\f1f1",
|
||||
"send": "\f1f2",
|
||||
"settings-filled": "\f1f3",
|
||||
"settings": "\f1f4",
|
||||
"share-filled": "\f1f5",
|
||||
"share-screen-outlined": "\f1f6",
|
||||
"share-screen-stop": "\f1f7",
|
||||
"share-screen": "\f1f8",
|
||||
"show-message": "\f1f9",
|
||||
"sidebar": "\f1fa",
|
||||
"skip-next": "\f1fb",
|
||||
"skip-previous": "\f1fc",
|
||||
"smallscreen": "\f1fd",
|
||||
"smile": "\f1fe",
|
||||
"sort-by-date": "\f1ff",
|
||||
"sort-by-number": "\f200",
|
||||
"sort-by-price": "\f201",
|
||||
"sort": "\f202",
|
||||
"speaker-muted-story": "\f203",
|
||||
"speaker-outline": "\f204",
|
||||
"speaker-story": "\f205",
|
||||
"speaker": "\f206",
|
||||
"spoiler-disable": "\f207",
|
||||
"spoiler": "\f208",
|
||||
"sport": "\f209",
|
||||
"star": "\f20a",
|
||||
"stars-lock": "\f20b",
|
||||
"stars-refund": "\f20c",
|
||||
"stats": "\f20d",
|
||||
"stealth-future": "\f20e",
|
||||
"stealth-past": "\f20f",
|
||||
"stickers": "\f210",
|
||||
"stop-raising-hand": "\f211",
|
||||
"stop": "\f212",
|
||||
"story-caption": "\f213",
|
||||
"story-expired": "\f214",
|
||||
"story-priority": "\f215",
|
||||
"story-reply": "\f216",
|
||||
"strikethrough": "\f217",
|
||||
"tag-add": "\f218",
|
||||
"tag-crossed": "\f219",
|
||||
"tag-filter": "\f21a",
|
||||
"tag-name": "\f21b",
|
||||
"tag": "\f21c",
|
||||
"timer": "\f21d",
|
||||
"toncoin": "\f21e",
|
||||
"tools": "\f21f",
|
||||
"topic-new": "\f220",
|
||||
"trade": "\f221",
|
||||
"transcribe": "\f222",
|
||||
"truck": "\f223",
|
||||
"unarchive": "\f224",
|
||||
"underlined": "\f225",
|
||||
"understood": "\f226",
|
||||
"undo": "\f227",
|
||||
"unique-profile": "\f228",
|
||||
"unlist-outline": "\f229",
|
||||
"unlist": "\f22a",
|
||||
"unlock-badge": "\f22b",
|
||||
"unlock": "\f22c",
|
||||
"unmute": "\f22d",
|
||||
"unpin": "\f22e",
|
||||
"unread": "\f22f",
|
||||
"up": "\f230",
|
||||
"user-filled": "\f231",
|
||||
"user-online": "\f232",
|
||||
"user-stars": "\f233",
|
||||
"user-tag": "\f234",
|
||||
"user": "\f235",
|
||||
"video-outlined": "\f236",
|
||||
"video-stop": "\f237",
|
||||
"video": "\f238",
|
||||
"view-once": "\f239",
|
||||
"voice-chat": "\f23a",
|
||||
"volume-1": "\f23b",
|
||||
"volume-2": "\f23c",
|
||||
"volume-3": "\f23d",
|
||||
"warning": "\f23e",
|
||||
"web": "\f23f",
|
||||
"webapp": "\f240",
|
||||
"word-wrap": "\f241",
|
||||
"zoom-in": "\f242",
|
||||
"zoom-out": "\f243",
|
||||
);
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -1,323 +1,324 @@
|
||||
export type FontIconName =
|
||||
| 'zoom-out'
|
||||
| 'zoom-in'
|
||||
| 'word-wrap'
|
||||
| 'webapp'
|
||||
| 'web'
|
||||
| 'warning'
|
||||
| 'volume-3'
|
||||
| 'volume-2'
|
||||
| 'volume-1'
|
||||
| 'voice-chat'
|
||||
| 'view-once'
|
||||
| 'video'
|
||||
| 'video-stop'
|
||||
| 'video-outlined'
|
||||
| 'user'
|
||||
| 'user-stars'
|
||||
| 'user-online'
|
||||
| 'user-filled'
|
||||
| 'up'
|
||||
| 'unread'
|
||||
| 'unpin'
|
||||
| 'unmute'
|
||||
| 'unlock'
|
||||
| 'unlock-badge'
|
||||
| 'unlist'
|
||||
| 'unlist-outline'
|
||||
| 'unique-profile'
|
||||
| 'undo'
|
||||
| 'understood'
|
||||
| 'underlined'
|
||||
| 'unarchive'
|
||||
| 'truck'
|
||||
| 'transcribe'
|
||||
| 'trade'
|
||||
| 'topic-new'
|
||||
| 'tools'
|
||||
| 'toncoin'
|
||||
| 'timer'
|
||||
| 'tag'
|
||||
| 'tag-name'
|
||||
| 'tag-filter'
|
||||
| 'tag-crossed'
|
||||
| 'tag-add'
|
||||
| 'strikethrough'
|
||||
| 'story-reply'
|
||||
| 'story-priority'
|
||||
| 'story-expired'
|
||||
| 'story-caption'
|
||||
| 'stop'
|
||||
| 'stop-raising-hand'
|
||||
| 'stickers'
|
||||
| 'stealth-past'
|
||||
| 'stealth-future'
|
||||
| 'stats'
|
||||
| 'stars-refund'
|
||||
| 'stars-lock'
|
||||
| 'star'
|
||||
| 'sport'
|
||||
| 'spoiler'
|
||||
| 'spoiler-disable'
|
||||
| 'speaker'
|
||||
| 'speaker-story'
|
||||
| 'speaker-outline'
|
||||
| 'speaker-muted-story'
|
||||
| 'sort'
|
||||
| 'sort-by-price'
|
||||
| 'sort-by-number'
|
||||
| 'sort-by-date'
|
||||
| 'smile'
|
||||
| 'smallscreen'
|
||||
| 'skip-previous'
|
||||
| 'skip-next'
|
||||
| 'sidebar'
|
||||
| 'show-message'
|
||||
| 'share-screen'
|
||||
| 'share-screen-stop'
|
||||
| 'share-screen-outlined'
|
||||
| 'share-filled'
|
||||
| 'settings'
|
||||
| 'settings-filled'
|
||||
| 'send'
|
||||
| 'send-outline'
|
||||
| 'sell'
|
||||
| 'sell-outline'
|
||||
| 'select'
|
||||
| 'search'
|
||||
| 'sd-photo'
|
||||
| 'scheduled'
|
||||
| 'schedule'
|
||||
| 'saved-messages'
|
||||
| 'save-story'
|
||||
| 'rotate'
|
||||
| 'revote'
|
||||
| 'revenue-split'
|
||||
| 'reply'
|
||||
| 'reply-filled'
|
||||
| 'replies'
|
||||
| 'replace'
|
||||
| 'reorder-tabs'
|
||||
| 'reopen-topic'
|
||||
| 'remove'
|
||||
| 'remove-quote'
|
||||
| 'reload'
|
||||
| 'refund'
|
||||
| 'redo'
|
||||
| 'recent'
|
||||
| 'readchats'
|
||||
| 'radial-badge'
|
||||
| 'quote'
|
||||
| 'quote-text'
|
||||
| 'proof-of-ownership'
|
||||
| 'privacy-policy'
|
||||
| 'previous'
|
||||
| 'poll'
|
||||
| 'play'
|
||||
| 'play-story'
|
||||
| 'pip'
|
||||
| 'pinned-message'
|
||||
| 'pinned-chat'
|
||||
| 'pin'
|
||||
| 'pin-list'
|
||||
| 'pin-badge'
|
||||
| 'photo'
|
||||
| 'phone'
|
||||
| 'phone-discard'
|
||||
| 'phone-discard-outline'
|
||||
| 'permissions'
|
||||
| 'pause'
|
||||
| 'password-off'
|
||||
| 'open-in-new-tab'
|
||||
| 'one-filled'
|
||||
| 'note'
|
||||
| 'non-contacts'
|
||||
| 'noise-suppression'
|
||||
| 'nochannel'
|
||||
| 'next'
|
||||
| 'next-link'
|
||||
| 'new-chat-filled'
|
||||
| 'my-notes'
|
||||
| 'muted'
|
||||
| 'mute'
|
||||
| 'move-caption-up'
|
||||
| 'move-caption-down'
|
||||
| 'more'
|
||||
| 'more-circle'
|
||||
| 'monospace'
|
||||
| 'microphone'
|
||||
| 'microphone-alt'
|
||||
| 'message'
|
||||
| 'message-succeeded'
|
||||
| 'message-read'
|
||||
| 'message-pending'
|
||||
| 'message-failed'
|
||||
| 'menu'
|
||||
| 'mention'
|
||||
| 'loop'
|
||||
| 'logout'
|
||||
| 'lock'
|
||||
| 'lock-badge'
|
||||
| 'location'
|
||||
| 'link'
|
||||
| 'link-broken'
|
||||
| 'link-badge'
|
||||
| 'large-play'
|
||||
| 'large-pause'
|
||||
| 'language'
|
||||
| 'lamp'
|
||||
| 'keyboard'
|
||||
| 'key'
|
||||
| 'italic'
|
||||
| 'install'
|
||||
| 'info'
|
||||
| 'info-filled'
|
||||
| 'help'
|
||||
| 'heart'
|
||||
| 'heart-outline'
|
||||
| 'hd-photo'
|
||||
| 'hashtag'
|
||||
| 'hand-stop'
|
||||
| 'grouped'
|
||||
| 'grouped-disable'
|
||||
| 'group'
|
||||
| 'group-filled'
|
||||
| 'gift'
|
||||
| 'gift-transfer-inline'
|
||||
| 'gifs'
|
||||
| 'fullscreen'
|
||||
| 'frozen-time'
|
||||
| 'fragment'
|
||||
| 'forward'
|
||||
| 'forums'
|
||||
| 'fontsize'
|
||||
| 'folder'
|
||||
| 'folder-badge'
|
||||
| 'flip'
|
||||
| 'flag'
|
||||
| 'file-badge'
|
||||
| 'favorite'
|
||||
| 'favorite-filled'
|
||||
| 'eye'
|
||||
| 'eye-outline'
|
||||
| 'eye-crossed'
|
||||
| 'eye-crossed-outline'
|
||||
| 'expand'
|
||||
| 'expand-modal'
|
||||
| 'enter'
|
||||
| 'email'
|
||||
| 'edit'
|
||||
| 'eats'
|
||||
| 'dropdown-arrows'
|
||||
| 'download'
|
||||
| 'down'
|
||||
| 'double-badge'
|
||||
| 'document'
|
||||
| 'diamond'
|
||||
| 'delete'
|
||||
| 'delete-user'
|
||||
| 'delete-left'
|
||||
| 'delete-filled'
|
||||
| 'data'
|
||||
| 'darkmode'
|
||||
| 'crown-wear'
|
||||
| 'crown-wear-outline'
|
||||
| 'crown-take-off'
|
||||
| 'crown-take-off-outline'
|
||||
| 'crop'
|
||||
| 'craft'
|
||||
| 'copy'
|
||||
| 'copy-media'
|
||||
| 'comments'
|
||||
| 'comments-sticker'
|
||||
| 'combine-craft'
|
||||
| 'colorize'
|
||||
| 'collapse'
|
||||
| 'collapse-modal'
|
||||
| 'cloud-download'
|
||||
| 'closed-gift'
|
||||
| 'close'
|
||||
| 'close-topic'
|
||||
| 'close-circle'
|
||||
| 'clock'
|
||||
| 'clock-edit'
|
||||
| 'check'
|
||||
| 'chats-badge'
|
||||
| 'chat-badge'
|
||||
| 'channelviews'
|
||||
| 'channel'
|
||||
| 'channel-filled'
|
||||
| 'cash-circle'
|
||||
| 'card'
|
||||
| 'car'
|
||||
| 'camera'
|
||||
| 'camera-add'
|
||||
| 'calendar'
|
||||
| 'calendar-filter'
|
||||
| 'bug'
|
||||
| 'brush'
|
||||
| 'bots'
|
||||
| 'bot-commands-filled'
|
||||
| 'bot-command'
|
||||
| 'boosts'
|
||||
| 'boostcircle'
|
||||
| 'boost'
|
||||
| 'boost-outline'
|
||||
| 'boost-craft-chance'
|
||||
| 'bold'
|
||||
| 'avatar-saved-messages'
|
||||
| 'avatar-deleted-account'
|
||||
| 'avatar-archived-chats'
|
||||
| 'author-hidden'
|
||||
| 'auction'
|
||||
| 'auction-next-round'
|
||||
| 'auction-filled'
|
||||
| 'auction-drop'
|
||||
| 'attach'
|
||||
| 'ask-support'
|
||||
| 'arrow-right'
|
||||
| 'arrow-left'
|
||||
| 'arrow-down'
|
||||
| 'arrow-down-circle'
|
||||
| 'archive'
|
||||
| 'archive-to-main'
|
||||
| 'archive-from-main'
|
||||
| 'archive-filled'
|
||||
| 'animations'
|
||||
| 'animals'
|
||||
| 'allow-speak'
|
||||
| 'admin'
|
||||
| 'add'
|
||||
| 'add-user'
|
||||
| 'add-user-filled'
|
||||
| 'add-one-badge'
|
||||
| 'add-filled'
|
||||
| 'add-caption'
|
||||
| 'active-sessions'
|
||||
| 'rating-icons-negative'
|
||||
| 'rating-icons-level90'
|
||||
| 'rating-icons-level9'
|
||||
| 'rating-icons-level80'
|
||||
| 'rating-icons-level8'
|
||||
| 'rating-icons-level70'
|
||||
| 'rating-icons-level7'
|
||||
| 'rating-icons-level60'
|
||||
| 'rating-icons-level6'
|
||||
| 'rating-icons-level50'
|
||||
| 'rating-icons-level5'
|
||||
| 'rating-icons-level40'
|
||||
| 'rating-icons-level4'
|
||||
| 'rating-icons-level30'
|
||||
| 'rating-icons-level3'
|
||||
| 'rating-icons-level20'
|
||||
| 'rating-icons-level2'
|
||||
| 'rating-icons-level10'
|
||||
| 'rating-icons-level1'
|
||||
| 'folder-tabs-user'
|
||||
| 'folder-tabs-star'
|
||||
| 'folder-tabs-group'
|
||||
| 'folder-tabs-folder'
|
||||
| 'folder-tabs-chats'
|
||||
| 'folder-tabs-chat'
|
||||
| 'add-caption'
|
||||
| 'add-filled'
|
||||
| 'add-one-badge'
|
||||
| 'add-user-filled'
|
||||
| 'add-user'
|
||||
| 'add'
|
||||
| 'admin'
|
||||
| 'allow-speak'
|
||||
| 'animals'
|
||||
| 'animations'
|
||||
| 'archive-filled'
|
||||
| 'archive-from-main'
|
||||
| 'archive-to-main'
|
||||
| 'archive'
|
||||
| 'arrow-down-circle'
|
||||
| 'arrow-down'
|
||||
| 'arrow-left'
|
||||
| 'arrow-right'
|
||||
| 'ask-support'
|
||||
| 'attach'
|
||||
| 'auction-drop'
|
||||
| 'auction-filled'
|
||||
| 'auction-next-round'
|
||||
| 'auction'
|
||||
| 'author-hidden'
|
||||
| 'avatar-archived-chats'
|
||||
| 'avatar-deleted-account'
|
||||
| 'avatar-saved-messages'
|
||||
| 'bold'
|
||||
| 'boost-craft-chance'
|
||||
| 'boost-outline'
|
||||
| 'boost'
|
||||
| 'boostcircle'
|
||||
| 'boosts'
|
||||
| 'bot-command'
|
||||
| 'bot-commands-filled'
|
||||
| 'bots'
|
||||
| 'brush'
|
||||
| 'bug'
|
||||
| 'calendar-filter'
|
||||
| 'calendar'
|
||||
| 'camera-add'
|
||||
| 'camera'
|
||||
| 'car'
|
||||
| 'card'
|
||||
| 'cash-circle'
|
||||
| 'channel-filled'
|
||||
| 'channel'
|
||||
| 'channelviews'
|
||||
| 'chat-badge'
|
||||
| 'chats-badge'
|
||||
| 'check'
|
||||
| 'clock-edit'
|
||||
| 'clock'
|
||||
| 'close-circle'
|
||||
| 'close-topic'
|
||||
| 'close'
|
||||
| 'closed-gift'
|
||||
| 'cloud-download'
|
||||
| 'collapse-modal'
|
||||
| 'collapse'
|
||||
| 'colorize'
|
||||
| 'combine-craft'
|
||||
| 'comments-sticker'
|
||||
| 'comments'
|
||||
| 'copy-media'
|
||||
| 'copy'
|
||||
| 'craft'
|
||||
| 'crop'
|
||||
| 'crown-take-off-outline'
|
||||
| 'crown-take-off'
|
||||
| 'crown-wear-outline'
|
||||
| 'crown-wear'
|
||||
| 'darkmode'
|
||||
| 'data'
|
||||
| 'delete-filled'
|
||||
| 'delete-left'
|
||||
| 'delete-user'
|
||||
| 'delete'
|
||||
| 'diamond'
|
||||
| 'document'
|
||||
| 'double-badge'
|
||||
| 'down'
|
||||
| 'download'
|
||||
| 'dropdown-arrows'
|
||||
| 'eats'
|
||||
| 'edit'
|
||||
| 'email'
|
||||
| 'enter'
|
||||
| 'expand-modal'
|
||||
| 'expand'
|
||||
| 'eye-crossed-outline'
|
||||
| 'eye-crossed'
|
||||
| 'eye-outline'
|
||||
| 'eye'
|
||||
| 'favorite-filled'
|
||||
| 'favorite'
|
||||
| 'file-badge'
|
||||
| 'flag'
|
||||
| 'flip'
|
||||
| 'folder-badge'
|
||||
| 'folder-tabs-bot'
|
||||
| 'folder-tabs-channel'
|
||||
| 'folder-tabs-bot';
|
||||
| 'folder-tabs-chat'
|
||||
| 'folder-tabs-chats'
|
||||
| 'folder-tabs-folder'
|
||||
| 'folder-tabs-group'
|
||||
| 'folder-tabs-star'
|
||||
| 'folder-tabs-user'
|
||||
| 'folder'
|
||||
| 'fontsize'
|
||||
| 'forums'
|
||||
| 'forward'
|
||||
| 'fragment'
|
||||
| 'frozen-time'
|
||||
| 'fullscreen'
|
||||
| 'gifs'
|
||||
| 'gift-transfer-inline'
|
||||
| 'gift'
|
||||
| 'group-filled'
|
||||
| 'group'
|
||||
| 'grouped-disable'
|
||||
| 'grouped'
|
||||
| 'hand-stop'
|
||||
| 'hashtag'
|
||||
| 'hd-photo'
|
||||
| 'heart-outline'
|
||||
| 'heart'
|
||||
| 'help'
|
||||
| 'info-filled'
|
||||
| 'info'
|
||||
| 'install'
|
||||
| 'italic'
|
||||
| 'key'
|
||||
| 'keyboard'
|
||||
| 'lamp'
|
||||
| 'language'
|
||||
| 'large-pause'
|
||||
| 'large-play'
|
||||
| 'link-badge'
|
||||
| 'link-broken'
|
||||
| 'link'
|
||||
| 'location'
|
||||
| 'lock-badge'
|
||||
| 'lock'
|
||||
| 'logout'
|
||||
| 'loop'
|
||||
| 'mention'
|
||||
| 'menu'
|
||||
| 'message-failed'
|
||||
| 'message-pending'
|
||||
| 'message-read'
|
||||
| 'message-succeeded'
|
||||
| 'message'
|
||||
| 'microphone-alt'
|
||||
| 'microphone'
|
||||
| 'monospace'
|
||||
| 'more-circle'
|
||||
| 'more'
|
||||
| 'move-caption-down'
|
||||
| 'move-caption-up'
|
||||
| 'mute'
|
||||
| 'muted'
|
||||
| 'my-notes'
|
||||
| 'new-chat-filled'
|
||||
| 'next-link'
|
||||
| 'next'
|
||||
| 'nochannel'
|
||||
| 'noise-suppression'
|
||||
| 'non-contacts'
|
||||
| 'note'
|
||||
| 'one-filled'
|
||||
| 'open-in-new-tab'
|
||||
| 'password-off'
|
||||
| 'pause'
|
||||
| 'permissions'
|
||||
| 'phone-discard-outline'
|
||||
| 'phone-discard'
|
||||
| 'phone'
|
||||
| 'photo'
|
||||
| 'pin-badge'
|
||||
| 'pin-list'
|
||||
| 'pin'
|
||||
| 'pinned-chat'
|
||||
| 'pinned-message'
|
||||
| 'pip'
|
||||
| 'play-story'
|
||||
| 'play'
|
||||
| 'poll'
|
||||
| 'previous'
|
||||
| 'privacy-policy'
|
||||
| 'proof-of-ownership'
|
||||
| 'quote-text'
|
||||
| 'quote'
|
||||
| 'radial-badge'
|
||||
| 'rating-icons-level1'
|
||||
| 'rating-icons-level10'
|
||||
| 'rating-icons-level2'
|
||||
| 'rating-icons-level20'
|
||||
| 'rating-icons-level3'
|
||||
| 'rating-icons-level30'
|
||||
| 'rating-icons-level4'
|
||||
| 'rating-icons-level40'
|
||||
| 'rating-icons-level5'
|
||||
| 'rating-icons-level50'
|
||||
| 'rating-icons-level6'
|
||||
| 'rating-icons-level60'
|
||||
| 'rating-icons-level7'
|
||||
| 'rating-icons-level70'
|
||||
| 'rating-icons-level8'
|
||||
| 'rating-icons-level80'
|
||||
| 'rating-icons-level9'
|
||||
| 'rating-icons-level90'
|
||||
| 'rating-icons-negative'
|
||||
| 'readchats'
|
||||
| 'recent'
|
||||
| 'redo'
|
||||
| 'refund'
|
||||
| 'reload'
|
||||
| 'remove-quote'
|
||||
| 'remove'
|
||||
| 'reopen-topic'
|
||||
| 'reorder-tabs'
|
||||
| 'replace'
|
||||
| 'replies'
|
||||
| 'reply-filled'
|
||||
| 'reply'
|
||||
| 'revenue-split'
|
||||
| 'revote'
|
||||
| 'rotate'
|
||||
| 'save-story'
|
||||
| 'saved-messages'
|
||||
| 'schedule'
|
||||
| 'scheduled'
|
||||
| 'sd-photo'
|
||||
| 'search'
|
||||
| 'select'
|
||||
| 'sell-outline'
|
||||
| 'sell'
|
||||
| 'send-outline'
|
||||
| 'send'
|
||||
| 'settings-filled'
|
||||
| 'settings'
|
||||
| 'share-filled'
|
||||
| 'share-screen-outlined'
|
||||
| 'share-screen-stop'
|
||||
| 'share-screen'
|
||||
| 'show-message'
|
||||
| 'sidebar'
|
||||
| 'skip-next'
|
||||
| 'skip-previous'
|
||||
| 'smallscreen'
|
||||
| 'smile'
|
||||
| 'sort-by-date'
|
||||
| 'sort-by-number'
|
||||
| 'sort-by-price'
|
||||
| 'sort'
|
||||
| 'speaker-muted-story'
|
||||
| 'speaker-outline'
|
||||
| 'speaker-story'
|
||||
| 'speaker'
|
||||
| 'spoiler-disable'
|
||||
| 'spoiler'
|
||||
| 'sport'
|
||||
| 'star'
|
||||
| 'stars-lock'
|
||||
| 'stars-refund'
|
||||
| 'stats'
|
||||
| 'stealth-future'
|
||||
| 'stealth-past'
|
||||
| 'stickers'
|
||||
| 'stop-raising-hand'
|
||||
| 'stop'
|
||||
| 'story-caption'
|
||||
| 'story-expired'
|
||||
| 'story-priority'
|
||||
| 'story-reply'
|
||||
| 'strikethrough'
|
||||
| 'tag-add'
|
||||
| 'tag-crossed'
|
||||
| 'tag-filter'
|
||||
| 'tag-name'
|
||||
| 'tag'
|
||||
| 'timer'
|
||||
| 'toncoin'
|
||||
| 'tools'
|
||||
| 'topic-new'
|
||||
| 'trade'
|
||||
| 'transcribe'
|
||||
| 'truck'
|
||||
| 'unarchive'
|
||||
| 'underlined'
|
||||
| 'understood'
|
||||
| 'undo'
|
||||
| 'unique-profile'
|
||||
| 'unlist-outline'
|
||||
| 'unlist'
|
||||
| 'unlock-badge'
|
||||
| 'unlock'
|
||||
| 'unmute'
|
||||
| 'unpin'
|
||||
| 'unread'
|
||||
| 'up'
|
||||
| 'user-filled'
|
||||
| 'user-online'
|
||||
| 'user-stars'
|
||||
| 'user-tag'
|
||||
| 'user'
|
||||
| 'video-outlined'
|
||||
| 'video-stop'
|
||||
| 'video'
|
||||
| 'view-once'
|
||||
| 'voice-chat'
|
||||
| 'volume-1'
|
||||
| 'volume-2'
|
||||
| 'volume-3'
|
||||
| 'warning'
|
||||
| 'web'
|
||||
| 'webapp'
|
||||
| 'word-wrap'
|
||||
| 'zoom-in'
|
||||
| 'zoom-out';
|
||||
|
||||
31
src/types/language.d.ts
vendored
31
src/types/language.d.ts
vendored
@ -112,6 +112,7 @@ export interface LangPair {
|
||||
'UserRestrictionsNoChangeInfo': undefined;
|
||||
'UserRestrictionsInviteUsers': undefined;
|
||||
'UserRestrictionsPinMessages': undefined;
|
||||
'UserRestrictionsEditRank': undefined;
|
||||
'ChatPermissionNotAvailable': undefined;
|
||||
'StatsMessageInteractionsTitle': undefined;
|
||||
'StatsGroupGrowthTitle': undefined;
|
||||
@ -490,6 +491,7 @@ export interface LangPair {
|
||||
'PrivacyExceptions': undefined;
|
||||
'AlwaysAllow': undefined;
|
||||
'EditAdminAddUsers': undefined;
|
||||
'EditAdminEditRank': undefined;
|
||||
'NeverAllow': undefined;
|
||||
'AlwaysAllowPlaceholder': undefined;
|
||||
'NeverAllowPlaceholder': undefined;
|
||||
@ -2004,6 +2006,17 @@ export interface LangPair {
|
||||
'GiftPreviewToggleRegularModels': undefined;
|
||||
'AriaGiftPreviewPlay': undefined;
|
||||
'AriaGiftPreviewStop': undefined;
|
||||
'RankModalEdit': undefined;
|
||||
'RankModalEditMy': undefined;
|
||||
'MemberContextEditRank': undefined;
|
||||
'RankMemberTag': undefined;
|
||||
'RankAdminTag': undefined;
|
||||
'RankOwnerTag': undefined;
|
||||
'RankModalMemberTagTitle': undefined;
|
||||
'RankModalAdminTagTitle': undefined;
|
||||
'RankModalOwnerTagTitle': undefined;
|
||||
'RankEditSave': undefined;
|
||||
'RankEditTextOwn': undefined;
|
||||
'MenuAddCaption': undefined;
|
||||
}
|
||||
|
||||
@ -3519,6 +3532,24 @@ export interface LangPairWithVariables<V = LangVariable> {
|
||||
'BotAuthSuccessText': {
|
||||
'url': V;
|
||||
};
|
||||
'RankModalMemberText': {
|
||||
'tag': V;
|
||||
'author': V;
|
||||
'group': V;
|
||||
};
|
||||
'RankModalAdminText': {
|
||||
'tag': V;
|
||||
'author': V;
|
||||
'group': V;
|
||||
};
|
||||
'RankModalOwnerText': {
|
||||
'tag': V;
|
||||
'author': V;
|
||||
'group': V;
|
||||
};
|
||||
'RankEditText': {
|
||||
'user': V;
|
||||
};
|
||||
}
|
||||
|
||||
export interface LangPairPlural {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user