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

366 lines
16 KiB
TypeScript

// Metro module 9791 (f9792).
import _toArray from "../../../_bundle/_toArray";
import { useCallback, useMemo, useRef, useEffect, useState } from "react";
import { Image as Image2, ScrollView, View } from "react-native";
import AccessibilityStore from "../../a11y/AccessibilityStore";
import { Orientation, VerticalGradient } from "../../../Constants";
import { createStyles } from "../../../design/components/Styles/native/createStyles";
import Module712 from "../../../_bundle/Module712";
import { CollectiblesItemType } from "../../../_bundle/Module1901";
import ProductPurchaseSuccessActionCreators from "./ProductPurchaseSuccessActionCreators";
import { HeaderBackButton } from "../../../_bundle/Module5150";
import { XSmallIcon } from "../../../design/components/Icon/native/redesign/generated/XSmallIcon";
import { intl, t } from "../../../intl/index.native";
import * as _ReanimatedRexport from "../../reanimated/ReanimatedRexport";
import ReanimatedRexport, { useSharedValue, withDelay, useAnimatedStyle } from "../../reanimated/ReanimatedRexport";
import { withSpring } from "../../../design/animation/reanimated/spring/spring";
import { withTiming } from "../../../design/animation/reanimated/timing/timing";
import { triggerHapticFeedback, HapticFeedbackTypes } from "../../haptics/HapticUtils.native";
import tinycolor from "../../../_bundle/tinycolor";
import useCollectiblesShopStyles_native from "../useCollectiblesShopStyles.native";
import { useToken } from "../../../design/tokens/native/useToken";
import Module4611 from "../../../_bundle/Module4611";
import { useCurrentUser } from "../hooks/useCurrentUser";
import { useAvatarDecorationPreviewSizes } from "./useAvatarDecorationPreviewSizes";
import { useStateFromStores } from "../../../_bundle/Module589";
import { useFetchCollectiblesProductCategory } from "../hooks/useFetchCollectiblesProductCategory";
import { useHandleUseNow } from "./useHandleUseNow";
import { useFetchVirtualCurrencyBalance } from "../../virtual_currency/hooks/useFetchVirtualCurrencyBalance";
import { lockOrientation, restoreDefaultOrientation } from "../../device/native/DeviceOrientation";
import { usePreviewCollectibleProduct } from "../hooks/usePreviewCollectiblesProduct";
import { useShopProductItems } from "../hooks/useShopProductItems";
import { SafeAreaPaddingView } from "../../../components_native/common/SafeAreaView";
import { BalanceWidgetPill } from "../../virtual_currency/native/index";
import BundleSampleV2 from "./BundleSampleV2";
import AvatarDecorationSampleV2 from "./AvatarDecorationSampleV2";
import ProfileEffectUserPreview from "../profile_effects/native/previews/ProfileEffectUserPreview";
import ProfileFrameUserPreview from "../profile_frames/native/previews/ProfileFrameUserPreview";
import { NameplatePreview } from "../nameplates/native/NameplatePreview";
import { Text } from "../../../design/components/Text/native/Text";
import { isPremiumCollectiblesProduct } from "../CollectiblesUtils";
import { Button } from "../../../design/components/Button/native/Button.native";
let useStyles, useStyles2, __initData, __initData2, __initData3, c6495_21, c6495_22, ProductPurchaseGradientBackground;
const CancelButton = function CancelButton(props) {
const { tintColor, onCancel } = props;
const styles = useStyles();
return <HeaderBackButton onPress={useCallback(() => {
if (onCancel != null) {
onCancel();
}
ProductPurchaseSuccessActionCreators.close();
}, [onCancel])} backImage={() => <XSmallIcon size="lg" style={[styles.closeButtonIcon, {
tintColor
}]} />} accessibilityLabel={intl.string(t.cpT0Cq)} labelVisible={false} />;
};
ProductPurchaseGradientBackground = function ProductPurchaseGradientBackground(props) {
const product = props.product;
const styles2 = useStyles2(product.type);
const backgroundColors = useCollectiblesShopStyles_native(product.styles).backgroundColors;
const r21 = backgroundColors?.tertiary != null;
let c17494_1 = r21;
const token = useToken(Module712.colors.BACKGROUND_BASE_LOW);
const token2 = useToken(Module712.colors.BACKGROUND_SURFACE_HIGH);
return <Module4611 style={styles2.backdrop} start={VerticalGradient.START} end={VerticalGradient.END} locations={r21 ? [0, 0.6, 0.85] : [0, 0.05, 0.6, 0.95, 1]} colors={useMemo(() => {
let r10;
if (backgroundColors == null) {
r10 = [token, token, token2, c6495_22, c6495_22];
} else {
const r5 = backgroundColors.primary.toHexString();
r10 = c17494_1 ? [r5, backgroundColors.secondary.toHexString(), backgroundColors.tertiary.toHexString()] : [r5, backgroundColors.primary.toHexString(), backgroundColors.secondary.toHexString(), c6495_22, c6495_22];
}
return r10;
}, [backgroundColors, token, token2, r21])} />;
};
useStyles = createStyles({
closeButtonIcon: {
tintColor: Module712.colors.MOBILE_TEXT_HEADING_PRIMARY
}
});
useStyles2 = createStyles(function(a0, r8 = false) {
return {
root: {
flex: 1,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW
},
header: {
flexDirection: "row",
alignItems: "center",
paddingHorizontal: Module712.space.PX_16
},
headerLeading: {
flex: 1,
flexDirection: "row",
alignItems: "center"
},
imageBackground: {
resizeMode: "cover",
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0
},
backdrop: {
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0
},
main: {
flex: 1
},
curtain: {
position: "absolute",
backgroundColor: Module712.colors.BLACK,
top: 0,
bottom: 0,
left: 0,
right: 0
},
body: {
flexGrow: 1,
flexDirection: "column",
justifyContent: "center"
},
preview: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
flex: a0 === CollectiblesItemType.AVATAR_DECORATION ? 1 : 0,
marginTop: a0 === CollectiblesItemType.AVATAR_DECORATION ? "20%" : 0,
marginHorizontal: a0 === CollectiblesItemType.NAMEPLATE ? Module712.space.PX_32 : void 0,
...r8 && a0 === CollectiblesItemType.AVATAR_DECORATION ? {
shadowColor: Module712.unsafe_rawColors.PRIMARY_630,
shadowOffset: {
width: 0,
height: 0
},
shadowOpacity: 1,
shadowRadius: 60,
elevation: 24
} : {}
},
previewBundle: {
flex: 1,
justifyContent: "flex-start",
alignItems: "center",
minHeight: 250
},
messages: {
paddingTop: Module712.space.PX_24,
minHeight: a0 === CollectiblesItemType.AVATAR_DECORATION ? "32%" : void 0,
flexDirection: "column",
alignItems: "center",
justifyContent: "flex-start",
gap: Module712.space.PX_16
},
title: {
textAlign: "center",
marginHorizontal: Module712.space.PX_32
},
footer: {
marginBottom: Module712.space.PX_16
},
cta: {
flexDirection: "row",
gap: Module712.space.PX_12,
paddingVertical: Module712.space.PX_16,
marginHorizontal: Module712.space.PX_24,
borderRadius: Module712.radii.round
}
};
});
__initData = {
code: "function ProductPurchaseSuccessModalTsx1(){const{interpolate,springInput,isProfilePreview}=this.__closure;return{opacity:interpolate(springInput.get(),[0,1],[0.1,1]),transform:[{scale:interpolate(springInput.get(),[0,1],[isProfilePreview?0.6:0,1])}]};}"
};
__initData2 = {
code: "function ProductPurchaseSuccessModalTsx2(){const{interpolate,springInput}=this.__closure;return{opacity:interpolate(springInput.get(),[0,1],[0,1]),transform:[{scale:interpolate(springInput.get(),[0,1],[0.75,1])}]};}"
};
__initData3 = {
code: "function ProductPurchaseSuccessModalTsx3(){const{interpolate,linearInput}=this.__closure;return{opacity:interpolate(linearInput.get(),[0,1],[0.5,0])};}"
};
c6495_21 = [80, 79, 78, 75, 72, 50, 45, 35, 70];
c6495_22 = tinycolor("black").toHexString();
export default function ProductPurchaseSuccessModal(props) {
const { product, useCategoryImage = false, renderMessages, onSuccess, onCancel: onCancel2 } = props;
let showOrbBalancePill = props.showOrbBalancePill;
if (showOrbBalancePill === void 0) {
showOrbBalancePill = false;
}
let orbBalancePriorToPurchase = props.orbBalancePriorToPurchase;
if (orbBalancePriorToPurchase === void 0) {
orbBalancePriorToPurchase = null;
}
let setState;
setState = void 0;
const currentUser = useCurrentUser();
const backgroundColors2 = useCollectiblesShopStyles_native(product.styles).backgroundColors;
const styles2 = useStyles2(product.type, backgroundColors2?.tertiary != null);
const token3 = useToken(Module712.colors.INTERACTIVE_TEXT_ACTIVE);
const ref = useRef(c6495_21);
const callback = useCallback(() => {
const r8 = _toArray(ref.current);
const r12 = r8[0];
const current = r8.slice(1);
if (r12 != null && current.length === 0) {
triggerHapticFeedback(HapticFeedbackTypes.IMPACT_HEAVY);
} else if (current.length >= c6495_21.length / 2) {
triggerHapticFeedback(HapticFeedbackTypes.IMPACT_LIGHT);
} else {
triggerHapticFeedback(HapticFeedbackTypes.IMPACT_MEDIUM);
}
if (r12 != null) {
setTimeout(callback, r12);
}
ref.current = current;
}, []);
useEffect(() => {
callback();
return () => {
ref.current = [];
};
}, [callback]);
const avatarDecorationPreviewSizes = useAvatarDecorationPreviewSizes();
const { avatarSize, avatarDecorationSize } = avatarDecorationPreviewSizes;
const stateFromStores2 = useStateFromStores([AccessibilityStore], () => AccessibilityStore.useReducedMotion);
const isProfilePreview = product.type === CollectiblesItemType.PROFILE_EFFECT || product.type === CollectiblesItemType.PROFILE_FRAME;
const stateFromStores = stateFromStores2;
let c17496_1 = isProfilePreview;
const sharedValue = useSharedValue(0);
const sharedValue2 = useSharedValue(0);
useEffect(() => {
sharedValue.set(stateFromStores ? 1 : withDelay(200, withSpring(1, {
duration: 500,
dampingRatio: 0.7
})));
sharedValue2.set(stateFromStores ? 1 : withDelay(200, withTiming(1, {
duration: 200
})));
}, [sharedValue, stateFromStores, sharedValue2]);
const l = () => ({
opacity: _ReanimatedRexport.interpolate(sharedValue.get(), [0, 1], [0.1, 1]),
transform: [{
scale: _ReanimatedRexport.interpolate(sharedValue.get(), [0, 1], [c17496_1 ? 0.6 : 0, 1])
}]
});
l.__closure = {
interpolate: _ReanimatedRexport.interpolate,
springInput: sharedValue,
isProfilePreview
};
l.__workletHash = 15385317790278;
l.__initData = __initData;
const animatedStyle = useAnimatedStyle(l);
const n = () => ({
opacity: _ReanimatedRexport.interpolate(sharedValue.get(), [0, 1], [0, 1]),
transform: [{
scale: _ReanimatedRexport.interpolate(sharedValue.get(), [0, 1], [0.75, 1])
}]
});
n.__closure = {
interpolate: _ReanimatedRexport.interpolate,
springInput: sharedValue
};
n.__workletHash = 4517716462039;
n.__initData = __initData2;
const animatedStyle2 = useAnimatedStyle(n);
const r124 = () => ({
opacity: _ReanimatedRexport.interpolate(sharedValue2.get(), [0, 1], [0.5, 0])
});
r124.__closure = {
interpolate: _ReanimatedRexport.interpolate,
linearInput: sharedValue2
};
r124.__workletHash = 6018737312;
r124.__initData = __initData3;
const animatedStyle3 = useAnimatedStyle(r124);
const mobileBgUrl = useFetchCollectiblesProductCategory(product.skuId).category?.mobileBgUrl;
const [item] = product.items;
const handleUseNow = useHandleUseNow({
product,
onSuccess
});
const { handleUseNow: handleUseNow2, canUseNow, isApplying, handleEditProfile } = handleUseNow;
const avatarSource = currentUser.getAvatarSource(void 0, false, avatarSize);
const balance = useFetchVirtualCurrencyBalance().balance;
useEffect(() => {
lockOrientation(Orientation.PORTRAIT);
return () => {
restoreDefaultOrientation();
};
}, []);
usePreviewCollectibleProduct(product, true);
const shopProductItems = useShopProductItems(product);
let targetSize;
[targetSize, setState] = useState();
const callback2 = useCallback((a0) => {
const layout = a0.nativeEvent.layout;
const { width, height } = layout;
setState((prevState) => prevState != null && (prevState.width === width && prevState.height === height) ? prevState : {
width,
height
});
}, []);
const r193 = [useCategoryImage && mobileBgUrl != null ? <Image2 source={{
uri: mobileBgUrl
}} style={styles2.imageBackground} /> : <ProductPurchaseGradientBackground product={product} />, , ,];
const style = [styles2.main, {
backgroundColor: useCategoryImage ? "rgba(0, 0, 0, 0.3)" : void 0
}];
if (showOrbBalancePill) {
showOrbBalancePill = <BalanceWidgetPill initialRenderedBalance={orbBalancePriorToPurchase} balance={balance} />;
}
const r211 = [<View style={styles2.headerLeading}>{showOrbBalancePill}</View>, ,];
let tintColor2 = backgroundColors2 == null ? void 0 : backgroundColors2.label.toHexString();
if (tintColor2 == null) {
tintColor2 = token3;
}
r211[1] = <CancelButton tintColor={tintColor2} onCancel={onCancel2} />;
const r220 = [<View style={styles2.header}>{r211}</View>, , ,];
const type = product.type;
const r284 = [<ReanimatedRexport.View style={[styles2.preview, animatedStyle]}>
{CollectiblesItemType.BUNDLE === type ? <View style={styles2.previewBundle} onLayout={callback2}>
{targetSize != null && <BundleSampleV2 deco={shopProductItems.firstAvatarDecoration} pfx={shopProductItems.firstProfileEffect} nameplate={shopProductItems.firstNameplate} previewAssets={product.previewAssets} disableStaticBackground size="large" targetSize={targetSize} exposureLocation="ProductPurchaseSuccessModal" />}
</View> : CollectiblesItemType.AVATAR_DECORATION === type ? <AvatarDecorationSampleV2 item={item} size={avatarDecorationSize} avatarSource={avatarSource} animate={!stateFromStores} /> : CollectiblesItemType.PROFILE_EFFECT === type ? <ProfileEffectUserPreview user={currentUser} profileEffect={product.items[0]} /> : CollectiblesItemType.PROFILE_FRAME === type ? <ProfileFrameUserPreview user={currentUser} profileFrame={product.items[0]} /> : CollectiblesItemType.NAMEPLATE === type ? <NameplatePreview user={currentUser} nameplate={product.items[0]} animate /> : null}
</ReanimatedRexport.View>, ,];
r284[1] = <ReanimatedRexport.View style={[styles2.messages, animatedStyle2]}>
{renderMessages != null ? renderMessages() : <>
{[<Text variant="heading-xl/bold" color="text-overlay-light" style={styles2.title}>
{intl.format(t.YNaxMp, {
itemName: product.name
})}
</Text>, <Text variant="text-md/medium" color="text-overlay-light" style={styles2.title}>
{isPremiumCollectiblesProduct(product) ? intl.format(t.nW6E3m, {
itemName: product.name
}) : intl.format(t["4kp0AB"], {
itemName: product.name
})}
</Text>]}
</>}
</ReanimatedRexport.View>;
r220[1] = <ScrollView style={{
flex: 1
}} contentContainerStyle={styles2.body} alwaysBounceVertical={false}>{r284}</ScrollView>;
r220[2] = <View style={styles2.footer}>
<View style={styles2.cta}>
<Button {...canUseNow ? {
loading: isApplying,
disabled: isApplying,
onPress: handleUseNow2,
text: intl.string(t.MAS7uK),
size: "lg",
grow: true
} : {
onPress: handleEditProfile,
text: intl.string(t["2p2aYz"]),
size: "lg",
grow: true
}} />
</View>
</View>;
r193[1] = <SafeAreaPaddingView style={style} top bottom left right>{r220}</SafeAreaPaddingView>;
r193[2] = <ReanimatedRexport.View style={[styles2.curtain, animatedStyle3]} pointerEvents="none" />;
return <View style={styles2.root} id={product.skuId}>{r193}</View>;
};