Files
discord-decomp/modules/quests/native/QuestHomeBounties.tsx
T
2026-11-01 12:12:55 +02:00

363 lines
15 KiB
TypeScript

// Metro module 14093 (f14094).
import * as Module19 from "react";
import { useRef, useState, useCallback, useMemo, useEffect } from "react";
import { View } from "react-native";
import BountyStore from "../BountyStore";
import { BountyCarouselEmptyStateReason } from "../QuestConstants";
import { ContentDismissActionType } from "../../dismissible_content/DismissibleContentConstants";
import Module712 from "../../../_bundle/Module712";
import BountyCard, { CARD_WIDTH } from "./BountyCard";
import { createStyles } from "../../../design/components/Styles/native/createStyles";
import { useBountyCarouselEmptyStateAnalytics } from "../lib/analytics/AnalyticsHooks";
import { intl, t } from "../../../intl/index.native";
import { BountiesPosterIllocon } from "../../../design/assets/native";
import { Text } from "../../../design/components/Text/native/Text";
import openBountiesNuxPromoSheet, { PROMO_SHEET_KEY } from "./openBountiesNuxPromoSheet";
import { DismissibleContent } from "../../../_bundle/Module1358";
import { useSelectedDismissibleContent } from "../../dismissible_content/hooks/useSelectedDismissibleContent";
import Dispatcher from "../../../Dispatcher";
import { MIN_PRODUCTS_FOR_ORB_SHOP_CAROUSEL } from "../../collectibles/native/hooks/usePopularOrbShopProducts";
import { triggerHapticFeedback, HapticFeedbackTypes } from "../../haptics/HapticUtils.native";
import { trackBountyCarouselScroll, trackAdContentClicked } from "../lib/analytics/AnalyticsActions";
import { BountyScrollingType, HorizontalScrollingDirection, QuestContentCTA } from "../lib/analytics/AnalyticsTypes";
import { QuestContent } from "../QuestTypes";
import BountiesModalActionCreators, { BOUNTIES_MODAL_KEY } from "./BountiesModal/BountiesModalActionCreators";
import { runAfterInteractions } from "../../../utils/native/RunAfterInteractionsUtils";
import { shouldMigrateToAdAnalyticsInterface, AdAnalyticsInterfaceExperimentStep } from "../experiments/AdAnalyticsInterfaceExperiment";
import { captureAdUserAction } from "../../ads/analytics/captureAdUserAction";
import { AdUserActionType } from "../../ads/analytics/captureAdUserActionTypes";
import { AdCreativeType } from "../../../_bundle/Module6013";
import useIsCarouselInView from "./useIsCarouselInView";
import { BillableAdPlacementImpressionTrackerNative } from "./QuestContentImpressionTracker.native";
import { FlashList } from "../../../_bundle/noop_6676";
import QuestHomeOrbShopCarousel from "./QuestHomeOrbShopCarousel";
import { useQuestHomeBounties } from "../hooks/QuestHooks";
import { useStateFromStores } from "../../../_bundle/Module589";
import BountiesCtaHeader from "./BountiesCtaHeader";
let PX_16, PX_162, c9859_13, useStyles, ItemSeparator, keyExtractor, QuestHomeBountiesCarousel;
const EmptyState = function EmptyState(props) {
const reason = props.reason;
const styles = useStyles();
useBountyCarouselEmptyStateAnalytics(reason);
return <View style={styles.emptyState}>
<BountiesPosterIllocon size={32} />
<View style={styles.emptyStateText}>
<Text variant="text-sm/semibold" color="text-default">
{reason === BountyCarouselEmptyStateReason.COMPLETED ? intl.string(t.O2hRaZ) : intl.string(t.TKuW8z)}
</Text>
<Text variant="text-xs/medium" color="text-muted">
{intl.format(reason === BountyCarouselEmptyStateReason.COMPLETED ? t["D/790X"] : t.ReqPds, {
onClickLearnMore: function onClickLearnMore() {
openBountiesNuxPromoSheet();
}
})}
</Text>
</View>
</View>;
};
ItemSeparator = function ItemSeparator() {
return <View style={{
width: PX_162
}} />;
};
keyExtractor = function keyExtractor(a0) {
return a0.id;
};
QuestHomeBountiesCarousel = function QuestHomeBountiesCarousel(props) {
let ref5, ref6, ref7, ref8, callback2, callback3, isInView;
const { bounties, orbShopProducts, obtainableOrbRewards, showOrbShopPlaceholderCarousel = false } = props;
ref5 = void 0;
ref6 = void 0;
ref7 = void 0;
ref8 = void 0;
callback2 = void 0;
callback3 = void 0;
isInView = void 0;
const styles = useStyles();
const r16 = obtainableOrbRewards > 0 && (orbShopProducts.length >= MIN_PRODUCTS_FOR_ORB_SHOP_CAROUSEL || showOrbShopPlaceholderCarousel);
const ref = useRef(null);
const [state, setState] = useState(0);
const [state2, setState2] = useState(0);
const [state3, setState3] = useState(false);
const ref2 = useRef(null);
const ref3 = useRef(false);
const ref4 = useRef({
parent: {
scrollX: 0
},
children: {},
axis: "horizontal"
});
const callback = useCallback((a0) => {
if (a0 != null) {
if (!Object.hasOwn(ref4.current.children, a0)) {
return void 0;
}
const r42 = ref4.current.children[a0];
if (r42 != null) {
const calculateVisibility2 = r42.calculateVisibility;
if (calculateVisibility2 != null) {
calculateVisibility2.call(r42);
}
}
} else {
for (const item2 of Object.values(ref4.current.children)) {
if (item2 != null) {
const calculateVisibility = item2.calculateVisibility;
if (calculateVisibility != null) {
calculateVisibility.call(item2);
}
}
}
}
}, []);
const callback8 = useCallback((a0) => {
setState(a0.nativeEvent.layout.width);
ref4.current.parent.layout = a0.nativeEvent.layout;
callback();
}, [callback]);
const memo = useMemo(() => new Array(bounties.length).fill(0).map((item, index) => index * c9859_13), [bounties.length]);
const callback7 = useCallback(() => <View style={{
width: Math.max(0, state - CARD_WIDTH - PX_16)
}} />, [state]);
ref5 = useRef(state2);
ref6 = useRef(null);
const callback6 = useCallback((a0) => {
const current2 = Math.round(a0.nativeEvent.contentOffset.x / c9859_13);
if (current2 !== ref5.current) {
ref5.current = current2;
const current3 = Date.now();
if (ref6.current == null || current3 - ref6.current >= 50) {
ref6.current = current3;
triggerHapticFeedback(HapticFeedbackTypes.IMPACT_LIGHT);
}
}
ref4.current.parent.scrollX = a0.nativeEvent.contentOffset.x;
callback();
}, [callback]);
ref7 = useRef(false);
ref8 = useRef(null);
const callback5 = useCallback(() => {
ref7.current = false;
if (ref8.current != null) {
clearTimeout(ref8.current);
ref8.current = null;
}
}, []);
const callback4 = useCallback((a0) => {
const carouselPosition = Math.round(a0.nativeEvent.contentOffset.x / c9859_13);
const current2 = ref7.current;
ref7.current = false;
if (carouselPosition !== state2) {
trackBountyCarouselScroll({
scrollingType: current2 ? BountyScrollingType.AUTO : BountyScrollingType.MANUAL,
scrollingDirection: carouselPosition > state2 ? HorizontalScrollingDirection.RIGHT : HorizontalScrollingDirection.LEFT,
carouselPosition,
questContent: QuestContent.QUEST_HOME_MOBILE_CAROUSEL
});
setState2(carouselPosition);
}
}, [state2]);
callback2 = useCallback((c27625_0) => {
if (ref8.current != null) {
clearTimeout(ref8.current);
ref8.current = null;
}
ref8.current = setTimeout(() => {
ref7.current = true;
const current2 = ref.current;
if (current2 != null) {
current2.scrollToOffset({
offset: c27625_0 * c9859_13,
animated: true
});
}
ref8.current = null;
}, 350);
}, []);
useEffect(() => () => {
if (ref8.current != null) {
clearTimeout(ref8.current);
ref8.current = null;
}
}, []);
useEffect(() => {
const handleModalClose2 = function handleModalClose(a0) {
if (a0.key === BOUNTIES_MODAL_KEY) {
let c30698_1, c30698_2;
setState3(false);
const current = ref2.current;
ref2.current = null;
if (current != null) {
let r21 = BountyStore.isBountyCompleted(current) && !ref3.current;
ref3.current = false;
const r27 = bounties.findIndex((bounty) => bounty.id === current);
c30698_1 = r27;
if (r27 !== -1) {
const r30 = bounties.findIndex((bounty, index) => index > state2 && index > c30698_1 && !BountyStore.isBountyCompleted(bounty.id));
c30698_2 = r30;
if (r21) {
r21 = r30 !== -1;
}
if (r21) {
r21 = r30 <= state2 + 3;
}
if (r21) {
runAfterInteractions(() => {
callback2(c30698_2);
});
}
}
}
}
};
Dispatcher.subscribe("MODAL_POP", handleModalClose2);
return () => {
Dispatcher.unsubscribe("MODAL_POP", handleModalClose2);
};
}, [bounties, state2, callback2]);
callback3 = useCallback((a0, a1) => {
if (shouldMigrateToAdAnalyticsInterface(AdAnalyticsInterfaceExperimentStep.STEP_2_CLICKED_INTERNAL, "quest_home_bounties")) {
captureAdUserAction({
type: AdUserActionType.CLICK_INTERNAL,
adCreativeType: AdCreativeType.BOUNTY,
adCreativeId: a0.id,
questContentCTA: QuestContentCTA.START_BOUNTY,
surfaceId: QuestContent.QUEST_HOME_MOBILE_CAROUSEL,
sourceQuestContent: QuestContent.QUEST_HOME_MOBILE_CAROUSEL,
questContentPosition: a1
});
} else {
trackAdContentClicked({
adContentId: a0.id,
adCreativeType: AdCreativeType.BOUNTY,
questContent: QuestContent.QUEST_HOME_MOBILE_CAROUSEL,
questContentCTA: QuestContentCTA.START_BOUNTY,
sourceQuestContent: QuestContent.QUEST_HOME_MOBILE_CAROUSEL,
questContentPosition: a1
});
}
ref2.current = a0.id;
ref3.current = BountyStore.isBountyCompleted(a0.id);
setState3(true);
BountiesModalActionCreators.showModal({
bountyId: a0.id,
sourceQuestContent: QuestContent.QUEST_HOME_MOBILE_CAROUSEL
});
}, []);
const isCarouselInView = useIsCarouselInView();
const containerRef = isCarouselInView.containerRef;
isInView = isCarouselInView.isInView;
const callback9 = useCallback(({ item, index }) => <BillableAdPlacementImpressionTrackerNative key={item.id} adContentId={item.id} adCreativeType={AdCreativeType.BOUNTY} questContent={QuestContent.QUEST_HOME_MOBILE_CAROUSEL} questContentPosition={index} trackGuildAndChannelMetadata={false} visibilityRef={ref4} sourceQuestContent={QuestContent.QUEST_HOME_MOBILE_CAROUSEL} overrideVisibility={!!isInView && void 0}>
{() => <BountyCard bounty={item} index={index} isActive={index === state2} isModalVisible={state3} onPress={callback3} />}
</BillableAdPlacementImpressionTrackerNative>, [state2, callback3, isInView, state3]);
const callback10 = useCallback((a0) => {
return <View {...a0} onLayout={(event) => {
const r13 = bounties[a0.index];
if (r13 != null) {
ref4.current.children[r13.id] = {
...ref4.current.children[r13.id],
layout: event.nativeEvent.layout
};
callback(r13.id);
}
a0.onLayout(event);
}} />;
}, [bounties, callback]);
return <View style={styles.container}>
<View ref={containerRef} onLayout={callback8}>
<FlashList ref={ref} horizontal data={bounties} renderItem={callback9} keyExtractor={keyExtractor} contentContainerStyle={styles.listContentContainer} snapToOffsets={memo} snapToEnd={false} decelerationRate="fast" showsHorizontalScrollIndicator={false} ItemSeparatorComponent={ItemSeparator} ListFooterComponent={callback7} onScroll={callback6} onScrollBeginDrag={callback5} onMomentumScrollEnd={callback4} scrollEventThrottle={16} extraData={useMemo(() => ({
isInView,
activeIndex: state2,
isModalVisible: state3
}), [isInView, state2, state3])} CellRendererComponent={callback10} />
</View>
{r16 ? <QuestHomeOrbShopCarousel orbShopProducts={orbShopProducts} obtainableOrbRewards={obtainableOrbRewards} showOrbShopPlaceholderCarousel={showOrbShopPlaceholderCarousel} /> : null}
</View>;
};
PX_16 = Module712.space.PX_16;
PX_162 = Module712.space.PX_16;
c9859_13 = CARD_WIDTH + PX_162;
useStyles = createStyles(() => ({
container: {
marginBottom: Module712.space.PX_48
},
listContentContainer: {
paddingLeft: PX_16
},
emptyState: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_12,
borderWidth: 1,
borderColor: Module712.colors.BORDER_MUTED,
backgroundColor: Module712.colors.BACKGROUND_SURFACE_HIGH,
borderRadius: Module712.radii.lg,
overflow: "hidden",
paddingHorizontal: Module712.space.PX_16,
paddingVertical: 14,
marginHorizontal: Module712.space.PX_16
},
emptyStateText: {
flex: 1,
gap: 2
}
}));
const r55 = Module19.memo(function QuestHomeBounties(props) {
let r67, r89;
const { verticalScrollEnabled, orbShopProducts, obtainableOrbRewards, showOrbShopPlaceholderCarousel = false } = props;
const questHomeBounties = useQuestHomeBounties().questHomeBounties;
const styles = useStyles();
const r3 = questHomeBounties.length > 0;
const [r15, r12] = useSelectedDismissibleContent(r3 ? [DismissibleContent.BOUNTIES_NUX_PROMO_SHEET] : []);
let c20897_0 = r15;
let c20897_1 = r12;
const ref9 = useRef(false);
useEffect(() => {
if (!(c20897_0 !== DismissibleContent.BOUNTIES_NUX_PROMO_SHEET || ref9.current)) {
ref9.current = true;
openBountiesNuxPromoSheet();
}
}, [r15]);
useEffect(() => {
const handleHide2 = function handleHide(a0) {
if (a0.key === PROMO_SHEET_KEY) {
c20897_1(ContentDismissActionType.USER_DISMISS);
}
};
if (c20897_0 === DismissibleContent.BOUNTIES_NUX_PROMO_SHEET) {
Dispatcher.subscribe("HIDE_ACTION_SHEET", handleHide2);
return () => {
Dispatcher.unsubscribe("HIDE_ACTION_SHEET", handleHide2);
};
}
}, [r15, r12]);
let isEmptyOrCompleted = questHomeBounties.length === 0;
const stateFromStores = useStateFromStores([BountyStore], () => BountyStore.areAllBountiesCompleted());
const r17 = (isEmptyOrCompleted ? !isEmptyOrCompleted : !stateFromStores) && obtainableOrbRewards > 0 && (orbShopProducts.length >= MIN_PRODUCTS_FOR_ORB_SHOP_CAROUSEL || showOrbShopPlaceholderCarousel);
L30: {
if (!isEmptyOrCompleted && !stateFromStores) {
if (verticalScrollEnabled) {
r67 = <View style={styles.container}>
<BountiesCtaHeader bounties={questHomeBounties} />
{r17 ? <QuestHomeOrbShopCarousel orbShopProducts={orbShopProducts} obtainableOrbRewards={obtainableOrbRewards} showOrbShopPlaceholderCarousel={showOrbShopPlaceholderCarousel} /> : null}
</View>;
break L30;
}
r67 = <QuestHomeBountiesCarousel bounties={questHomeBounties} orbShopProducts={orbShopProducts} obtainableOrbRewards={obtainableOrbRewards} showOrbShopPlaceholderCarousel={showOrbShopPlaceholderCarousel} />;
} else {
if (verticalScrollEnabled) {
if (!isEmptyOrCompleted) {
isEmptyOrCompleted = stateFromStores;
}
r89 = <BountiesCtaHeader bounties={questHomeBounties} isEmptyOrCompleted={isEmptyOrCompleted} />;
} else {
r89 = <EmptyState reason={isEmptyOrCompleted ? BountyCarouselEmptyStateReason.EMPTY : BountyCarouselEmptyStateReason.COMPLETED} />;
}
r67 = <View style={styles.container}>{r89}</View>;
}
}
return r67;
});
export default r55;