Boost Modal: Support multiple boosts for one channel (#3963)

This commit is contained in:
Alexander Zinchuk 2023-11-12 12:54:49 +04:00
parent cd28a97822
commit 62f742c023
4 changed files with 55 additions and 17 deletions

View File

@ -212,19 +212,32 @@ export async function fetchMyBoosts() {
};
}
export function applyBoost({
export async function applyBoost({
chat,
slots,
} : {
chat: ApiChat;
slots: number[];
}) {
return invokeRequest(new GramJs.premium.ApplyBoost({
const result = await invokeRequest(new GramJs.premium.ApplyBoost({
peer: buildInputPeer(chat.id, chat.accessHash),
slots,
}), {
shouldReturnTrue: true,
});
}));
if (!result) return undefined;
addEntitiesToLocalDb(result.users);
addEntitiesToLocalDb(result.chats);
const users = result.users.map(buildApiUser).filter(Boolean);
const chats = result.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean);
const boosts = result.myBoosts.map(buildApiMyBoost);
return {
users,
chats,
boosts,
};
}
export async function fetchBoostsStatus({

View File

@ -5,11 +5,11 @@ export function getBoostProgressInfo(boostInfo: ApiBoostsStatus, freezeOnLevelUp
level, boosts, currentLevelBoosts, nextLevelBoosts, hasMyBoost,
} = boostInfo;
const currentLevel = level;
const hasNextLevel = Boolean(nextLevelBoosts);
const isJustUpgraded = freezeOnLevelUp && boosts === currentLevelBoosts && hasMyBoost;
const currentLevel = isJustUpgraded ? level - 1 : level;
const hasNextLevel = Boolean(nextLevelBoosts);
const levelProgress = (!nextLevelBoosts || isJustUpgraded) ? 1
: (boosts - currentLevelBoosts) / (nextLevelBoosts - currentLevelBoosts);
const remainingBoosts = nextLevelBoosts ? nextLevelBoosts - boosts : 0;

View File

@ -33,6 +33,7 @@ type LoadedParams = {
progress: number;
descriptionText: string;
isBoosted?: boolean;
canBoostMore?: boolean;
};
type BoostInfo = ({
@ -100,6 +101,7 @@ const BoostModal = ({
value,
progress,
descriptionText,
canBoostMore,
}: BoostInfo = useMemo(() => {
if (!info?.boostStatus || !chat) {
return {
@ -112,7 +114,8 @@ const BoostModal = ({
level, currentLevelBoosts, hasMyBoost,
} = info.boostStatus;
const firstBoost = info?.myBoosts && getFirstAvailableBoost(info.myBoosts);
const firstBoost = info?.myBoosts && getFirstAvailableBoost(info.myBoosts, chat.id);
const areBoostsInDifferentChannels = info?.myBoosts && !areAllBoostsInChannel(info.myBoosts, chat.id);
const {
boosts,
@ -163,10 +166,11 @@ const BoostModal = ({
descriptionText: description,
boost: firstBoost,
isBoosted: hasBoost,
canBoostMore: areBoostsInDifferentChannels,
};
}, [chat, chatTitle, info, lang]);
const isBoostDisabled = !boost && isCurrentUserPremium;
const isBoostDisabled = !info?.myBoosts?.length && isCurrentUserPremium;
const isReplacingBoost = boost?.chatId && boost.chatId !== info?.chatId;
const handleApplyBoost = useLastCallback(() => {
@ -187,10 +191,11 @@ const BoostModal = ({
openPremiumDialog();
}
closeBoostModal();
return;
}
if (isBoosted) {
if (!canBoostMore) {
closeBoostModal();
return;
}
@ -231,10 +236,10 @@ const BoostModal = ({
</div>
<div className="dialog-buttons">
<Button isText className="confirm-dialog-button" disabled={isBoostDisabled} onClick={handleButtonClick}>
{!isBoosted ? (
{canBoostMore ? (
<>
<Icon name="boost" />
{lang('ChannelBoost.BoostChannel')}
{lang(isBoosted && canBoostMore ? 'BoostingBoostAgain' : 'ChannelBoost.BoostChannel')}
</>
) : lang('OK')}
</Button>
@ -316,14 +321,20 @@ const BoostModal = ({
);
};
function getFirstAvailableBoost(myBoosts: ApiMyBoost[]) {
return myBoosts.find((boost) => !boost.chatId) || myBoosts.sort((a, b) => a.date - b.date)[0];
function getFirstAvailableBoost(myBoosts: ApiMyBoost[], chatId?: string) {
return myBoosts.find((boost) => !boost.chatId)
|| myBoosts.filter((b) => chatId && b.chatId !== chatId)
.sort((a, b) => a.date - b.date)[0];
}
function areAllBoostsInChannel(myBoosts: ApiMyBoost[], chatId: string) {
return myBoosts.every((boost) => boost.chatId === chatId);
}
export default memo(withGlobal<OwnProps>(
(global, { info }): StateProps => {
const chat = info && selectChat(global, info?.chatId);
const firstBoost = info?.myBoosts && getFirstAvailableBoost(info.myBoosts);
const firstBoost = info?.myBoosts && getFirstAvailableBoost(info.myBoosts, info.chatId);
const boostedChat = firstBoost?.chatId ? selectChat(global, firstBoost?.chatId) : undefined;
return {

View File

@ -611,6 +611,20 @@ addActionHandler('applyBoost', async (global, actions, payload): Promise<void> =
return;
}
global = getGlobal();
let tabState = selectTabState(global, tabId);
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
global = addChats(global, buildCollectionByKey(result.chats, 'id'));
if (tabState.boostModal) {
global = updateTabState(global, {
boostModal: {
...tabState.boostModal,
myBoosts: result.boosts,
},
}, tabId);
}
setGlobal(global);
const newStatusResult = await callApi('fetchBoostsStatus', {
chat,
});
@ -620,7 +634,7 @@ addActionHandler('applyBoost', async (global, actions, payload): Promise<void> =
}
global = getGlobal();
const tabState = selectTabState(global, tabId);
tabState = selectTabState(global, tabId);
if (!tabState.boostModal?.boostStatus) return;
global = updateTabState(global, {
boostModal: {