Url Auth: Support apps (#6896)
This commit is contained in:
parent
d5ec8153db
commit
fa6224abb7
@ -34,6 +34,8 @@ You are an expert in TypeScript, JavaScript, HTML, SCSS and Teact with deep expe
|
|||||||
- Functions should start with a verb (e.g. `openModal`, `closeDialog`, `handleClick`).
|
- Functions should start with a verb (e.g. `openModal`, `closeDialog`, `handleClick`).
|
||||||
- Prefer checking required parameter before calling a function, avoid making it optional and checking at the beginning of the function.
|
- Prefer checking required parameter before calling a function, avoid making it optional and checking at the beginning of the function.
|
||||||
- Only leave comments for complex logic.
|
- Only leave comments for complex logic.
|
||||||
|
- Avoid using default values for props that can be intentionally undefined/false.
|
||||||
|
- No unnecessary `as` casts. Prefer `satisfies` where possible.
|
||||||
- Do not use `null`. There's linter rule to enforce it.
|
- Do not use `null`. There's linter rule to enforce it.
|
||||||
- **IMPORTANT: Avoid conditional spread operators** - TypeScript doesn't check if spread fields match the target type.
|
- **IMPORTANT: Avoid conditional spread operators** - TypeScript doesn't check if spread fields match the target type.
|
||||||
```typescript
|
```typescript
|
||||||
@ -180,7 +182,7 @@ addActionHandler('loadUser', async (global, actions, { userId }) => {
|
|||||||
### 3. Hooks
|
### 3. Hooks
|
||||||
* **useLastCallback** is your go-to for callbacks, since it won't trigger re-renders and always uses the latest scope.
|
* **useLastCallback** is your go-to for callbacks, since it won't trigger re-renders and always uses the latest scope.
|
||||||
* Only use **useCallback** when you really need to memoize a render function.
|
* Only use **useCallback** when you really need to memoize a render function.
|
||||||
* Prefer **useFlag()** over `useState<boolean>()` for simple boolean toggles.
|
* Prefer **useFlag()** over `useState<boolean>()` for simple boolean toggles. `useState` is preferred when component just calls `setState(someVariable)`.
|
||||||
* Check the `hooks/` folders for additional utilities.
|
* Check the `hooks/` folders for additional utilities.
|
||||||
* Avoid adding new `useEffect` where possible.
|
* Avoid adding new `useEffect` where possible.
|
||||||
|
|
||||||
|
|||||||
@ -168,7 +168,7 @@ export function buildApiUrlAuthResult(result: GramJs.TypeUrlAuthResult): ApiUrlA
|
|||||||
if (result instanceof GramJs.UrlAuthResultRequest) {
|
if (result instanceof GramJs.UrlAuthResultRequest) {
|
||||||
const {
|
const {
|
||||||
bot, domain, requestWriteAccess, requestPhoneNumber, browser, platform, ip, region, matchCodes,
|
bot, domain, requestWriteAccess, requestPhoneNumber, browser, platform, ip, region, matchCodes,
|
||||||
matchCodesFirst, userIdHint,
|
matchCodesFirst, userIdHint, isApp, verifiedAppName,
|
||||||
} = result;
|
} = result;
|
||||||
const user = buildApiUser(bot);
|
const user = buildApiUser(bot);
|
||||||
if (!user) return undefined;
|
if (!user) return undefined;
|
||||||
@ -178,6 +178,7 @@ export function buildApiUrlAuthResult(result: GramJs.TypeUrlAuthResult): ApiUrlA
|
|||||||
return {
|
return {
|
||||||
type: 'request',
|
type: 'request',
|
||||||
domain,
|
domain,
|
||||||
|
isApp,
|
||||||
shouldRequestWriteAccess: requestWriteAccess,
|
shouldRequestWriteAccess: requestWriteAccess,
|
||||||
bot: user,
|
bot: user,
|
||||||
shouldRequestPhoneNumber: requestPhoneNumber,
|
shouldRequestPhoneNumber: requestPhoneNumber,
|
||||||
@ -188,6 +189,7 @@ export function buildApiUrlAuthResult(result: GramJs.TypeUrlAuthResult): ApiUrlA
|
|||||||
matchCodes,
|
matchCodes,
|
||||||
matchCodesFirst,
|
matchCodesFirst,
|
||||||
userIdHint: userIdHint?.toString(),
|
userIdHint: userIdHint?.toString(),
|
||||||
|
verifiedAppName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -389,6 +389,7 @@ export type ApiUrlAuthResultRequest = {
|
|||||||
type: 'request';
|
type: 'request';
|
||||||
bot: ApiUser;
|
bot: ApiUser;
|
||||||
domain: string;
|
domain: string;
|
||||||
|
isApp?: boolean;
|
||||||
shouldRequestWriteAccess?: boolean;
|
shouldRequestWriteAccess?: boolean;
|
||||||
shouldRequestPhoneNumber?: boolean;
|
shouldRequestPhoneNumber?: boolean;
|
||||||
browser?: string;
|
browser?: string;
|
||||||
@ -398,6 +399,7 @@ export type ApiUrlAuthResultRequest = {
|
|||||||
matchCodes?: string[];
|
matchCodes?: string[];
|
||||||
matchCodesFirst?: boolean;
|
matchCodesFirst?: boolean;
|
||||||
userIdHint?: string;
|
userIdHint?: string;
|
||||||
|
verifiedAppName?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ApiUrlAuthResultAccepted = {
|
type ApiUrlAuthResultAccepted = {
|
||||||
|
|||||||
@ -613,6 +613,7 @@
|
|||||||
"OpenUrlText" = "Do you want to open **{url}**?";
|
"OpenUrlText" = "Do you want to open **{url}**?";
|
||||||
"OpenUrlConfirm" = "Open";
|
"OpenUrlConfirm" = "Open";
|
||||||
"BotAuthTitle" = "Log in to {url}";
|
"BotAuthTitle" = "Log in to {url}";
|
||||||
|
"BotAuthAppSubtitle" = "This app will receive your **name**, **username** and **profile photo**.";
|
||||||
"BotAuthSiteSubtitle" = "This site will receive your **name**, **username** and **profile photo**.";
|
"BotAuthSiteSubtitle" = "This site will receive your **name**, **username** and **profile photo**.";
|
||||||
"BotAuthAllowMessages" = "Allow Messages";
|
"BotAuthAllowMessages" = "Allow Messages";
|
||||||
"BotAuthAllowMessagesInfo" = "This will allow **{bot}** to message you.";
|
"BotAuthAllowMessagesInfo" = "This will allow **{bot}** to message you.";
|
||||||
@ -2007,6 +2008,7 @@
|
|||||||
"ActionBotAllowedFromDomain" = "You allowed this bot to message you when you logged in on {domain}.";
|
"ActionBotAllowedFromDomain" = "You allowed this bot to message you when you logged in on {domain}.";
|
||||||
"ActionBotAllowedFromApp" = "You allowed this bot to message you when you opened {app}.";
|
"ActionBotAllowedFromApp" = "You allowed this bot to message you when you opened {app}.";
|
||||||
"ActionBotAppPlaceholder" = "App";
|
"ActionBotAppPlaceholder" = "App";
|
||||||
|
"BotAuthUnverifiedApp" = "Unverified App";
|
||||||
"ActionGiftTextUnknown" = "You've received a gift";
|
"ActionGiftTextUnknown" = "You've received a gift";
|
||||||
"ActionGiftTextUnknownYou" = "You sent a gift";
|
"ActionGiftTextUnknownYou" = "You sent a gift";
|
||||||
"ActionGiftTextCost" = "{from} sent you a gift for {cost}";
|
"ActionGiftTextCost" = "{from} sent you a gift for {cost}";
|
||||||
|
|||||||
@ -163,13 +163,19 @@ const UrlAuthModal = ({
|
|||||||
|| renderingRequest.browser || renderingRequest.ip || renderingRequest.region,
|
|| renderingRequest.browser || renderingRequest.ip || renderingRequest.region,
|
||||||
);
|
);
|
||||||
const requestDomain = renderingRequest.domain;
|
const requestDomain = renderingRequest.domain;
|
||||||
|
const requestDisplayName = renderingRequest.isApp
|
||||||
|
? renderingRequest.verifiedAppName || lang('BotAuthUnverifiedApp')
|
||||||
|
: requestDomain;
|
||||||
|
const titleTarget = renderingRequest.isApp
|
||||||
|
? requestDisplayName
|
||||||
|
: <SafeLink url={requestDomain} text={requestDomain} />;
|
||||||
const formattedPhoneNumber = currentUser?.phoneNumber ? `+${formatPhoneNumber(currentUser.phoneNumber)}` : undefined;
|
const formattedPhoneNumber = currentUser?.phoneNumber ? `+${formatPhoneNumber(currentUser.phoneNumber)}` : undefined;
|
||||||
const titleText = lang('BotAuthTitle', {
|
const titleText = lang('BotAuthTitle', {
|
||||||
url: <SafeLink url={requestDomain} text={requestDomain} />,
|
url: titleTarget,
|
||||||
}, {
|
}, {
|
||||||
withNodes: true,
|
withNodes: true,
|
||||||
});
|
});
|
||||||
const descriptionText = lang('BotAuthSiteSubtitle', undefined, {
|
const descriptionText = lang(renderingRequest.isApp ? 'BotAuthAppSubtitle' : 'BotAuthSiteSubtitle', undefined, {
|
||||||
withNodes: true,
|
withNodes: true,
|
||||||
withMarkdown: true,
|
withMarkdown: true,
|
||||||
});
|
});
|
||||||
@ -179,7 +185,7 @@ const UrlAuthModal = ({
|
|||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
{lang('BotAuthPhoneNumberText', {
|
{lang('BotAuthPhoneNumberText', {
|
||||||
domain: requestDomain,
|
domain: requestDisplayName,
|
||||||
phone: formattedPhoneNumber || lang('Phone'),
|
phone: formattedPhoneNumber || lang('Phone'),
|
||||||
}, {
|
}, {
|
||||||
withNodes: true,
|
withNodes: true,
|
||||||
@ -308,7 +314,7 @@ const UrlAuthModal = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.footnote}>
|
<div className={styles.footnote}>
|
||||||
{lang('BotAuthTitle', {
|
{lang('BotAuthTitle', {
|
||||||
url: <SafeLink url={requestDomain} text={requestDomain} />,
|
url: titleTarget,
|
||||||
}, {
|
}, {
|
||||||
withNodes: true,
|
withNodes: true,
|
||||||
})}
|
})}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import { copyTextToClipboard } from '../../../util/clipboard';
|
|||||||
import { getUsernameFromDeepLink } from '../../../util/deepLinkParser';
|
import { getUsernameFromDeepLink } from '../../../util/deepLinkParser';
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
import { pick } from '../../../util/iteratees.ts';
|
import { pick } from '../../../util/iteratees.ts';
|
||||||
import { getTranslationFn } from '../../../util/localization';
|
import { type AdvancedLangFnParameters, getTranslationFn } from '../../../util/localization';
|
||||||
import { formatStarsAsText } from '../../../util/localization/format';
|
import { formatStarsAsText } from '../../../util/localization/format';
|
||||||
import { oldTranslate } from '../../../util/oldLangProvider';
|
import { oldTranslate } from '../../../util/oldLangProvider';
|
||||||
import requestActionTimeout from '../../../util/requestActionTimeout';
|
import requestActionTimeout from '../../../util/requestActionTimeout';
|
||||||
@ -1298,41 +1298,28 @@ function handleUrlAuthResult<T extends GlobalState>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.type === 'accepted' && !result.url) {
|
if (result.type === 'accepted' && !result.url) {
|
||||||
if (!wasPhoneShared && tabState.urlAuth?.request?.shouldRequestPhoneNumber) {
|
const request = tabState.urlAuth?.request;
|
||||||
actions.showNotification({
|
const requestDisplayName = request?.isApp
|
||||||
message: {
|
? (request.verifiedAppName || getTranslationFn()('BotAuthUnverifiedApp'))
|
||||||
key: 'BotAuthSuccessTextNoPhone',
|
: (request?.domain || url);
|
||||||
variables: {
|
const successMessage: AdvancedLangFnParameters = {
|
||||||
url: tabState.urlAuth.request?.domain || result.url,
|
key: !wasPhoneShared && request?.shouldRequestPhoneNumber ? 'BotAuthSuccessTextNoPhone' : 'BotAuthSuccessText',
|
||||||
},
|
variables: {
|
||||||
options: {
|
url: requestDisplayName,
|
||||||
withMarkdown: true,
|
},
|
||||||
withNodes: true,
|
options: {
|
||||||
},
|
withMarkdown: true,
|
||||||
},
|
withNodes: true,
|
||||||
title: {
|
},
|
||||||
key: 'BotAuthSuccessTitle',
|
};
|
||||||
},
|
|
||||||
tabId,
|
actions.showNotification({
|
||||||
});
|
message: successMessage,
|
||||||
} else {
|
title: {
|
||||||
actions.showNotification({
|
key: 'BotAuthSuccessTitle',
|
||||||
message: {
|
},
|
||||||
key: 'BotAuthSuccessText',
|
tabId,
|
||||||
variables: {
|
});
|
||||||
url: tabState.urlAuth?.request?.domain || result.url,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
withMarkdown: true,
|
|
||||||
withNodes: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
key: 'BotAuthSuccessTitle',
|
|
||||||
},
|
|
||||||
tabId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
actions.closeUrlAuthModal({ tabId });
|
actions.closeUrlAuthModal({ tabId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/types/language.d.ts
vendored
2
src/types/language.d.ts
vendored
@ -549,6 +549,7 @@ export interface LangPair {
|
|||||||
'AboutPremiumDescription2': undefined;
|
'AboutPremiumDescription2': undefined;
|
||||||
'OpenUrlTitle': undefined;
|
'OpenUrlTitle': undefined;
|
||||||
'OpenUrlConfirm': undefined;
|
'OpenUrlConfirm': undefined;
|
||||||
|
'BotAuthAppSubtitle': undefined;
|
||||||
'BotAuthSiteSubtitle': undefined;
|
'BotAuthSiteSubtitle': undefined;
|
||||||
'BotAuthAllowMessages': undefined;
|
'BotAuthAllowMessages': undefined;
|
||||||
'BotAuthInfo': undefined;
|
'BotAuthInfo': undefined;
|
||||||
@ -1589,6 +1590,7 @@ export interface LangPair {
|
|||||||
'NoForwardsRequestSaving': undefined;
|
'NoForwardsRequestSaving': undefined;
|
||||||
'NoForwardsRequestCopying': undefined;
|
'NoForwardsRequestCopying': undefined;
|
||||||
'ActionBotAppPlaceholder': undefined;
|
'ActionBotAppPlaceholder': undefined;
|
||||||
|
'BotAuthUnverifiedApp': undefined;
|
||||||
'ActionGiftTextUnknown': undefined;
|
'ActionGiftTextUnknown': undefined;
|
||||||
'ActionGiftTextUnknownYou': undefined;
|
'ActionGiftTextUnknownYou': undefined;
|
||||||
'ActionGiftUniqueSent': undefined;
|
'ActionGiftUniqueSent': undefined;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user