This commit is contained in:
janisslsm committed 2026-11-01 12:12:55 +02:00
1 parent 1781d25a15
commit 732c0ad767
33051 files changed
+2591613 -3019689

No files matched your search

@@ -0,0 +1,31 @@
// Metro module 14721 (f14722).
import { DetectableAppNames } from "../../local_app_detection/LocalAppDetectionTypes";
import { isNotNullish } from "../../../utils/GlobalUtils";
const r11 = {};
r11[DetectableAppNames.MINECRAFT] = "1402418491272986635";
r11[DetectableAppNames.FORTNITE] = "1402418703554842694";
r11[DetectableAppNames.GENSHIN] = "762434991303950386";
r11[DetectableAppNames.PUBG_MOBILE] = "1474086506955014275";
r11[DetectableAppNames.CALL_OF_DUTY_MOBILE] = "1474087680169082943";
r11[DetectableAppNames.CLASH_OF_CLANS] = "1441990808399253575";
r11[DetectableAppNames.MOBILE_LEGENDS_BANG_BANG] = "1441992389232165056";
r11[DetectableAppNames.GARENA_FREE_FIRE] = "1407144801089880165";
r11[DetectableAppNames.POKEMON_GO] = "1474100461203357870";
r11[DetectableAppNames.POKEMON_TCG_POCKET] = "1474100935126028351";
r11[DetectableAppNames.CLASH_ROYALE] = "1420796862369239162";
r11[DetectableAppNames.AMONG_US] = "1402418440685486130";
r11[DetectableAppNames.MONOPOLY_GO] = "1474101904765227169";
r11[DetectableAppNames.BRAWL_STARS] = "1474102260807106581";
r11[DetectableAppNames.BRAWLHALLA] = "356944273133928458";
r11[DetectableAppNames.WUTHERING_WAVES] = "1247227126416146462";
let c10402_2 = r11;
export { c10402_2 as DETECTABLE_GAME_TO_APPLICATION_ID_MAP };
export function getGameIdsForDetectedGames(a0) {
return Object.entries(a0).filter((item) => {
const [, r13] = item;
return r13;
}).map((item) => {
const [r11, , ] = item;
return c10402_2[r11];
}).filter(isNotNullish);
}
@@ -0,0 +1,309 @@
// Metro module 15237 (f15238).
import { useState, useMemo, useCallback } from "react";
import { Image as Image2, View } from "react-native";
import AccessibilityStore from "../../a11y/AccessibilityStore";
import GuildStore from "../../../stores/GuildStore";
import { AnalyticEvents, GuildFeatures, JoinGuildSources } from "../../../Constants";
import { getWindowDimensions } from "../../screen/useWindowDimensions.native";
import { createStyles } from "../../../design/components/Styles/native/createStyles";
import Module712 from "../../../_bundle/Module712";
import { useStateFromStores } from "../../../_bundle/Module589";
import AvatarUtils from "../../../utils/AvatarUtils";
import { getDevicePixelRatio } from "../../image_upload/ImageLoaderUtils";
import AnalyticsUtils from "../../../utils/AnalyticsUtils";
import GuildActionCreators from "../../../actions/GuildActionCreators";
import { transitionToGuild } from "../../routing/transitionToGuild.native";
import { intl, t } from "../../../intl/index.native";
import ClipView, { CutoutShape } from "../../../design/components/Icon/native/ClipView";
import GuildBadgeV2 from "../../guild/native/GuildBadgeV2";
import { Icon } from "../../../design/void/native";
import { Text } from "../../../design/components/Text/native/Text";
import { Button } from "../../../design/components/Button/native/Button.native";
import { ContextMenu } from "../../../design/components/ContextMenu/native/ContextMenu.native";
import { IconButton } from "../../../design/components/Button/native/IconButton.native";
import { MoreHorizontalIcon } from "../../../design/components/Icon/native/redesign/generated/MoreHorizontalIcon";
const useStyles = createStyles((a0) => {
const r7 = a0 === "one-column";
const width = r7 ? 12 : 10;
let r1 = 50;
const width2 = r7 ? 56 : 50;
if (r7) {
r1 = 56;
}
const r5 = r1 / 2;
const borderRadius = width / 2;
return {
card: {
backgroundColor: Module712.colors.BG_SURFACE_RAISED,
borderColor: Module712.colors.BORDER_MUTED,
borderWidth: 1,
borderRadius: Module712.radii.lg,
overflow: "hidden",
flex: 1,
marginBottom: Module712.space.PX_16
},
bannerContainer: {
height: r7 ? 88 : 80,
backgroundColor: Module712.colors.CARD_BACKGROUND_DEFAULT
},
banner: {
flex: 1
},
content: {
flex: 1,
justifyContent: "space-between",
marginTop: r7 ? 32 : 28,
marginBottom: Module712.space.PX_12,
marginHorizontal: Module712.space.PX_12
},
guildIconContainer: {
position: "absolute",
top: r7 ? 88 - r5 - 2 : 80 - r5 - 2,
left: 16
},
guildIcon: {
width: width2,
height: width2,
borderRadius: Module712.radii.lg
},
guildNameRow: {
flexDirection: "row",
alignItems: "center",
marginBottom: Module712.space.PX_4
},
guildBadge: {
marginRight: r7 ? Module712.space.PX_8 : Module712.space.PX_4
},
guildName: {
flex: 1,
minWidth: 0
},
description: {
marginBottom: r7 ? Module712.space.PX_8 : Module712.space.PX_4
},
memberCounts: {
flexDirection: "row",
gap: Module712.space.PX_16
},
memberCount: {
display: "flex",
flexDirection: "row",
alignItems: "center",
marginBottom: r7 ? Module712.space.PX_12 : Module712.space.PX_8,
gap: 6
},
dot: {
width,
height: width,
borderRadius,
backgroundColor: Module712.colors.TEXT_STATUS_OFFLINE
},
dotOnline: {
width,
height: width,
borderRadius,
backgroundColor: Module712.colors.TEXT_STATUS_ONLINE
},
dismissButton: {
position: "absolute",
top: 8,
right: 8,
width: 2 * Module712.radii.lg,
height: 2 * Module712.radii.lg,
borderRadius: Module712.radii.lg,
backgroundColor: Module712.colors.BACKGROUND_MOD_SUBTLE,
alignItems: "center",
justifyContent: "center"
}
};
});
export default function GameCommunityMultiGuildUpsellCard(props) {
let stateFromStores2, c21797_8, c21797_9;
const { guild, gameId, variant, onDismiss } = props;
stateFromStores2 = void 0;
c21797_8 = void 0;
c21797_9 = void 0;
const styles = useStyles(variant);
const [state, setState] = useState(false);
const stateFromStores = useStateFromStores([AccessibilityStore], () => AccessibilityStore.useReducedMotion);
stateFromStores2 = useStateFromStores([GuildStore], () => GuildStore.getGuild(guild.id) != null);
let r26 = variant === "one-column";
let r0 = 50;
const r2 = r26 ? 56 : 50;
c21797_8 = r2;
const memo = useMemo(() => {
let icon = guild.icon;
if (icon == null) {
icon = null;
}
return AvatarUtils.getGuildIconSource({
id: guild.id,
icon,
canAnimate: !stateFromStores,
size: c21797_8 * getDevicePixelRatio()
});
}, [guild.id, guild.icon, stateFromStores, r2]);
const r58 = stateFromStores ? !stateFromStores : guild.features.has(GuildFeatures.ANIMATED_BANNER) === true;
c21797_9 = r58;
const memo2 = useMemo(() => {
let r12;
const { splash, banner } = guild;
if (splash != null) {
const width = getWindowDimensions().width;
r12 = AvatarUtils.getGuildSplashSource({
id: guild.id,
splash,
size: (variant !== "one-column" ? width / 2 : width) * getDevicePixelRatio()
});
} else {
r12 = banner != null ? AvatarUtils.getAnimatableSourceWithFallback(c21797_9, (a0) => AvatarUtils.getGuildBannerSource({
id: guild.id,
banner
}, a0)) : null;
}
return r12;
}, [guild.id, guild.splash, guild.banner, r58, variant]);
const callback2 = useCallback(async () => {
let c27970_2;
let c27970_3 = 0;
L16: {
try {
if (stateFromStores2) {
break L16;
}
if (state) {
break L16;
}
setState(true);
AnalyticsUtils.track(AnalyticEvents.GAME_COMMUNITY_MULTI_GUILD_UPSELL_CARD_JOINED, {
guild_id: guild.id,
game_id: gameId,
variant
});
c27970_3 = 1;
await GuildActionCreators.joinGuild(guild.id, {
source: JoinGuildSources.GAME_COMMUNITY_UPSELL,
autoNavigate: false
});
await GuildActionCreators.waitForGuild(guild.id);
c27970_3 = 0;
(0, setState)(false);
} catch ($e) {
const r29 = $e;
let r7 = r29;
c27970_2 = r29;
if (c27970_3 !== 0) {
while (true) {
try {
const r110 = c27970_2;
c27970_3 = 0;
(0, setState)(false);
throw r110;
} catch (r107) {
r7 = r107;
c27970_2 = r107;
if (c27970_3 === 0) {
break;
}
}
}
}
throw r7;
}
return void 0;
}
}, [guild.id, stateFromStores2, state, gameId, variant]);
const callback = useCallback(() => {
transitionToGuild(guild.id);
}, [guild.id]);
const memo3 = useMemo(() => onDismiss == null ? [] : [{
label: intl.string(t.XW1okC),
variant: "destructive",
action: () => onDismiss(guild.id, gameId)
}], [guild.id, gameId, onDismiss]);
let presenceCount = guild.presenceCount;
if (presenceCount == null) {
presenceCount = 0;
}
let memberCount = guild.memberCount;
if (memberCount == null) {
memberCount = 0;
}
const { name, description } = guild;
if (r26) {
r0 = 56;
}
const r4 = r0 / 2;
const width = r2 + 8;
const r122 = [<View style={styles.bannerContainer}>
<ClipView style={styles.banner} cutouts={[{
shape: CutoutShape.RoundedRect,
x: 12,
y: (r26 ? 88 - r4 - 2 : 80 - r4 - 2) - 4,
width,
height: width,
cornerRadius: Module712.radii.lg + 4
}]}>
{memo2 != null ? <Image2 style={styles.banner} source={memo2} resizeMode="cover" /> : <View style={styles.banner} />}
</ClipView>
</View>, <View style={styles.guildIconContainer}>
<Image2 style={styles.guildIcon} source={memo} />
</View>, , ,];
const Sizes = Icon.Sizes;
const r165 = [<View>
<View style={styles.guildNameRow}>
<GuildBadgeV2 guild={guild} size={r26 ? Sizes.REFRESH_SMALL_16 : Sizes.EXTRA_SMALL} style={styles.guildBadge} />
<Text variant={r26 ? "heading-md/bold" : "heading-sm/bold"} color="mobile-text-heading-primary" accessibilityRole="header" style={styles.guildName} lineClamp={1}>{name}</Text>
</View>
{description != null && description.length > 0 && <Text variant={r26 ? "text-sm/medium" : "text-xs/medium"} style={styles.description} lineClamp={3}>{description}</Text>}
</View>, ,];
const r191 = [presenceCount > 0 && <View style={styles.memberCount}>
<View style={styles.dotOnline} />
<Text variant="text-xs/medium" color="text-subtle">
{intl.format(t["LC+S+m"], {
membersOnline: presenceCount
})}
</Text>
</View>, ,];
if (r26) {
r26 = memberCount > 0;
}
if (r26) {
r26 = <View style={styles.memberCount}>
<View style={styles.dot} />
<Text variant="text-xs/medium" color="text-subtle">
{intl.format(t.zRl6XR, {
count: memberCount
})}
</Text>
</View>;
}
r191[1] = r26;
r165[1] = <View>
<View style={styles.memberCounts}>{r191}</View>
<Button {...stateFromStores2 ? {
variant: "active",
size: "sm",
text: intl.string(t.KLOhbO),
onPress: callback,
grow: true
} : {
variant: "primary",
size: "sm",
loading: state,
text: intl.string(t.VJlc0S),
onPress: callback2,
grow: true
}} />
</View>;
r122[2] = <View style={styles.content}>{r165}</View>;
r122[3] = memo3.length > 0 && <View style={styles.dismissButton}>
<ContextMenu items={memo3}>
{(a0) => {
const { ref, ...rest } = a0;
return <IconButton ref={a0.ref} {...rest} icon={<MoreHorizontalIcon size="sm" />} size="sm" variant="secondary-overlay" accessibilityLabel={intl.string(t.ogxXGq)} />;
}}
</ContextMenu>
</View>;
return <View style={styles.card}>{r122}</View>;
};
@@ -0,0 +1,276 @@
// Metro module 15236 (f15237).
import { useCallback, useRef, useMemo } from "react";
import { View } from "react-native";
import MobileGameCommunitiesStore from "./MobileGameCommunitiesStore";
import { AnalyticEvents } from "../../../Constants";
import { MIN_HEADER_HEIGHT } from "../../main_tabs_v2/native/shared_components/MainTabsV2Constants";
import { jsx } from "react/jsx-runtime";
import { createStyles } from "../../../design/components/Styles/native/createStyles";
import Module712 from "../../../_bundle/Module712";
import { useFocusEffect } from "../../../_bundle/Module1481";
import { useStateFromStoresObject, useStateFromStoresArray } from "../../../_bundle/Module589";
import useAnalyticsLocations from "../../app_analytics/useAnalyticsLocations";
import AnalyticsLocation from "../../app_analytics/AnalyticsLocation";
import GameCommunityMultiGuildUpsellCard from "./GameCommunityMultiGuildUpsellCard";
import { FlashList } from "../../../_bundle/noop_6676";
import useSafeAreaInsets_native from "../../safe_area/useSafeAreaInsets.native";
import { useGradientTop } from "../../client_themes/native/ClientThemesOverrides";
import { GameCommunityUpsellMultiExperiment } from "./GameCommunityUpsellExperiment";
import { Text } from "../../../design/components/Text/native/Text";
import { intl, t } from "../../../intl/index.native";
import { dismissGuild } from "./MobileGameCommunitiesActionCreators";
import AnalyticsUtils from "../../../utils/AnalyticsUtils";
import { HeaderIconButton } from "../../main_tabs_v2/native/shared_components/HeaderShared";
import Module9126 from "../../../_bundle/Module9126";
function $mk95782($env) {
return () => {
$env[3].current.clear();
};
}
function $mk95783($env) {
return (a0) => {
a0.viewableItems.forEach($mk110713($env));
};
}
function $mk110713($env) {
return ({ item }) => {
if (item != null) {
let r0 = "left" in item && item.left != null;
const r5 = $env;
if (r0) {
r0 = !r5[3].current.has(item.left.id);
}
if (r0) {
const r21 = $env.$parent;
const r22 = r5[3];
const left = item.left;
const game_id = r5[0][item.left.id];
const variant = r5[1];
const location_stack = r5[2];
r22.current.add(left.id);
const r13 = r21[0];
const r29 = r21[3];
r13(r29[8]).trackImpression({
type: r13(r29[9]).ImpressionTypes.PANE,
name: r13(r29[9]).ImpressionNames.GAME_COMMUNITY_MULTI_GUILD_UPSELL_CARD,
properties: {
game_id,
guild_id: left.id,
location_stack,
variant
}
});
}
if ("right" in item && item.right != null && !r5[3].current.has(item.right.id)) {
const r54 = $env.$parent;
const r55 = r5[3];
const right = item.right;
const game_id2 = r5[0][item.right.id];
const variant2 = r5[1];
const location_stack2 = r5[2];
r55.current.add(right.id);
const r67 = r54[0];
const r68 = r54[3];
r67(r68[8]).trackImpression({
type: r67(r68[9]).ImpressionTypes.PANE,
name: r67(r68[9]).ImpressionNames.GAME_COMMUNITY_MULTI_GUILD_UPSELL_CARD,
properties: {
game_id: game_id2,
guild_id: right.id,
location_stack: location_stack2,
variant: variant2
}
});
}
if ("id" in item && item.id != null && !r5[3].current.has(item.id)) {
const r93 = $env.$parent;
const r94 = r5[3];
const game_id3 = r5[0][item.id];
const variant3 = r5[1];
const location_stack3 = r5[2];
r94.current.add(item.id);
const r104 = r93[0];
const r105 = r93[3];
r104(r105[8]).trackImpression({
type: r104(r105[9]).ImpressionTypes.PANE,
name: r104(r105[9]).ImpressionNames.GAME_COMMUNITY_MULTI_GUILD_UPSELL_CARD,
properties: {
game_id: game_id3,
guild_id: item.id,
location_stack: location_stack3,
variant: variant3
}
});
}
}
};
}
let TwoColumnGuildUpsellList, useStyles, c10820_12;
let env10820 = {};
export function OneColumnGuildUpsellList({ suggestedGuilds: suggestedGuilds2, contentContainerStyle, subheader, onDismiss }) {
let stateFromStoresObject;
let env21793;
stateFromStoresObject = void 0;
const callback = useCallback((a0) => a0.id, []);
stateFromStoresObject = useStateFromStoresObject([MobileGameCommunitiesStore], () => MobileGameCommunitiesStore.getGuildGameIds());
const analyticsLocations = useAnalyticsLocations(AnalyticsLocation.GAME_COMMUNITY_MULTI_GUILD_UPSELL_GUILDS_BAR_ENTRYPOINT).analyticsLocations;
const callback2 = useCallback(({ item }) => <GameCommunityMultiGuildUpsellCard key={item.id} guild={item} gameId={stateFromStoresObject[item.id]} variant="one-column" onDismiss={stateFromStoresObject[item.id] != null ? onDismiss : null} />, [onDismiss, stateFromStoresObject]);
const r40 = env21793 = {
$parent: env10820
};
env21793[0] = stateFromStoresObject;
env21793[1] = "one-column";
env21793[2] = analyticsLocations;
env21793[3] = void 0;
env21793[3] = useRef(new Set());
useFocusEffect(useCallback($mk95782(r40), []));
return (0, jsx)(FlashList, {
onViewableItemsChanged: useCallback($mk95783(r40), [stateFromStoresObject, analyticsLocations, "one-column"]),
viewabilityConfig: c10820_12,
contentContainerStyle,
keyExtractor: callback,
data: suggestedGuilds2,
ListHeaderComponent: subheader,
renderItem: callback2
});
}
TwoColumnGuildUpsellList = function TwoColumnGuildUpsellList({ suggestedGuilds, contentContainerStyle, rowStyle, subheader, onDismiss: onDismiss2 }) {
let stateFromStoresObject2;
let env21795;
stateFromStoresObject2 = void 0;
const memo = useMemo(() => suggestedGuilds.reduce((acc, suggestedGuild, index) => {
if (index % 2 === 0) {
acc.push({
left: suggestedGuild,
right: suggestedGuilds[index + 1]
});
}
return acc;
}, []), [suggestedGuilds]);
const callback = useCallback((a0) => {
let r5 = a0.left?.id;
if (r5 == null) {
r5 = "";
}
let r6 = a0.right?.id;
if (r6 == null) {
r6 = "";
}
return `${r5}-${r6}`;
}, []);
stateFromStoresObject2 = useStateFromStoresObject([MobileGameCommunitiesStore], () => MobileGameCommunitiesStore.getGuildGameIds());
const analyticsLocations = useAnalyticsLocations(AnalyticsLocation.GAME_COMMUNITY_MULTI_GUILD_UPSELL_GUILDS_BAR_ENTRYPOINT).analyticsLocations;
const r42 = env21795 = {
$parent: env10820
};
env21795[0] = stateFromStoresObject2;
env21795[1] = "two-column";
env21795[2] = analyticsLocations;
env21795[3] = void 0;
env21795[3] = useRef(new Set());
useFocusEffect(useCallback($mk95782(r42), []));
return (0, jsx)(FlashList, {
onViewableItemsChanged: useCallback($mk95783(r42), [stateFromStoresObject2, analyticsLocations, "two-column"]),
viewabilityConfig: c10820_12,
contentContainerStyle,
keyExtractor: callback,
data: memo,
ListHeaderComponent: subheader,
renderItem: useCallback(({ item }) => {
const r1 = item.left?.id != null && stateFromStoresObject2[item.left.id] != null;
const r25 = item.right?.id != null && stateFromStoresObject2[item.right.id] != null;
return <View style={rowStyle}>
{item.left != null && <GameCommunityMultiGuildUpsellCard guild={item.left} gameId={stateFromStoresObject2[item.left.id]} variant="two-column" onDismiss={r1 ? onDismiss2 : null} />}
{item.right != null ? <GameCommunityMultiGuildUpsellCard guild={item.right} gameId={stateFromStoresObject2[item.right.id]} variant="two-column" onDismiss={r25 ? onDismiss2 : null} /> : (0, jsx)(View, {
style: {
flex: 1
}
})}
</View>;
}, [rowStyle, onDismiss2, stateFromStoresObject2])
});
};
useStyles = createStyles((a0, a1) => ({
container: {
flex: 1,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW
},
headerWrapper: {
flexDirection: "row",
alignItems: "center",
flexShrink: 0,
paddingTop: a1,
minHeight: a1 + MIN_HEADER_HEIGHT,
paddingHorizontal: Module712.space.PX_8
},
headerTitle: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
subtitle: {
alignSelf: "center",
marginHorizontal: Module712.space.PX_24,
marginBottom: Module712.space.PX_24,
marginTop: Module712.space.PX_8,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW,
textAlign: "center"
},
listContent: {
paddingHorizontal: Module712.space.PX_16,
paddingBottom: a0
},
twoColumnRow: {
flexDirection: "row",
gap: Module712.space.PX_16,
flex: 1
}
}));
c10820_12 = {
itemVisiblePercentThreshold: 50,
minimumViewTime: 500
};
export default function GameCommunityMultiGuildUpsellModal(props) {
const onClose = props.onClose;
const safeAreaInsets_native = useSafeAreaInsets_native();
const { top, bottom } = safeAreaInsets_native;
const gradientTop = useGradientTop();
const styles = useStyles(bottom, top);
let c21796_1 = styles;
const visualVariant = GameCommunityUpsellMultiExperiment.useConfig({
location: "GameCommunityMultiGuildUpsellModal"
}).visualVariant;
const stateFromStoresArray = useStateFromStoresArray([MobileGameCommunitiesStore], () => MobileGameCommunitiesStore.getPresentableUpsellGuilds());
const memo2 = useMemo(() => [c21796_1.headerWrapper, gradientTop], [styles.headerWrapper, gradientTop]);
const memo = useMemo(() => <Text variant="text-sm/medium" color="text-muted" style={c21796_1.subtitle}>
{intl.string(t["PH+G/A"])}
</Text>, [styles.subtitle]);
const callback = useCallback((a0, a1) => {
dismissGuild(a0);
AnalyticsUtils.track(AnalyticEvents.GAME_COMMUNITY_MULTI_GUILD_UPSELL_CARD_DISMISSED, {
game_id: a1,
guild_id: a0,
variant: visualVariant
});
}, [visualVariant]);
return <View style={styles.container}>
<View style={memo2}>
<HeaderIconButton source={Module9126} onPress={onClose} accessibilityLabel={intl.string(t.cpT0Cq)} />
<View style={styles.headerTitle}>
<Text variant="redesign/heading-18/bold" color="mobile-text-heading-primary" lineClamp={1}>
{intl.string(t["fs+2Kn"])}
</Text>
</View>
<View style={{
width: 40
}} />
</View>
<View style={{
flex: 1
}}>
{visualVariant === "one-column" ? <OneColumnGuildUpsellList suggestedGuilds={stateFromStoresArray.slice(0, 8)} contentContainerStyle={styles.listContent} subheader={memo} onDismiss={callback} /> : null}
{visualVariant === "two-column" ? <TwoColumnGuildUpsellList suggestedGuilds={stateFromStoresArray.slice(0, 20)} contentContainerStyle={styles.listContent} rowStyle={styles.twoColumnRow} subheader={memo} onDismiss={callback} /> : null}
</View>
</View>;
};
export { TwoColumnGuildUpsellList };
@@ -0,0 +1,99 @@
// Metro module 14719 (f14720).
import { useCallback } from "react";
import { ScrollView, View } from "react-native";
import LocalAppDetectionStore from "../../local_app_detection/native/LocalAppDetectionStore";
import MobileGameCommunitiesStore from "./MobileGameCommunitiesStore";
import { createStyles } from "../../../design/components/Styles/native/createStyles";
import Module712 from "../../../_bundle/Module712";
import { useStateFromStores, useStateFromStoresObject } from "../../../_bundle/Module589";
import { DETECTABLE_GAME_TO_APPLICATION_ID_MAP } from "./GameCommunityConfig";
import { detectLocalApps } from "../../local_app_detection/native/LocalAppDetectionUtils";
import { ALL_DETECTABLE_APP_NAMES } from "../../local_app_detection/LocalAppDetectionTypes";
import { TableRowGroup } from "../../../design/components/TableRow/native/TableRowGroup.native";
import { TableRow } from "../../../design/components/TableRow/native/TableRow.native";
import { RefreshIcon } from "../../../design/components/Icon/native/redesign/generated/RefreshIcon";
import { TableRowArrow } from "../../../design/components/TableRow/native/TableRowArrow.native";
import { removeDismissedContent } from "../../user_settings/UserSettingsProtoActionCreators";
import { DismissibleContent } from "../../../_bundle/Module1358";
import { resetDismissibleContentFrameworkStore } from "../../dismissible_content/DismissibleContentFrameworkActionCreators";
let useStyles;
const MultiGuildDevTools = function MultiGuildDevTools() {
let callback;
const styles = useStyles();
const stateFromStores = useStateFromStores([LocalAppDetectionStore], () => LocalAppDetectionStore.getUserAgnosticState());
const stateFromStoresObject = useStateFromStoresObject([MobileGameCommunitiesStore], () => ({
guildsCount: MobileGameCommunitiesStore.getPresentableUpsellGuilds().length,
dismissedCount: MobileGameCommunitiesStore.getDismissedGuildIds().size,
lastFetchedAt: MobileGameCommunitiesStore.getLastFetchedAt()
}));
const { guildsCount, dismissedCount, lastFetchedAt } = stateFromStoresObject;
const r14 = Object.entries(DETECTABLE_GAME_TO_APPLICATION_ID_MAP).map((item) => {
const [detectableAppName, gameId] = item;
const r19 = stateFromStores.apps[detectableAppName];
let detected = r19?.detected;
if (detected == null) {
detected = false;
}
return {
detectableAppName,
gameId,
detected,
lastScannedAt: r19?.lastScannedAt
};
});
const subLabel = lastFetchedAt > 0 ? `${new Date(lastFetchedAt).toLocaleTimeString()}` : "Never";
callback = useCallback(() => {
LocalAppDetectionStore.DEV_resetState();
MobileGameCommunitiesStore.DEV_clearFetchCache();
detectLocalApps(ALL_DETECTABLE_APP_NAMES);
}, []);
return <View style={styles.container}>
<ScrollView style={styles.scrollView}>
<View style={styles.section}>
<TableRowGroup title="Detected Apps" hasIcons={false}>
{r14.length === 0 ? <TableRow label="No games configured" subLabel="MULTI_GUILD_GAME_CONFIGS is empty" disabled /> : r14.map((item) => <TableRow key={item.detectableAppName} label={item.detectableAppName} subLabel={`Game ID: ${item.gameId} — ${item.detected ? "Detected" : "Not detected"}${item.lastScannedAt != null ? ` (scanned ${new Date(item.lastScannedAt).toLocaleTimeString()})` : ""}`} disabled />)}
</TableRowGroup>
</View>
<View style={styles.section}>
<TableRowGroup title="Store State" hasIcons={false}>
<TableRow label="Presentable Guilds" subLabel={String(guildsCount)} disabled />
<TableRow label="Dismissed Guilds" subLabel={String(dismissedCount)} disabled />
<TableRow label="Last Fetched" subLabel={subLabel} disabled />
</TableRowGroup>
</View>
<View style={styles.section}>
<TableRowGroup title="Actions" hasIcons>
<TableRow label="Refresh Upsell Guilds" subLabel="Redects games and suggested guilds" onPress={callback} icon={<RefreshIcon />} trailing={<TableRowArrow />} />
<TableRow label="Clear Dismissed Guilds" subLabel="Reset dismissed guild IDs so all guilds show again" onPress={() => {
MobileGameCommunitiesStore.DEV_clearDismissedGuilds();
callback();
}} icon={<RefreshIcon />} trailing={<TableRowArrow />} />
<TableRow label="Clear All Store State" subLabel="Reset all MobileGameCommunitiesStore state (guilds, dismissed, fetch cache)" onPress={() => {
MobileGameCommunitiesStore.DEV_clearState();
}} icon={<RefreshIcon />} trailing={<TableRowArrow />} />
<TableRow label="Reset Upsell Animation" subLabel="Clear the dismissed state for the create button NUX animation so it can replay" onPress={() => {
removeDismissedContent(DismissibleContent.MOBILE_MULTI_GUILD_CREATE_UPSELL_ANIMATION);
resetDismissibleContentFrameworkStore();
}} icon={<RefreshIcon />} trailing={<TableRowArrow />} />
</TableRowGroup>
</View>
</ScrollView>
</View>;
};
useStyles = createStyles({
container: {
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW,
flex: 1
},
scrollView: {
flex: 1
},
section: {
paddingHorizontal: Module712.space.PX_16,
paddingTop: Module712.space.PX_16,
paddingBottom: Module712.space.PX_8
}
});
export default function GameCommunityUpsellDevTools() {
return <MultiGuildDevTools />;
};
@@ -0,0 +1,22 @@
// Metro module 12765 (f12766).
import { createApexExperiment } from "../../experiments/apex/index";
const apexExperiment = createApexExperiment({
name: "2026-02-game-community-upsell-multi",
kind: "user",
defaultConfig: {
enabled: false,
visualVariant: "one-column"
},
variations: {
1: {
enabled: true,
visualVariant: "one-column"
},
2: {
enabled: true,
visualVariant: "two-column"
}
}
});
export const GAME_COMMUNITY_UPSELL_MULTI_EXPERIMENT = "2026-02-game-community-upsell-multi";
export { apexExperiment as GameCommunityUpsellMultiExperiment };
@@ -0,0 +1,118 @@
// Metro module 15232 (f15233).
import { useEffect, useCallback, useMemo } from "react";
import { View } from "react-native";
import MobileGameCommunitiesStore from "./MobileGameCommunitiesStore";
import { AnalyticEvents } from "../../../Constants";
import { createStyles } from "../../../design/components/Styles/native/createStyles";
import Module712 from "../../../_bundle/Module712";
import { GameCommunityUpsellMultiExperiment } from "./GameCommunityUpsellExperiment";
import { fetchMobileGameCommunities, dismissGuild } from "./MobileGameCommunitiesActionCreators";
import { useStateFromStoresArray } from "../../../_bundle/Module589";
import AnalyticsUtils from "../../../utils/AnalyticsUtils";
import CreateGuildModalActionCreators from "../../create_guild/native/CreateGuildModalActionCreators";
import { Card } from "../../../design/components/Card/native/Card.native";
import { Text } from "../../../design/components/Text/native/Text";
import { intl, t } from "../../../intl/index.native";
import { Button } from "../../../design/components/Button/native/Button.native";
import { useYouBarTotalHeight } from "../../main_tabs_v2/native/you_bar/hooks/useYouBarTotalHeight";
import { GuildsEmptyContent } from "../../main_tabs_v2/native/tabs/guilds/empty_states/GuildsEmpty";
import { OneColumnGuildUpsellList, TwoColumnGuildUpsellList } from "./GameCommunityMultiGuildUpsellModal";
const useStyles = createStyles({
container: {
flex: 1,
backgroundColor: Module712.colors.PANEL_BG
},
header: {
height: 56,
flexDirection: "row",
alignItems: "center",
marginHorizontal: Module712.space.PX_16
},
headerTitle: {
flex: 1
},
twoColumnRow: {
flexDirection: "row",
gap: Module712.space.PX_16,
flex: 1
},
listContainer: {
flex: 1
},
subheaderWrapper: {
marginBottom: Module712.space.PX_8
},
createCard: {
backgroundColor: Module712.colors.BG_SURFACE_RAISED,
gap: Module712.space.PX_4,
marginBottom: Module712.space.PX_24
},
descriptionSpacing: {
marginBottom: Module712.space.PX_8
},
joinSection: {
gap: Module712.space.PX_4
}
});
export default function GuildUpsellChannelList(props) {
let callback, youBarTotalHeight;
const style = props.style;
callback = void 0;
youBarTotalHeight = void 0;
const styles = useStyles();
const visualVariant = GameCommunityUpsellMultiExperiment.useConfig({
location: "GuildUpsellChannelList"
}).visualVariant;
useEffect(() => {
fetchMobileGameCommunities(Array.from(MobileGameCommunitiesStore.getLastFetchedGameIds()), Array.from(MobileGameCommunitiesStore.getDismissedGuildIds()));
}, []);
const stateFromStoresArray = useStateFromStoresArray([MobileGameCommunitiesStore], () => MobileGameCommunitiesStore.getPresentableUpsellGuilds().slice(0, visualVariant === "one-column" ? 8 : 20));
const callback2 = useCallback((a0, a1) => {
dismissGuild(a0);
AnalyticsUtils.track(AnalyticEvents.GAME_COMMUNITY_MULTI_GUILD_UPSELL_CARD_DISMISSED, {
game_id: a1,
guild_id: a0,
variant: visualVariant
});
}, [visualVariant]);
callback = useCallback(() => {
CreateGuildModalActionCreators.openCreateGuildModal();
}, []);
const memo = useMemo(() => <View style={styles.subheaderWrapper}>
<Card style={styles.createCard}>
<Text variant="heading-md/bold" color="mobile-text-heading-primary">
{intl.string(t.B44MTm)}
</Text>
<Text variant="text-sm/medium" color="text-default" style={styles.descriptionSpacing}>
{intl.string(t.l0tmhq)}
</Text>
<Button variant="primary" size="sm" text={intl.string(t.CumH4u)} onPress={callback} grow />
</Card>
<View style={styles.joinSection}>
<Text variant="heading-md/bold" color="mobile-text-heading-primary">
{intl.string(t.rJRote)}
</Text>
<Text variant="text-sm/medium" color="text-subtle" style={styles.descriptionSpacing}>
{intl.string(t.pJT2DK)}
</Text>
</View>
</View>, [callback, styles.subheaderWrapper, styles.createCard, styles.descriptionSpacing, styles.joinSection]);
youBarTotalHeight = useYouBarTotalHeight();
const memo2 = useMemo(() => ({
paddingHorizontal: Module712.space.PX_16,
paddingBottom: Module712.space.PX_16 + youBarTotalHeight
}), [youBarTotalHeight]);
return stateFromStoresArray.length === 0 ? <View style={[styles.container, style]}>
<GuildsEmptyContent />
</View> : <View style={[styles.container, style]}>
<View style={styles.header}>
<Text style={styles.headerTitle} color="mobile-text-heading-primary" variant="heading-lg/bold">
{intl.string(t["7hB4kg"])}
</Text>
</View>
<View style={styles.listContainer}>
{visualVariant === "one-column" ? <OneColumnGuildUpsellList suggestedGuilds={stateFromStoresArray} contentContainerStyle={memo2} onDismiss={callback2} subheader={memo} /> : null}
{visualVariant === "two-column" ? <TwoColumnGuildUpsellList suggestedGuilds={stateFromStoresArray} contentContainerStyle={memo2} rowStyle={styles.twoColumnRow} onDismiss={callback2} subheader={memo} /> : null}
</View>
</View>;
};
@@ -0,0 +1,42 @@
// Metro module 15233 (f15234).
import { Endpoints } from "../../../Constants";
import { HTTP } from "../../../_bundle/sendRequest";
import Module1464 from "../../../_bundle/Module1464";
import Dispatcher from "../../../Dispatcher";
export function fetchMobileGameCommunities(a0) {
const gameIds = a0;
let ignored_guild_ids = arguments[1];
if (ignored_guild_ids === void 0) {
ignored_guild_ids = [];
}
let limit = arguments[2];
if (limit === void 0) {
limit = 20;
}
return HTTP.get({
url: Endpoints.MOBILE_GAME_COMMUNITIES,
query: Module1464.stringify({
game_ids: a0,
limit,
ignored_guild_ids
}),
oldFormErrors: true,
rejectWithError: true
}).then((result) => {
Dispatcher.dispatch({
type: "MOBILE_GAME_COMMUNITIES_FETCH_SUCCESS",
guilds: result.body.guilds,
gameIds
});
}, () => {
Dispatcher.dispatch({
type: "MOBILE_GAME_COMMUNITIES_FETCH_FAILURE"
});
});
}
export function dismissGuild(a0) {
Dispatcher.dispatch({
type: "MOBILE_GAME_COMMUNITIES_DISMISS_GUILD",
guildId: a0
});
}
@@ -0,0 +1,42 @@
// Metro module 16334 (f16335).
import LocalAppDetectionStore from "../../local_app_detection/native/LocalAppDetectionStore";
import MobileGameCommunitiesStore from "./MobileGameCommunitiesStore";
import AutomaticLifecycleManager from "../../../lib/AutomaticLifecycleManager";
import { getGameIdsForDetectedGames } from "./GameCommunityConfig";
import { fetchMobileGameCommunities } from "./MobileGameCommunitiesActionCreators";
import { GameCommunityUpsellMultiExperiment } from "./GameCommunityUpsellExperiment";
import { ALL_DETECTABLE_APP_NAMES } from "../../local_app_detection/LocalAppDetectionTypes";
class MobileGameCommunitiesManager extends AutomaticLifecycleManager {
actions = {
LOCAL_APP_DETECTION_COMPLETE: (a0) => this.handleLocalAppDetectionComplete(a0),
POST_CONNECTION_OPEN: () => this.handlePostConnectionOpen()
};
_fetchGameCommunities(a0) {
const gameIdsForDetectedGames = getGameIdsForDetectedGames(a0);
const r18 = Date.now() - MobileGameCommunitiesStore.getLastFetchedAt();
const r20 = gameIdsForDetectedGames.some((gameIdsForDetectedGame) => !MobileGameCommunitiesStore.getLastFetchedGameIds().has(gameIdsForDetectedGame));
if (!(!(r18 >= 86400000) && !r20)) {
fetchMobileGameCommunities(gameIdsForDetectedGames, Array.from(MobileGameCommunitiesStore.getDismissedGuildIds()), 6);
}
}
handlePostConnectionOpen() {
if (GameCommunityUpsellMultiExperiment.getConfig({
location: "MobileGameCommunitiesManager"
}).enabled && MobileGameCommunitiesStore.getLastFetchedAt() === 0 && Object.values(LocalAppDetectionStore.getUserAgnosticState().apps).some((item) => item?.lastScannedAt != null)) {
const r37 = {};
for (const item of ALL_DETECTABLE_APP_NAMES) {
r37[item] = LocalAppDetectionStore.isAppInstalled(item);
}
this._fetchGameCommunities(r37);
}
}
handleLocalAppDetectionComplete({ result }) {
if (GameCommunityUpsellMultiExperiment.getConfig({
location: "MobileGameCommunitiesManager"
}).enabled) {
this._fetchGameCommunities(result);
}
}
}
const mobileGameCommunitiesManager = new MobileGameCommunitiesManager();
export default mobileGameCommunitiesManager;
@@ -0,0 +1,127 @@
// Metro module 14720 (f14721).
import { makeDiscoverableGuild } from "../../../utils/GuildDiscoveryUtils";
import Module589 from "../../../_bundle/Module589";
import Dispatcher from "../../../Dispatcher";
let c10401_2 = {
guilds: [],
lastFetchedAt: 0,
lastFetchedGameIds: new Set(),
dismissedGuildIds: new Set(),
guildGameIds: {}
};
class MobileGameCommunitiesStore extends Module589.PersistedStore {
static displayName = "MobileGameCommunitiesStore";
static persistKey = "MobileGameCommunitiesStore";
initialize(a0) {
if (a0 != null) {
const r3 = {
guilds: a0.guilds.map((guild) => ({
...guild,
features: new Set(guild.features)
})),
lastFetchedAt: a0.lastFetchedAt,
lastFetchedGameIds: new Set(a0.lastFetchedGameIds),
dismissedGuildIds: new Set(a0.dismissedGuildIds),
guildGameIds: null
};
let guildGameIds = a0.guildGameIds;
if (guildGameIds == null) {
guildGameIds = {};
}
r3.guildGameIds = guildGameIds;
c10401_2 = r3;
}
}
getState() {
return {
guilds: c10401_2.guilds.map((guild) => ({
...guild,
features: [...guild.features]
})),
lastFetchedAt: c10401_2.lastFetchedAt,
lastFetchedGameIds: [...c10401_2.lastFetchedGameIds],
dismissedGuildIds: [...c10401_2.dismissedGuildIds],
guildGameIds: c10401_2.guildGameIds
};
}
getPresentableUpsellGuilds() {
return c10401_2.guilds.filter((guild) => !c10401_2.dismissedGuildIds.has(guild.id));
}
hasGuilds() {
return this.getPresentableUpsellGuilds().length > 0;
}
getLastFetchedAt() {
return c10401_2.lastFetchedAt;
}
getLastFetchedGameIds() {
return c10401_2.lastFetchedGameIds;
}
getGuildGameIds() {
return c10401_2.guildGameIds;
}
getDismissedGuildIds() {
return c10401_2.dismissedGuildIds;
}
DEV_clearFetchCache() {
c10401_2 = {
...c10401_2,
guilds: [],
lastFetchedAt: 0,
lastFetchedGameIds: new Set(),
guildGameIds: {}
};
this.emitChange();
}
DEV_clearDismissedGuilds() {
c10401_2 = {
...c10401_2,
dismissedGuildIds: new Set()
};
this.emitChange();
}
DEV_clearState() {
c10401_2 = {
guilds: [],
lastFetchedAt: 0,
lastFetchedGameIds: new Set(),
dismissedGuildIds: new Set(),
guildGameIds: {}
};
this.emitChange();
}
}
const mobileGameCommunitiesStore = new MobileGameCommunitiesStore(Dispatcher, {
MOBILE_GAME_COMMUNITIES_FETCH_SUCCESS: function handleFetchSuccess({ guilds, gameIds }) {
const guildGameIds = {
...c10401_2.guildGameIds
};
for (const item of guilds) {
if (item.game_id != null) {
guildGameIds[item.id] = item.game_id;
}
}
c10401_2 = {
...c10401_2,
guilds: guilds.map((guild) => makeDiscoverableGuild(guild)),
lastFetchedAt: Date.now(),
lastFetchedGameIds: new Set(gameIds),
guildGameIds
};
},
MOBILE_GAME_COMMUNITIES_DISMISS_GUILD: function handleDismissGuildAction(a0) {
c10401_2 = {
...c10401_2,
dismissedGuildIds: new Set([...c10401_2.dismissedGuildIds, a0.guildId])
};
},
LOGOUT: function handleLogout() {
c10401_2 = {
guilds: [],
lastFetchedAt: 0,
lastFetchedGameIds: new Set(),
dismissedGuildIds: new Set(),
guildGameIds: {}
};
}
});
export default mobileGameCommunitiesStore;