Age Verification: Follow Up (#6096)

This commit is contained in:
Alexander Zinchuk 2025-08-01 12:28:30 +02:00
parent 7f089bb858
commit 7e503ecc32
7 changed files with 44 additions and 19 deletions

View File

@ -2142,9 +2142,9 @@
"TonModalHint" = "You can top-up your TON using Fragment.";
"TonGiftReceived" = "TON Top-Up";
"MediaSpoilerSensitive" = "18+";
"TitleSensitiveModal" = "18+ content";
"TitleSensitiveModal" = "{years}+ content";
"TextSensitiveModal" = "This media may contain sensitive content suitable only for adults. Do you still want to view it?";
"ButtonSensitiveAlways" = "Always show 18+ media";
"ButtonSensitiveAlways" = "Always show {years}+ media";
"ButtonSensitiveView" = "View Anyway";
"TitleAgeVerificationModal" = "Age Verification";
"TextAgeVerificationModal_one" = "To access such content, you must confirm that you are at least **{count}** year old as required by UK law.";

View File

@ -1,5 +1,7 @@
import type { FC } from '../../lib/teact/teact';
import { memo } from '../../lib/teact/teact';
import { withGlobal } from '../../global';
import { VERIFY_AGE_MIN_DEFAULT } from '../../config';
import useLang from '../../hooks/useLang';
@ -16,18 +18,23 @@ type OwnProps = {
confirmHandler: NoneToVoidFunction;
};
const SensitiveContentConfirmModal: FC<OwnProps> = ({
type StateProps = {
verifyAgeMin: number;
};
const SensitiveContentConfirmModal = ({
isOpen,
onClose,
shouldAlwaysShow,
onAlwaysShowChanged,
confirmHandler,
}) => {
verifyAgeMin,
}: OwnProps & StateProps) => {
const lang = useLang();
return (
<ConfirmDialog
title={lang('TitleSensitiveModal')}
title={lang('TitleSensitiveModal', { years: verifyAgeMin })}
confirmLabel={lang('ButtonSensitiveView')}
isOpen={isOpen}
onClose={onClose}
@ -36,7 +43,7 @@ const SensitiveContentConfirmModal: FC<OwnProps> = ({
{lang('TextSensitiveModal')}
<Checkbox
className={styles.checkBox}
label={lang('ButtonSensitiveAlways')}
label={lang('ButtonSensitiveAlways', { years: verifyAgeMin })}
checked={shouldAlwaysShow}
onCheck={onAlwaysShowChanged}
/>
@ -44,4 +51,11 @@ const SensitiveContentConfirmModal: FC<OwnProps> = ({
);
};
export default memo(SensitiveContentConfirmModal);
export default memo(withGlobal<OwnProps>((global): StateProps => {
const appConfig = global.appConfig;
const verifyAgeMin = appConfig?.verifyAgeMin;
return {
verifyAgeMin: verifyAgeMin || VERIFY_AGE_MIN_DEFAULT,
};
})(SensitiveContentConfirmModal));

View File

@ -4,6 +4,8 @@ import { getActions, withGlobal } from '../../../global';
import type { TabState } from '../../../global/types';
import { VERIFY_AGE_MIN_DEFAULT } from '../../../config';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
@ -19,18 +21,17 @@ export type OwnProps = {
type StateProps = {
verifyAgeBotUsername?: string;
verifyAgeMin: number;
};
const AGE_REQUIRED = 18;
const AgeVerificationModal: FC<OwnProps & StateProps> = ({
modal,
verifyAgeBotUsername,
verifyAgeMin,
}) => {
const { closeAgeVerificationModal, openChatByUsername } = getActions();
const lang = useLang();
const isOpen = Boolean(modal);
const ageRequired = AGE_REQUIRED;
const handleVerifyAge = useLastCallback(() => {
if (verifyAgeBotUsername) {
@ -62,10 +63,10 @@ const AgeVerificationModal: FC<OwnProps & StateProps> = ({
{lang('TitleAgeVerificationModal')}
</h2>
<p className={styles.mainText}>
{lang('TextAgeVerificationModal', { count: ageRequired }, {
{lang('TextAgeVerificationModal', { count: verifyAgeMin }, {
withMarkdown: true,
withNodes: true,
pluralValue: ageRequired,
pluralValue: verifyAgeMin,
})}
</p>
<p className={styles.description}>
@ -86,8 +87,10 @@ const AgeVerificationModal: FC<OwnProps & StateProps> = ({
export default memo(withGlobal((global): StateProps => {
const appConfig = global.appConfig;
const verifyAgeBotUsername = appConfig?.verifyAgeBotUsername;
const verifyAgeMin = appConfig?.verifyAgeMin || VERIFY_AGE_MIN_DEFAULT;
return {
verifyAgeBotUsername,
verifyAgeMin,
};
})(AgeVerificationModal));

View File

@ -1,9 +1,10 @@
import type { ElementRef } from '../../../../lib/teact/teact';
import { useCallback, useEffect, useRef } from '../../../../lib/teact/teact';
import { getActions } from '../../../../global';
import { getActions, getGlobal } from '../../../../global';
import type { WebApp, WebAppInboundEvent, WebAppOutboundEvent } from '../../../../types/webapp';
import { VERIFY_AGE_MIN_DEFAULT } from '../../../../config';
import { getWebAppKey } from '../../../../global/helpers';
import { extractCurrentThemeParams } from '../../../../util/themeStyle';
import { REM } from '../../../common/helpers/mediaDimensions';
@ -385,8 +386,10 @@ const useWebAppFrame = (
if (eventType === 'web_app_verify_age') {
const { passed } = eventData;
const minAge = getGlobal().appConfig?.verifyAgeMin || VERIFY_AGE_MIN_DEFAULT;
const ageFromParam = eventData.age || 0;
if (passed) {
if (passed && ageFromParam >= minAge) {
showNotification({
message: {
key: 'TitleAgeCheckSuccess',

View File

@ -120,6 +120,7 @@ export const STARS_SUGGESTED_POST_FUTURE_MIN = 300; // 5 minutes in seconds
export const TON_CURRENCY_CODE = 'TON';
export const TON_SUGGESTED_POST_COMMISSION_PERMILLE = 850;
export const TON_USD_RATE_DEFAULT = 3;
export const VERIFY_AGE_MIN_DEFAULT = 18;
export const TON_TOPUP_URL_DEFAULT = 'https://fragment.com/ads/topup';
export const TON_SUGGESTED_POST_AMOUNT_MIN = 10000000; // 0.01 TON in nanos
export const TON_SUGGESTED_POST_AMOUNT_MAX = 10000000000000; // 10 000 TON in nanos

View File

@ -1667,10 +1667,10 @@ addActionHandler('openChatByUsername', async (global, actions, payload): Promise
const chatByUsername = await fetchChatByUsername(global, username);
global = getGlobal();
const user = chatByUsername && selectUser(global, chatByUsername.id);
if (!chatByUsername || !chat || !user?.hasMainMiniApp) return;
if (!chatByUsername || !user?.hasMainMiniApp) return;
actions.requestMainWebView({
botId: chatByUsername.id,
peerId: chat.id,
peerId: chat?.id || chatByUsername.id,
theme,
startParam: startApp,
mode,

View File

@ -1601,9 +1601,7 @@ export interface LangPair {
'TonModalHint': undefined;
'TonGiftReceived': undefined;
'MediaSpoilerSensitive': undefined;
'TitleSensitiveModal': undefined;
'TextSensitiveModal': undefined;
'ButtonSensitiveAlways': undefined;
'ButtonSensitiveView': undefined;
'TitleAgeVerificationModal': undefined;
'DescriptionAgeVerificationModal': undefined;
@ -2781,6 +2779,12 @@ export interface LangPairWithVariables<V = LangVariable> {
'number': V;
'owner': V;
};
'TitleSensitiveModal': {
'years': V;
};
'ButtonSensitiveAlways': {
'years': V;
};
}
export interface LangPairPlural {