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, chat,
slots, slots,
} : { } : {
chat: ApiChat; chat: ApiChat;
slots: number[]; slots: number[];
}) { }) {
return invokeRequest(new GramJs.premium.ApplyBoost({ const result = await invokeRequest(new GramJs.premium.ApplyBoost({
peer: buildInputPeer(chat.id, chat.accessHash), peer: buildInputPeer(chat.id, chat.accessHash),
slots, 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({ export async function fetchBoostsStatus({

View File

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

View File

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

View File

@ -611,6 +611,20 @@ addActionHandler('applyBoost', async (global, actions, payload): Promise<void> =
return; 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', { const newStatusResult = await callApi('fetchBoostsStatus', {
chat, chat,
}); });
@ -620,7 +634,7 @@ addActionHandler('applyBoost', async (global, actions, payload): Promise<void> =
} }
global = getGlobal(); global = getGlobal();
const tabState = selectTabState(global, tabId); tabState = selectTabState(global, tabId);
if (!tabState.boostModal?.boostStatus) return; if (!tabState.boostModal?.boostStatus) return;
global = updateTabState(global, { global = updateTabState(global, {
boostModal: { boostModal: {