Management / Join Requests: Add animated stickers, various fixes (#1679)
This commit is contained in:
parent
71ef93e993
commit
bb0d846838
1
src/@types/global.d.ts
vendored
1
src/@types/global.d.ts
vendored
@ -46,6 +46,7 @@ type EmojiWithSkins = Record<number, Emoji>;
|
|||||||
type AllEmojis = Record<string, Emoji | EmojiWithSkins>;
|
type AllEmojis = Record<string, Emoji | EmojiWithSkins>;
|
||||||
|
|
||||||
declare module '*.png';
|
declare module '*.png';
|
||||||
|
declare module '*.tgs';
|
||||||
|
|
||||||
declare module 'pako/dist/pako_inflate' {
|
declare module 'pako/dist/pako_inflate' {
|
||||||
function inflate(...args: any[]): string;
|
function inflate(...args: any[]): string;
|
||||||
|
|||||||
BIN
src/assets/tgs/invites/Invite.tgs
Normal file
BIN
src/assets/tgs/invites/Invite.tgs
Normal file
Binary file not shown.
BIN
src/assets/tgs/invites/Requests.tgs
Normal file
BIN
src/assets/tgs/invites/Requests.tgs
Normal file
Binary file not shown.
@ -2,43 +2,31 @@ import { ApiMediaFormat } from '../../../api/types';
|
|||||||
|
|
||||||
import * as mediaLoader from '../../../util/mediaLoader';
|
import * as mediaLoader from '../../../util/mediaLoader';
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
import MonkeyIdle from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyIdle.tgs';
|
import MonkeyIdle from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyIdle.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import MonkeyTracking from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyTracking.tgs';
|
import MonkeyTracking from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyTracking.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import MonkeyClose from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyClose.tgs';
|
import MonkeyClose from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyClose.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import MonkeyPeek from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyPeek.tgs';
|
import MonkeyPeek from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyPeek.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import FoldersAll from '../../../assets/tgs/settings/FoldersAll.tgs';
|
import FoldersAll from '../../../assets/tgs/settings/FoldersAll.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import FoldersNew from '../../../assets/tgs/settings/FoldersNew.tgs';
|
import FoldersNew from '../../../assets/tgs/settings/FoldersNew.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import DiscussionGroups from '../../../assets/tgs/settings/DiscussionGroupsDucks.tgs';
|
import DiscussionGroups from '../../../assets/tgs/settings/DiscussionGroupsDucks.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import CameraFlip from '../../../assets/tgs/calls/CameraFlip.tgs';
|
import CameraFlip from '../../../assets/tgs/calls/CameraFlip.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import HandFilled from '../../../assets/tgs/calls/HandFilled.tgs';
|
import HandFilled from '../../../assets/tgs/calls/HandFilled.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import HandOutline from '../../../assets/tgs/calls/HandOutline.tgs';
|
import HandOutline from '../../../assets/tgs/calls/HandOutline.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import Speaker from '../../../assets/tgs/calls/Speaker.tgs';
|
import Speaker from '../../../assets/tgs/calls/Speaker.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import VoiceAllowTalk from '../../../assets/tgs/calls/VoiceAllowTalk.tgs';
|
import VoiceAllowTalk from '../../../assets/tgs/calls/VoiceAllowTalk.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import VoiceMini from '../../../assets/tgs/calls/VoiceMini.tgs';
|
import VoiceMini from '../../../assets/tgs/calls/VoiceMini.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import VoiceMuted from '../../../assets/tgs/calls/VoiceMuted.tgs';
|
import VoiceMuted from '../../../assets/tgs/calls/VoiceMuted.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import VoiceOutlined from '../../../assets/tgs/calls/VoiceOutlined.tgs';
|
import VoiceOutlined from '../../../assets/tgs/calls/VoiceOutlined.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import Peach from '../../../assets/tgs/animatedEmojis/Peach.tgs';
|
import Peach from '../../../assets/tgs/animatedEmojis/Peach.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import Eggplant from '../../../assets/tgs/animatedEmojis/Eggplant.tgs';
|
import Eggplant from '../../../assets/tgs/animatedEmojis/Eggplant.tgs';
|
||||||
// @ts-ignore
|
|
||||||
import Cumshot from '../../../assets/tgs/animatedEmojis/Cumshot.tgs';
|
import Cumshot from '../../../assets/tgs/animatedEmojis/Cumshot.tgs';
|
||||||
|
|
||||||
|
import JoinRequest from '../../../assets/tgs/invites/Requests.tgs';
|
||||||
|
import Invite from '../../../assets/tgs/invites/Invite.tgs';
|
||||||
|
|
||||||
export const ANIMATED_STICKERS_PATHS = {
|
export const ANIMATED_STICKERS_PATHS = {
|
||||||
MonkeyIdle,
|
MonkeyIdle,
|
||||||
MonkeyTracking,
|
MonkeyTracking,
|
||||||
@ -58,6 +46,8 @@ export const ANIMATED_STICKERS_PATHS = {
|
|||||||
Peach,
|
Peach,
|
||||||
Eggplant,
|
Eggplant,
|
||||||
Cumshot,
|
Cumshot,
|
||||||
|
JoinRequest,
|
||||||
|
Invite,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function getAnimationData(name: keyof typeof ANIMATED_STICKERS_PATHS) {
|
export default function getAnimationData(name: keyof typeof ANIMATED_STICKERS_PATHS) {
|
||||||
|
|||||||
@ -22,7 +22,12 @@ type StateProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Dialogs: FC<StateProps> = ({ dialogs }) => {
|
const Dialogs: FC<StateProps> = ({ dialogs }) => {
|
||||||
const { dismissDialog, acceptInviteConfirmation, sendMessage } = getDispatch();
|
const {
|
||||||
|
dismissDialog,
|
||||||
|
acceptInviteConfirmation,
|
||||||
|
sendMessage,
|
||||||
|
showNotification,
|
||||||
|
} = getDispatch();
|
||||||
const [isModalOpen, openModal, closeModal] = useFlag();
|
const [isModalOpen, openModal, closeModal] = useFlag();
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
@ -60,6 +65,9 @@ const Dialogs: FC<StateProps> = ({ dialogs }) => {
|
|||||||
acceptInviteConfirmation({
|
acceptInviteConfirmation({
|
||||||
hash,
|
hash,
|
||||||
});
|
});
|
||||||
|
showNotification({
|
||||||
|
message: isChannel ? lang('RequestToJoinChannelSentDescription') : lang('RequestToJoinGroupSentDescription'),
|
||||||
|
});
|
||||||
closeModal();
|
closeModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,8 +87,8 @@ const Dialogs: FC<StateProps> = ({ dialogs }) => {
|
|||||||
header={renderInviteHeader(title, photo)}
|
header={renderInviteHeader(title, photo)}
|
||||||
onCloseAnimationEnd={dismissDialog}
|
onCloseAnimationEnd={dismissDialog}
|
||||||
>
|
>
|
||||||
{about && <p className="modal-about">{renderText(about)}</p>}
|
{participantsCount !== undefined && <p className="modal-help">{participantsText}</p>}
|
||||||
{participantsCount !== undefined && <p>{participantsText}</p>}
|
{about && <p className="modal-about">{renderText(about, ['br'])}</p>}
|
||||||
{isRequestNeeded && (
|
{isRequestNeeded && (
|
||||||
<p className="modal-help">
|
<p className="modal-help">
|
||||||
{isChannel
|
{isChannel
|
||||||
|
|||||||
@ -22,12 +22,15 @@ import {
|
|||||||
} from '../../modules/helpers';
|
} from '../../modules/helpers';
|
||||||
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
|
import useFlag from '../../hooks/useFlag';
|
||||||
|
import { getDayStartAt } from '../../util/dateFormat';
|
||||||
|
|
||||||
import SearchInput from '../ui/SearchInput';
|
import SearchInput from '../ui/SearchInput';
|
||||||
import Button from '../ui/Button';
|
import Button from '../ui/Button';
|
||||||
import Transition from '../ui/Transition';
|
import Transition from '../ui/Transition';
|
||||||
|
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||||
|
|
||||||
import './RightHeader.scss';
|
import './RightHeader.scss';
|
||||||
import { getDayStartAt } from '../../util/dateFormat';
|
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
chatId?: string;
|
chatId?: string;
|
||||||
@ -131,6 +134,7 @@ const RightHeader: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const backButtonRef = useRef<HTMLDivElement>(null);
|
const backButtonRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [isDeleteDialogOpen, openDeleteDialog, closeDeleteDialog] = useFlag();
|
||||||
|
|
||||||
const handleEditInviteClick = useCallback(() => {
|
const handleEditInviteClick = useCallback(() => {
|
||||||
setEditingExportedInvite({ chatId: chatId!, invite: currentInviteInfo! });
|
setEditingExportedInvite({ chatId: chatId!, invite: currentInviteInfo! });
|
||||||
@ -140,7 +144,8 @@ const RightHeader: FC<OwnProps & StateProps> = ({
|
|||||||
const handleDeleteInviteClick = useCallback(() => {
|
const handleDeleteInviteClick = useCallback(() => {
|
||||||
deleteExportedChatInvite({ chatId: chatId!, link: currentInviteInfo!.link });
|
deleteExportedChatInvite({ chatId: chatId!, link: currentInviteInfo!.link });
|
||||||
onScreenSelect(ManagementScreens.Invites);
|
onScreenSelect(ManagementScreens.Invites);
|
||||||
}, [chatId, currentInviteInfo, deleteExportedChatInvite, onScreenSelect]);
|
closeDeleteDialog();
|
||||||
|
}, [chatId, closeDeleteDialog, currentInviteInfo, deleteExportedChatInvite, onScreenSelect]);
|
||||||
|
|
||||||
const handleMessageSearchQueryChange = useCallback((query: string) => {
|
const handleMessageSearchQueryChange = useCallback((query: string) => {
|
||||||
setLocalTextSearchQuery({ query });
|
setLocalTextSearchQuery({ query });
|
||||||
@ -305,15 +310,26 @@ const RightHeader: FC<OwnProps & StateProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{currentInviteInfo && currentInviteInfo.isRevoked && (
|
{currentInviteInfo && currentInviteInfo.isRevoked && (
|
||||||
<Button
|
<>
|
||||||
round
|
<Button
|
||||||
color="danger"
|
round
|
||||||
size="smaller"
|
color="danger"
|
||||||
ariaLabel={lang('Delete')}
|
size="smaller"
|
||||||
onClick={handleDeleteInviteClick}
|
ariaLabel={lang('Delete')}
|
||||||
>
|
onClick={openDeleteDialog}
|
||||||
<i className="icon-delete" />
|
>
|
||||||
</Button>
|
<i className="icon-delete" />
|
||||||
|
</Button>
|
||||||
|
<ConfirmDialog
|
||||||
|
isOpen={isDeleteDialogOpen}
|
||||||
|
onClose={closeDeleteDialog}
|
||||||
|
title={lang('DeleteLink')}
|
||||||
|
text={lang('DeleteLinkHelp')}
|
||||||
|
confirmIsDestructive
|
||||||
|
confirmLabel={lang('Delete')}
|
||||||
|
confirmHandler={handleDeleteInviteClick}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -21,17 +21,29 @@
|
|||||||
&__user {
|
&__user {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__user-info {
|
&__user-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__user-subtitle {
|
&__user-subtitle {
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__user-name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__date {
|
&__date {
|
||||||
|
|||||||
@ -50,7 +50,7 @@ const JoinRequest: FC<OwnProps & StateProps> = ({
|
|||||||
? formatTime(lang, fixedDate) : formatHumanDate(lang, fixedDate, true, false, true);
|
? formatTime(lang, fixedDate) : formatHumanDate(lang, fixedDate, true, false, true);
|
||||||
|
|
||||||
const handleUserClick = () => {
|
const handleUserClick = () => {
|
||||||
openUserInfo({ userId });
|
openUserInfo({ id: userId });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAcceptRequest = useCallback(() => {
|
const handleAcceptRequest = useCallback(() => {
|
||||||
|
|||||||
@ -111,8 +111,7 @@ const ManageGroupMembers: FC<OwnProps & StateProps> = ({
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !user.isSelf
|
return (isChannel || user.canBeInvitedToGroup || !isUserBot(user))
|
||||||
&& (isChannel || user.canBeInvitedToGroup || !isUserBot(user))
|
|
||||||
&& (!noAdmins || !adminIds.includes(contactId));
|
&& (!noAdmins || !adminIds.includes(contactId));
|
||||||
}),
|
}),
|
||||||
chatsById,
|
chatsById,
|
||||||
|
|||||||
@ -59,6 +59,7 @@ const ManageInvite: FC<OwnProps & StateProps> = ({
|
|||||||
const [selectedExpireOption, setSelectedExpireOption] = useState('unlimited');
|
const [selectedExpireOption, setSelectedExpireOption] = useState('unlimited');
|
||||||
const [customUsageLimit, setCustomUsageLimit] = useState<number | undefined>(10);
|
const [customUsageLimit, setCustomUsageLimit] = useState<number | undefined>(10);
|
||||||
const [selectedUsageOption, setSelectedUsageOption] = useState('0');
|
const [selectedUsageOption, setSelectedUsageOption] = useState('0');
|
||||||
|
const [isSubmitBlocked, setIsSubmitBlocked] = useState(false);
|
||||||
|
|
||||||
useHistoryBack(isActive, onClose);
|
useHistoryBack(isActive, onClose);
|
||||||
|
|
||||||
@ -81,8 +82,9 @@ const ManageInvite: FC<OwnProps & StateProps> = ({
|
|||||||
setCustomUsageLimit(usageLimit);
|
setCustomUsageLimit(usageLimit);
|
||||||
}
|
}
|
||||||
if (expireDate) {
|
if (expireDate) {
|
||||||
|
const minSafeDate = getServerTime(serverTimeOffset) + DEFAULT_CUSTOM_EXPIRE_DATE;
|
||||||
setSelectedExpireOption('custom');
|
setSelectedExpireOption('custom');
|
||||||
setCustomExpireDate(expireDate * 1000);
|
setCustomExpireDate(Math.max(expireDate, minSafeDate) * 1000);
|
||||||
}
|
}
|
||||||
if (editingIsRequestNeeded) {
|
if (editingIsRequestNeeded) {
|
||||||
setIsRequestNeeded(true);
|
setIsRequestNeeded(true);
|
||||||
@ -108,6 +110,7 @@ const ManageInvite: FC<OwnProps & StateProps> = ({
|
|||||||
}, [closeCalendar]);
|
}, [closeCalendar]);
|
||||||
|
|
||||||
const handleSaveClick = useCallback(() => {
|
const handleSaveClick = useCallback(() => {
|
||||||
|
setIsSubmitBlocked(true);
|
||||||
const usageLimit = selectedUsageOption === 'custom' ? customUsageLimit : selectedUsageOption;
|
const usageLimit = selectedUsageOption === 'custom' ? customUsageLimit : selectedUsageOption;
|
||||||
let expireDate;
|
let expireDate;
|
||||||
switch (selectedExpireOption) {
|
switch (selectedExpireOption) {
|
||||||
@ -240,6 +243,7 @@ const ManageInvite: FC<OwnProps & StateProps> = ({
|
|||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
isShown
|
isShown
|
||||||
onClick={handleSaveClick}
|
onClick={handleSaveClick}
|
||||||
|
disabled={isSubmitBlocked}
|
||||||
ariaLabel={editingInvite ? lang('SaveLink') : lang('CreateLink')}
|
ariaLabel={editingInvite ? lang('SaveLink') : lang('CreateLink')}
|
||||||
>
|
>
|
||||||
<i className="icon-check" />
|
<i className="icon-check" />
|
||||||
|
|||||||
@ -10,10 +10,13 @@ import useLang from '../../../hooks/useLang';
|
|||||||
import { copyTextToClipboard } from '../../../util/clipboard';
|
import { copyTextToClipboard } from '../../../util/clipboard';
|
||||||
import { getServerTime } from '../../../util/serverTime';
|
import { getServerTime } from '../../../util/serverTime';
|
||||||
import { formatFullDate, formatMediaDateTime, formatTime } from '../../../util/dateFormat';
|
import { formatFullDate, formatMediaDateTime, formatTime } from '../../../util/dateFormat';
|
||||||
|
import { isChatChannel } from '../../../modules/helpers';
|
||||||
|
import { selectChat } from '../../../modules/selectors';
|
||||||
|
|
||||||
import PrivateChatInfo from '../../common/PrivateChatInfo';
|
import PrivateChatInfo from '../../common/PrivateChatInfo';
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
|
import Spinner from '../../ui/Spinner';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
@ -24,7 +27,9 @@ type OwnProps = {
|
|||||||
type StateProps = {
|
type StateProps = {
|
||||||
invite?: ApiExportedInvite;
|
invite?: ApiExportedInvite;
|
||||||
importers?: ApiChatInviteImporter[];
|
importers?: ApiChatInviteImporter[];
|
||||||
|
requesters?: ApiChatInviteImporter[];
|
||||||
admin?: ApiUser;
|
admin?: ApiUser;
|
||||||
|
isChannel?: boolean;
|
||||||
serverTimeOffset: number;
|
serverTimeOffset: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,6 +37,8 @@ const ManageInviteInfo: FC<OwnProps & StateProps> = ({
|
|||||||
chatId,
|
chatId,
|
||||||
invite,
|
invite,
|
||||||
importers,
|
importers,
|
||||||
|
requesters,
|
||||||
|
isChannel,
|
||||||
isActive,
|
isActive,
|
||||||
serverTimeOffset,
|
serverTimeOffset,
|
||||||
onClose,
|
onClose,
|
||||||
@ -39,6 +46,7 @@ const ManageInviteInfo: FC<OwnProps & StateProps> = ({
|
|||||||
const {
|
const {
|
||||||
showNotification,
|
showNotification,
|
||||||
loadChatInviteImporters,
|
loadChatInviteImporters,
|
||||||
|
loadChatInviteRequesters,
|
||||||
openUserInfo,
|
openUserInfo,
|
||||||
} = getDispatch();
|
} = getDispatch();
|
||||||
|
|
||||||
@ -50,8 +58,11 @@ const ManageInviteInfo: FC<OwnProps & StateProps> = ({
|
|||||||
const isExpired = ((invite?.expireDate || 0) - getServerTime(serverTimeOffset)) < 0;
|
const isExpired = ((invite?.expireDate || 0) - getServerTime(serverTimeOffset)) < 0;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (link) loadChatInviteImporters({ chatId, link });
|
if (link) {
|
||||||
}, [chatId, link, loadChatInviteImporters]);
|
loadChatInviteImporters({ chatId, link });
|
||||||
|
loadChatInviteRequesters({ chatId, link });
|
||||||
|
}
|
||||||
|
}, [chatId, link, loadChatInviteImporters, loadChatInviteRequesters]);
|
||||||
|
|
||||||
const handleCopyClicked = useCallback(() => {
|
const handleCopyClicked = useCallback(() => {
|
||||||
copyTextToClipboard(invite!.link);
|
copyTextToClipboard(invite!.link);
|
||||||
@ -63,8 +74,8 @@ const ManageInviteInfo: FC<OwnProps & StateProps> = ({
|
|||||||
useHistoryBack(isActive, onClose);
|
useHistoryBack(isActive, onClose);
|
||||||
|
|
||||||
const renderImporters = () => {
|
const renderImporters = () => {
|
||||||
if (invite?.isRevoked) return undefined;
|
if (!importers?.length && requesters?.length) return undefined;
|
||||||
if (!importers) return <p className="text-muted">{lang('Loading')}</p>;
|
if (!importers) return <Spinner />;
|
||||||
return (
|
return (
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<p>{importers.length ? lang('PeopleJoined', usage) : lang('NoOneJoined')}</p>
|
<p>{importers.length ? lang('PeopleJoined', usage) : lang('NoOneJoined')}</p>
|
||||||
@ -89,6 +100,31 @@ const ManageInviteInfo: FC<OwnProps & StateProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderRequesters = () => {
|
||||||
|
if (invite?.isRevoked) return undefined;
|
||||||
|
if (!requesters && importers) return <Spinner />;
|
||||||
|
if (!requesters?.length) return undefined;
|
||||||
|
return (
|
||||||
|
<div className="section">
|
||||||
|
<p>{isChannel ? lang('SubscribeRequests') : lang('MemberRequests')}</p>
|
||||||
|
<p className="text-muted">
|
||||||
|
{requesters.map((requester) => (
|
||||||
|
<ListItem
|
||||||
|
className="chat-item-clickable scroll-item small-icon"
|
||||||
|
onClick={() => openUserInfo({ id: requester.userId })}
|
||||||
|
>
|
||||||
|
<PrivateChatInfo
|
||||||
|
userId={requester.userId}
|
||||||
|
status={formatMediaDateTime(lang, requester.date * 1000, true)}
|
||||||
|
forceShowSelf
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Management ManageInviteInfo">
|
<div className="Management ManageInviteInfo">
|
||||||
<div className="custom-scroll">
|
<div className="custom-scroll">
|
||||||
@ -98,7 +134,7 @@ const ManageInviteInfo: FC<OwnProps & StateProps> = ({
|
|||||||
{invite && (
|
{invite && (
|
||||||
<>
|
<>
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<h3>{invite.title || invite.link}</h3>
|
<h3 className="link-title">{invite.title || invite.link}</h3>
|
||||||
<input
|
<input
|
||||||
className="form-control"
|
className="form-control"
|
||||||
value={invite.link}
|
value={invite.link}
|
||||||
@ -130,6 +166,7 @@ const ManageInviteInfo: FC<OwnProps & StateProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{renderImporters()}
|
{renderImporters()}
|
||||||
|
{renderRequesters()}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -140,12 +177,15 @@ const ManageInviteInfo: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { chatId }): StateProps => {
|
(global, { chatId }): StateProps => {
|
||||||
const { inviteInfo } = global.management.byChatId[chatId];
|
const { inviteInfo } = global.management.byChatId[chatId];
|
||||||
const invite = inviteInfo?.invite;
|
const { invite, importers, requesters } = inviteInfo || {};
|
||||||
const importers = inviteInfo?.importers;
|
const chat = selectChat(global, chatId);
|
||||||
|
const isChannel = chat && isChatChannel(chat);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
invite,
|
invite,
|
||||||
importers,
|
importers,
|
||||||
|
requesters,
|
||||||
|
isChannel,
|
||||||
serverTimeOffset: global.serverTimeOffset,
|
serverTimeOffset: global.serverTimeOffset,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useCallback, useMemo, useState,
|
FC, memo, useCallback, useEffect, useMemo, useState,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getDispatch, withGlobal } from '../../../lib/teact/teactn';
|
import { getDispatch, withGlobal } from '../../../lib/teact/teactn';
|
||||||
|
|
||||||
import { ApiChat, ApiExportedInvite } from '../../../api/types';
|
import { ApiChat, ApiExportedInvite } from '../../../api/types';
|
||||||
import { ManagementScreens } from '../../../types';
|
import { ManagementScreens } from '../../../types';
|
||||||
|
|
||||||
|
import { STICKER_SIZE_INVITES } from '../../../config';
|
||||||
|
import getAnimationData from '../../common/helpers/animatedAssets';
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
import { formatCountdown, MILLISECONDS_IN_DAY } from '../../../util/dateFormat';
|
import { formatCountdown, MILLISECONDS_IN_DAY } from '../../../util/dateFormat';
|
||||||
@ -16,6 +18,7 @@ import { copyTextToClipboard } from '../../../util/clipboard';
|
|||||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
||||||
import { getServerTime } from '../../../util/serverTime';
|
import { getServerTime } from '../../../util/serverTime';
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
|
import { isChatChannel } from '../../../modules/helpers';
|
||||||
|
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
import NothingFound from '../../common/NothingFound';
|
import NothingFound from '../../common/NothingFound';
|
||||||
@ -23,6 +26,7 @@ import Button from '../../ui/Button';
|
|||||||
import DropdownMenu from '../../ui/DropdownMenu';
|
import DropdownMenu from '../../ui/DropdownMenu';
|
||||||
import MenuItem from '../../ui/MenuItem';
|
import MenuItem from '../../ui/MenuItem';
|
||||||
import ConfirmDialog from '../../ui/ConfirmDialog';
|
import ConfirmDialog from '../../ui/ConfirmDialog';
|
||||||
|
import AnimatedSticker from '../../common/AnimatedSticker';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
@ -33,6 +37,7 @@ type OwnProps = {
|
|||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
chat?: ApiChat;
|
chat?: ApiChat;
|
||||||
|
isChannel?: boolean;
|
||||||
exportedInvites?: ApiExportedInvite[];
|
exportedInvites?: ApiExportedInvite[];
|
||||||
revokedExportedInvites?: ApiExportedInvite[];
|
revokedExportedInvites?: ApiExportedInvite[];
|
||||||
serverTimeOffset: number;
|
serverTimeOffset: number;
|
||||||
@ -54,6 +59,7 @@ const ManageInvites: FC<OwnProps & StateProps> = ({
|
|||||||
exportedInvites,
|
exportedInvites,
|
||||||
revokedExportedInvites,
|
revokedExportedInvites,
|
||||||
isActive,
|
isActive,
|
||||||
|
isChannel,
|
||||||
serverTimeOffset,
|
serverTimeOffset,
|
||||||
onClose,
|
onClose,
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
@ -66,14 +72,26 @@ const ManageInvites: FC<OwnProps & StateProps> = ({
|
|||||||
deleteRevokedExportedChatInvites,
|
deleteRevokedExportedChatInvites,
|
||||||
setOpenedInviteInfo,
|
setOpenedInviteInfo,
|
||||||
} = getDispatch();
|
} = getDispatch();
|
||||||
|
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
const [isDeleteRevokeAllDialogOpen, openDeleteRevokeAllDialog, closeDeleteRevokeAllDialog] = useFlag();
|
const [isDeleteRevokeAllDialogOpen, openDeleteRevokeAllDialog, closeDeleteRevokeAllDialog] = useFlag();
|
||||||
const [isRevokeDialogOpen, openRevokeDialog, closeRevokeDialog] = useFlag();
|
const [isRevokeDialogOpen, openRevokeDialog, closeRevokeDialog] = useFlag();
|
||||||
const [revokingInvite, setRevokingInvite] = useState<ApiExportedInvite | undefined>();
|
const [revokingInvite, setRevokingInvite] = useState<ApiExportedInvite | undefined>();
|
||||||
const [isDeleteDialogOpen, openDeleteDialog, closeDeleteDialog] = useFlag();
|
const [isDeleteDialogOpen, openDeleteDialog, closeDeleteDialog] = useFlag();
|
||||||
const [deletingInvite, setDeletingInvite] = useState<ApiExportedInvite | undefined>();
|
const [deletingInvite, setDeletingInvite] = useState<ApiExportedInvite | undefined>();
|
||||||
|
|
||||||
|
const [animationData, setAnimationData] = useState<string>();
|
||||||
|
const [isAnimationLoaded, setIsAnimationLoaded] = useState(false);
|
||||||
|
const handleAnimationLoad = useCallback(() => setIsAnimationLoaded(true), []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!animationData) {
|
||||||
|
getAnimationData('Invite').then(setAnimationData);
|
||||||
|
}
|
||||||
|
}, [animationData]);
|
||||||
|
|
||||||
useHistoryBack(isActive, onClose);
|
useHistoryBack(isActive, onClose);
|
||||||
const lang = useLang();
|
|
||||||
|
|
||||||
const hasDetailedCountdown = useMemo(() => {
|
const hasDetailedCountdown = useMemo(() => {
|
||||||
if (!exportedInvites) return undefined;
|
if (!exportedInvites) return undefined;
|
||||||
@ -265,6 +283,20 @@ const ManageInvites: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className="Management ManageInvites">
|
<div className="Management ManageInvites">
|
||||||
<div className="custom-scroll">
|
<div className="custom-scroll">
|
||||||
|
<div className="section">
|
||||||
|
<div className="section-icon">
|
||||||
|
{animationData && (
|
||||||
|
<AnimatedSticker
|
||||||
|
id="inviteDuck"
|
||||||
|
size={STICKER_SIZE_INVITES}
|
||||||
|
animationData={animationData}
|
||||||
|
play={isAnimationLoaded}
|
||||||
|
onLoad={handleAnimationLoad}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<p className='text-muted'>{isChannel ? lang('PrimaryLinkHelpChannel') : lang('PrimaryLinkHelp')}</p>
|
||||||
|
</div>
|
||||||
{primaryInviteLink && (
|
{primaryInviteLink && (
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<p className="text-muted">
|
<p className="text-muted">
|
||||||
@ -347,6 +379,8 @@ const ManageInvites: FC<OwnProps & StateProps> = ({
|
|||||||
onClose={closeDeleteRevokeAllDialog}
|
onClose={closeDeleteRevokeAllDialog}
|
||||||
title={lang('DeleteAllRevokedLinks')}
|
title={lang('DeleteAllRevokedLinks')}
|
||||||
text={lang('DeleteAllRevokedLinkHelp')}
|
text={lang('DeleteAllRevokedLinkHelp')}
|
||||||
|
confirmIsDestructive
|
||||||
|
confirmLabel={lang('DeleteAll')}
|
||||||
confirmHandler={handleDeleteAllRevoked}
|
confirmHandler={handleDeleteAllRevoked}
|
||||||
/>
|
/>
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
@ -354,6 +388,8 @@ const ManageInvites: FC<OwnProps & StateProps> = ({
|
|||||||
onClose={closeRevokeDialog}
|
onClose={closeRevokeDialog}
|
||||||
title={lang('RevokeLink')}
|
title={lang('RevokeLink')}
|
||||||
text={lang('RevokeAlert')}
|
text={lang('RevokeAlert')}
|
||||||
|
confirmIsDestructive
|
||||||
|
confirmLabel={lang('RevokeButton')}
|
||||||
confirmHandler={handleRevoke}
|
confirmHandler={handleRevoke}
|
||||||
/>
|
/>
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
@ -361,6 +397,8 @@ const ManageInvites: FC<OwnProps & StateProps> = ({
|
|||||||
onClose={closeDeleteDialog}
|
onClose={closeDeleteDialog}
|
||||||
title={lang('DeleteLink')}
|
title={lang('DeleteLink')}
|
||||||
text={lang('DeleteLinkHelp')}
|
text={lang('DeleteLinkHelp')}
|
||||||
|
confirmIsDestructive
|
||||||
|
confirmLabel={lang('Delete')}
|
||||||
confirmHandler={handleDelete}
|
confirmHandler={handleDelete}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -371,12 +409,14 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
(global, { chatId }): StateProps => {
|
(global, { chatId }): StateProps => {
|
||||||
const { invites, revokedInvites } = global.management.byChatId[chatId];
|
const { invites, revokedInvites } = global.management.byChatId[chatId];
|
||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
|
const isChannel = chat && isChatChannel(chat);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
exportedInvites: invites,
|
exportedInvites: invites,
|
||||||
revokedExportedInvites: revokedInvites,
|
revokedExportedInvites: revokedInvites,
|
||||||
chat,
|
chat,
|
||||||
serverTimeOffset: global.serverTimeOffset,
|
serverTimeOffset: global.serverTimeOffset,
|
||||||
|
isChannel,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(ManageInvites));
|
)(ManageInvites));
|
||||||
|
|||||||
@ -1,19 +1,23 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useCallback, useEffect,
|
FC, memo, useCallback, useEffect, useState,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getDispatch, withGlobal } from '../../../lib/teact/teactn';
|
import { getDispatch, withGlobal } from '../../../lib/teact/teactn';
|
||||||
|
|
||||||
import { ApiChat } from '../../../api/types';
|
import { ApiChat } from '../../../api/types';
|
||||||
|
|
||||||
|
import { STICKER_SIZE_JOIN_REQUESTS } from '../../../config';
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
import { selectChat } from '../../../modules/selectors';
|
import { selectChat } from '../../../modules/selectors';
|
||||||
import { isChatChannel } from '../../../modules/helpers';
|
import { isChatChannel, isUserId } from '../../../modules/helpers';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
|
import getAnimationData from '../../common/helpers/animatedAssets';
|
||||||
|
|
||||||
import JoinRequest from './JoinRequest';
|
import JoinRequest from './JoinRequest';
|
||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
import ConfirmDialog from '../../ui/ConfirmDialog';
|
import ConfirmDialog from '../../ui/ConfirmDialog';
|
||||||
|
import AnimatedSticker from '../../common/AnimatedSticker';
|
||||||
|
import Spinner from '../../ui/Spinner';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
@ -40,10 +44,20 @@ const ManageJoinRequests: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
|
const [animationData, setAnimationData] = useState<string>();
|
||||||
|
const [isAnimationLoaded, setIsAnimationLoaded] = useState(false);
|
||||||
|
const handleAnimationLoad = useCallback(() => setIsAnimationLoaded(true), []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!animationData) {
|
||||||
|
getAnimationData('JoinRequest').then(setAnimationData);
|
||||||
|
}
|
||||||
|
}, [animationData]);
|
||||||
|
|
||||||
useHistoryBack(isActive, onClose);
|
useHistoryBack(isActive, onClose);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!chat?.joinRequests) {
|
if (!chat?.joinRequests && !isUserId(chatId)) {
|
||||||
loadChatJoinRequests({ chatId });
|
loadChatJoinRequests({ chatId });
|
||||||
}
|
}
|
||||||
}, [chat, chatId, loadChatJoinRequests]);
|
}, [chat, chatId, loadChatJoinRequests]);
|
||||||
@ -60,17 +74,34 @@ const ManageJoinRequests: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Management ManageJoinRequests">
|
<div className="Management ManageJoinRequests">
|
||||||
{Boolean(chat?.joinRequests?.length) && (
|
<div className="section">
|
||||||
<div className="section bulk-actions">
|
<div className="section-icon">
|
||||||
<Button className="bulk-action-button" onClick={openAcceptAllDialog}>Accept all</Button>
|
{animationData && (
|
||||||
<Button className="bulk-action-button" onClick={openRejectAllDialog} isText>Dismiss all</Button>
|
<AnimatedSticker
|
||||||
|
id="joinRequestDucks"
|
||||||
|
size={STICKER_SIZE_JOIN_REQUESTS}
|
||||||
|
animationData={animationData}
|
||||||
|
play={isAnimationLoaded}
|
||||||
|
onLoad={handleAnimationLoad}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
{Boolean(chat?.joinRequests?.length) && (
|
||||||
|
<div className="bulk-actions">
|
||||||
|
<Button className="bulk-action-button" onClick={openAcceptAllDialog}>Accept all</Button>
|
||||||
|
<Button className="bulk-action-button" onClick={openRejectAllDialog} isText>Dismiss all</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<div className="custom-scroll" teactFastList>
|
<div className="custom-scroll" teactFastList>
|
||||||
<p key="title">
|
<p key="title">
|
||||||
{chat?.joinRequests?.length ? lang('JoinRequests', chat?.joinRequests?.length) : lang('NoMemberRequests')}
|
{!chat?.joinRequests ? lang('Loading') : chat.joinRequests.length
|
||||||
|
? lang('JoinRequests', chat.joinRequests.length) : lang('NoMemberRequests')}
|
||||||
</p>
|
</p>
|
||||||
|
{!chat?.joinRequests && (
|
||||||
|
<Spinner key="loading" />
|
||||||
|
)}
|
||||||
{chat?.joinRequests?.length === 0 && (
|
{chat?.joinRequests?.length === 0 && (
|
||||||
<p className="text-muted" key="empty">
|
<p className="text-muted" key="empty">
|
||||||
{isChannel ? lang('NoSubscribeRequestsDescription') : lang('NoMemberRequestsDescription')}
|
{isChannel ? lang('NoSubscribeRequestsDescription') : lang('NoMemberRequestsDescription')}
|
||||||
|
|||||||
@ -183,6 +183,10 @@
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Spinner {
|
||||||
|
margin: 2rem auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ManageGroupMembers {
|
.ManageGroupMembers {
|
||||||
@ -197,6 +201,7 @@
|
|||||||
.primary-link-input {
|
.primary-link-input {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
padding-right: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.primary-link-more-menu {
|
.primary-link-more-menu {
|
||||||
@ -230,6 +235,10 @@
|
|||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-scroll {
|
||||||
|
padding-bottom: 4rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ManageInviteInfo {
|
.ManageInviteInfo {
|
||||||
@ -237,6 +246,10 @@
|
|||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.link-title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ManageJoinRequests {
|
.ManageJoinRequests {
|
||||||
@ -251,7 +264,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ManageInvite, .ManageInvites {
|
.ManageInvite,
|
||||||
|
.ManageInvites {
|
||||||
.hint {
|
.hint {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|||||||
@ -114,7 +114,6 @@ const ListItem: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const handleSecondaryIconClick = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
const handleSecondaryIconClick = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
if (disabled || e.button !== 0 || (!onSecondaryIconClick && !contextActions)) return;
|
if (disabled || e.button !== 0 || (!onSecondaryIconClick && !contextActions)) return;
|
||||||
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (onSecondaryIconClick) {
|
if (onSecondaryIconClick) {
|
||||||
onSecondaryIconClick(e);
|
onSecondaryIconClick(e);
|
||||||
@ -188,7 +187,8 @@ const ListItem: FC<OwnProps> = ({
|
|||||||
round
|
round
|
||||||
color="translucent"
|
color="translucent"
|
||||||
size="smaller"
|
size="smaller"
|
||||||
onMouseDown={handleSecondaryIconClick}
|
onClick={IS_TOUCH_ENV ? handleSecondaryIconClick : undefined}
|
||||||
|
onMouseDown={!IS_TOUCH_ENV ? handleSecondaryIconClick : undefined}
|
||||||
>
|
>
|
||||||
<i className={`icon-${secondaryIcon}`} />
|
<i className={`icon-${secondaryIcon}`} />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -140,7 +140,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal-about {
|
.modal-about {
|
||||||
font-weight: bold;
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 5;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-help {
|
.modal-help {
|
||||||
|
|||||||
@ -121,8 +121,10 @@ export const STICKER_SIZE_SEARCH = 64;
|
|||||||
export const STICKER_SIZE_MODAL = 64;
|
export const STICKER_SIZE_MODAL = 64;
|
||||||
export const STICKER_SIZE_TWO_FA = 160;
|
export const STICKER_SIZE_TWO_FA = 160;
|
||||||
export const STICKER_SIZE_DISCUSSION_GROUPS = 140;
|
export const STICKER_SIZE_DISCUSSION_GROUPS = 140;
|
||||||
export const STICKER_SIZE_FOLDER_SETTINGS = 80;
|
export const STICKER_SIZE_FOLDER_SETTINGS = 100;
|
||||||
export const STICKER_SIZE_INLINE_BOT_RESULT = 100;
|
export const STICKER_SIZE_INLINE_BOT_RESULT = 100;
|
||||||
|
export const STICKER_SIZE_JOIN_REQUESTS = 140;
|
||||||
|
export const STICKER_SIZE_INVITES = 140;
|
||||||
export const RECENT_STICKERS_LIMIT = 20;
|
export const RECENT_STICKERS_LIMIT = 20;
|
||||||
export const MEMOJI_STICKER_ID = 'MEMOJI_STICKER';
|
export const MEMOJI_STICKER_ID = 'MEMOJI_STICKER';
|
||||||
|
|
||||||
|
|||||||
@ -558,6 +558,7 @@ export type ActionTypes = (
|
|||||||
'setEditingExportedInvite' | 'loadExportedChatInvites' | 'editExportedChatInvite' | 'exportChatInvite' |
|
'setEditingExportedInvite' | 'loadExportedChatInvites' | 'editExportedChatInvite' | 'exportChatInvite' |
|
||||||
'deleteExportedChatInvite' | 'deleteRevokedExportedChatInvites' | 'setOpenedInviteInfo' | 'loadChatInviteImporters' |
|
'deleteExportedChatInvite' | 'deleteRevokedExportedChatInvites' | 'setOpenedInviteInfo' | 'loadChatInviteImporters' |
|
||||||
'loadChatJoinRequests' | 'hideChatJoinRequest' | 'hideAllChatJoinRequests' | 'requestNextManagementScreen' |
|
'loadChatJoinRequests' | 'hideChatJoinRequest' | 'hideAllChatJoinRequests' | 'requestNextManagementScreen' |
|
||||||
|
'loadChatInviteRequesters' |
|
||||||
// groups
|
// groups
|
||||||
'togglePreHistoryHidden' | 'updateChatDefaultBannedRights' | 'updateChatMemberBannedRights' | 'updateChatAdmin' |
|
'togglePreHistoryHidden' | 'updateChatDefaultBannedRights' | 'updateChatMemberBannedRights' | 'updateChatAdmin' |
|
||||||
'acceptInviteConfirmation' |
|
'acceptInviteConfirmation' |
|
||||||
|
|||||||
@ -243,7 +243,7 @@ addReducer('loadChatInviteImporters', (global, actions, payload) => {
|
|||||||
}
|
}
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo;
|
const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo;
|
||||||
if (!currentInviteInfo?.invite) return;
|
if (!currentInviteInfo?.invite || currentInviteInfo.invite.link !== link) return;
|
||||||
setGlobal(updateManagement(global, chatId, {
|
setGlobal(updateManagement(global, chatId, {
|
||||||
inviteInfo: {
|
inviteInfo: {
|
||||||
...currentInviteInfo,
|
...currentInviteInfo,
|
||||||
@ -253,6 +253,38 @@ addReducer('loadChatInviteImporters', (global, actions, payload) => {
|
|||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addReducer('loadChatInviteRequesters', (global, actions, payload) => {
|
||||||
|
const {
|
||||||
|
chatId, link, offsetDate, offsetUserId, limit,
|
||||||
|
} = payload!;
|
||||||
|
const peer = selectChat(global, chatId);
|
||||||
|
const offsetUser = selectUser(global, offsetUserId);
|
||||||
|
if (!peer || (offsetUserId && !offsetUser)) return;
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const result = await callApi('fetchChatInviteImporters', {
|
||||||
|
peer,
|
||||||
|
link,
|
||||||
|
offsetDate,
|
||||||
|
offsetUser,
|
||||||
|
limit,
|
||||||
|
isRequested: true,
|
||||||
|
});
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
global = getGlobal();
|
||||||
|
const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo;
|
||||||
|
if (!currentInviteInfo?.invite || currentInviteInfo.invite.link !== link) return;
|
||||||
|
setGlobal(updateManagement(global, chatId, {
|
||||||
|
inviteInfo: {
|
||||||
|
...currentInviteInfo,
|
||||||
|
requesters: result,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
|
||||||
addReducer('loadChatJoinRequests', (global, actions, payload) => {
|
addReducer('loadChatJoinRequests', (global, actions, payload) => {
|
||||||
const {
|
const {
|
||||||
chatId, offsetDate, offsetUserId, limit,
|
chatId, offsetDate, offsetUserId, limit,
|
||||||
|
|||||||
@ -293,6 +293,7 @@ export interface ManagementState {
|
|||||||
inviteInfo?: {
|
inviteInfo?: {
|
||||||
invite: ApiExportedInvite;
|
invite: ApiExportedInvite;
|
||||||
importers?: ApiChatInviteImporter[];
|
importers?: ApiChatInviteImporter[];
|
||||||
|
requesters?: ApiChatInviteImporter[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user