Attach Web Bots: Ask before uninstall (#4223)

This commit is contained in:
Alexander Zinchuk 2024-02-06 16:49:03 +01:00
parent 9a0c0e10dd
commit 9c8b2e4e40
4 changed files with 65 additions and 8 deletions

View File

@ -65,9 +65,7 @@ const AttachBotInstallModal: FC<OwnProps> = ({
label={tosLabel} label={tosLabel}
onCheck={setIsTosAccepted} onCheck={setIsTosAccepted}
/> />
{bot?.isInactive && bot.isForSideMenu && ( {renderText(lang('WebBot.Account.Desclaimer.Desc', bot?.shortName), ['simple_markdown'])}
renderText(lang('WebBot.Account.Desclaimer.Desc', bot?.shortName), ['simple_markdown'])
)}
</ConfirmDialog> </ConfirmDialog>
); );
}; };

View File

@ -20,6 +20,7 @@ import { getColorLuma } from '../../../util/colors';
import { hexToRgb } from '../../../util/switchTheme'; import { hexToRgb } from '../../../util/switchTheme';
import { extractCurrentThemeParams, validateHexColor } from '../../../util/themeStyle'; import { extractCurrentThemeParams, validateHexColor } from '../../../util/themeStyle';
import { callApi } from '../../../api/gramjs'; import { callApi } from '../../../api/gramjs';
import renderText from '../../common/helpers/renderText';
import useAppLayout from '../../../hooks/useAppLayout'; import useAppLayout from '../../../hooks/useAppLayout';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
@ -31,6 +32,7 @@ import useSyncEffect from '../../../hooks/useSyncEffect';
import usePopupLimit from './hooks/usePopupLimit'; import usePopupLimit from './hooks/usePopupLimit';
import useWebAppFrame from './hooks/useWebAppFrame'; import useWebAppFrame from './hooks/useWebAppFrame';
import Icon from '../../common/Icon';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
import ConfirmDialog from '../../ui/ConfirmDialog'; import ConfirmDialog from '../../ui/ConfirmDialog';
import DropdownMenu from '../../ui/DropdownMenu'; import DropdownMenu from '../../ui/DropdownMenu';
@ -114,6 +116,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
const [shouldConfirmClosing, setShouldConfirmClosing] = useState(false); const [shouldConfirmClosing, setShouldConfirmClosing] = useState(false);
const [isCloseModalOpen, openCloseModal, hideCloseModal] = useFlag(false); const [isCloseModalOpen, openCloseModal, hideCloseModal] = useFlag(false);
const [isRemoveModalOpen, openRemoveModal, hideRemoveModal] = useFlag(false);
const [isLoaded, markLoaded, markUnloaded] = useFlag(false); const [isLoaded, markLoaded, markUnloaded] = useFlag(false);
@ -226,10 +229,23 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
} }
}, [isPaymentModalOpen, paymentStatus, sendEvent, setWebAppPaymentSlug, webApp]); }, [isPaymentModalOpen, paymentStatus, sendEvent, setWebAppPaymentSlug, webApp]);
const handleToggleClick = useLastCallback(() => { const handleRemoveAttachBot = useLastCallback(() => {
toggleAttachBot({ toggleAttachBot({
botId: bot!.id, botId: bot!.id,
isEnabled: !attachBot, isEnabled: false,
});
closeWebApp();
});
const handleToggleClick = useLastCallback(() => {
if (attachBot) {
openRemoveModal();
return;
}
toggleAttachBot({
botId: bot!.id,
isEnabled: true,
}); });
}); });
@ -340,6 +356,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
setShouldConfirmClosing(false); setShouldConfirmClosing(false);
hideCloseModal(); hideCloseModal();
hideRemoveModal();
setPopupParameters(undefined); setPopupParameters(undefined);
setIsRequestingPhone(false); setIsRequestingPhone(false);
setIsRequestingWriteAccess(false); setIsRequestingWriteAccess(false);
@ -350,7 +367,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
setHeaderColor(themeParams.bg_color); setHeaderColor(themeParams.bg_color);
markUnloaded(); markUnloaded();
} }
}, [hideCloseModal, isOpen, markUnloaded]); }, [isOpen]);
function handleEvent(event: WebAppInboundEvent) { function handleEvent(event: WebAppInboundEvent) {
const { eventType, eventData } = event; const { eventType, eventData } = event;
@ -479,7 +496,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
onClick={onTrigger} onClick={onTrigger}
ariaLabel="More actions" ariaLabel="More actions"
> >
<i className="icon icon-more" /> <Icon name="more" />
</Button> </Button>
); );
}, [isMobile]); }, [isMobile]);
@ -663,6 +680,14 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
confirmIsDestructive confirmIsDestructive
confirmLabel={lang('lng_bot_close_warning_sure')} confirmLabel={lang('lng_bot_close_warning_sure')}
/> />
<ConfirmDialog
isOpen={isRemoveModalOpen}
onClose={hideRemoveModal}
title={lang('BotRemoveFromMenuTitle')}
textParts={renderText(lang('BotRemoveFromMenu', bot?.firstName), ['simple_markdown'])}
confirmHandler={handleRemoveAttachBot}
confirmIsDestructive
/>
</Modal> </Modal>
); );
}; };

View File

@ -586,13 +586,46 @@ addActionHandler('requestWebView', async (global, actions, payload): Promise<voi
addActionHandler('requestAppWebView', async (global, actions, payload): Promise<void> => { addActionHandler('requestAppWebView', async (global, actions, payload): Promise<void> => {
const { const {
botId, appName, startApp, theme, isWriteAllowed, botId, appName, startApp, theme, isWriteAllowed, isFromConfirm,
tabId = getCurrentTabId(), tabId = getCurrentTabId(),
} = payload; } = payload;
const bot = selectUser(global, botId); const bot = selectUser(global, botId);
if (!bot) return; if (!bot) return;
// Native clients require to install attach bots before using their named mini apps
const isAttachBotInstalled = Boolean(global.attachMenu.bots[bot.id]);
if (bot.isAttachBot && !isFromConfirm && !isAttachBotInstalled) {
const result = await callApi('loadAttachBot', {
bot,
});
if (result) {
const attachBot = result.bot;
global = getGlobal();
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
setGlobal(global);
const shouldAskForTos = attachBot.isDisclaimerNeeded || attachBot.isForAttachMenu || attachBot.isForSideMenu;
if (shouldAskForTos) {
global = updateTabState(global, {
requestedAttachBotInstall: {
bot: attachBot,
onConfirm: {
action: 'requestAppWebView',
payload: {
...payload,
isFromConfirm: true,
},
},
},
}, tabId);
setGlobal(global);
return;
}
}
}
const botApp = await callApi('fetchBotApp', { const botApp = await callApi('fetchBotApp', {
bot, bot,
appName, appName,

View File

@ -2563,6 +2563,7 @@ export interface ActionPayloads {
theme?: ApiThemeParameters; theme?: ApiThemeParameters;
startApp?: string; startApp?: string;
isWriteAllowed?: boolean; isWriteAllowed?: boolean;
isFromConfirm?: boolean;
} & WithTabId; } & WithTabId;
setWebAppPaymentSlug: { setWebAppPaymentSlug: {
slug?: string; slug?: string;