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

427 lines
16 KiB
TypeScript

// Metro module 9959 (f9960).
import _slicedToArray from "../../../_bundle/_slicedToArray";
import { useMemo, useRef, useEffect, useCallback, forwardRef, useState } from "react";
import { Image as Image2, ScrollView, View } from "react-native";
import AccessibilityStore from "../../a11y/AccessibilityStore";
import EmojiStore from "../../emojis/EmojiStore";
import ChannelStore from "../../../stores/ChannelStore";
import MessageStore from "../../../stores/MessageStore";
import UserStore from "../../../stores/UserStore";
import { createStyles } from "../../../design/components/Styles/native/createStyles";
import Module712 from "../../../_bundle/Module712";
import { useStateFromStores } from "../../../_bundle/Module589";
import AvatarUtils from "../../../utils/AvatarUtils";
import Emoji from "../../emojis/native/Emoji";
import { intl, t } from "../../../intl/index.native";
import { PressableHighlight } from "../../../design/void/Pressables/native/Pressables";
import { Text } from "../../../design/components/Text/native/Text";
import { getTotalVotes } from "../PollsUtils";
import { Gesture, GestureDetector } from "../../../_bundle/Module5273";
import { reactionForId } from "../chat/formatPollMessageChatData";
import useAnalyticsLocations, { AnalyticsLocationProvider } from "../../app_analytics/useAnalyticsLocations";
import useVoteReactors from "../useVoteReactors";
import { useReactorsOnScrollNative } from "../../reactions/native/MessageReactionsContent";
import { ReactionTypes } from "../../messages/MessageReactionsTypes";
import NicknameUtils from "../../../utils/NicknameUtils";
import UserUtils from "../../../utils/UserUtils";
import { TableRow } from "../../../design/components/TableRow/native/TableRow.native";
import { Avatar, AvatarSizes } from "../../../design/void/native";
import DiscordTag from "../../user_profile/native/DiscordTag";
import showUserProfileActionSheet from "../../user_profile/native/showUserProfileActionSheet";
import ReanimatedRexport, { useSharedValue, useAnimatedStyle } from "../../reanimated/ReanimatedRexport";
import { withTiming } from "../../../design/animation/reanimated/timing/timing";
import { BottomSheetFlashList } from "../../../_bundle/noop_6676";
import useTheme from "../../../hooks/useTheme";
import { isThemeDark } from "../../../design/shared";
import Module9961 from "../../../_bundle/Module9961";
import Module9962 from "../../../_bundle/Module9962";
import AnalyticsLocation from "../../app_analytics/AnalyticsLocation";
import ActionSheetActionCreators from "../../action_sheet/native/ActionSheetActionCreators";
import { BottomSheet } from "../../../design/components/Sheet/native/BottomSheet.native";
let useStyles, Component, PollVotesHeader, __initData, VotersList, NoResults;
const PollEmoji = function PollEmoji(props) {
const { style, emoji } = props;
const styles = useStyles();
return <Emoji style={style} src={useStateFromStores([EmojiStore], () => {
if (emoji.id != null) {
let animated = emoji.animated;
if (!animated) {
let r12 = EmojiStore.getCustomEmojiById(emoji.id)?.animated;
if (r12 == null) {
r12 = false;
}
animated = r12;
}
return AvatarUtils.getEmojiURL({
id: emoji.id,
animated,
size: 16
});
}
})} name={emoji.name} textEmojiStyle={styles.emojiText} fastImageStyle={styles.emojiImage} />;
};
PollVotesHeader = function PollVotesHeader(props) {
let ref, ref2, ref3;
const { message, selectedAnswerId, setSelectedAnswerId } = props;
ref = void 0;
ref2 = void 0;
ref3 = void 0;
const styles = useStyles();
const memo2 = useMemo(() => getTotalVotes(message.reactions), [message.reactions]);
ref = useRef(null);
ref2 = useRef(null);
ref3 = useRef(false);
useEffect(() => {
setTimeout(async () => {
let c30171_0, c30171_1;
L24: {
L22: {
L16: {
let env31518;
c30171_1 = void 0;
const r9 = env31518 = {};
c30171_0 = r9;
env31518[0] = void 0;
env31518[1] = void 0;
env31518[2] = void 0;
env31518[3] = void 0;
env31518[4] = void 0;
env31518[5] = void 0;
env31518[6] = void 0;
env31518[7] = void 0;
env31518[8] = void 0;
env31518[9] = void 0;
env31518[10] = void 0;
env31518[11] = void 0;
const current = ref.current;
env31518[0] = current;
const current2 = ref2.current;
env31518[1] = current2;
if (current == null) {
break L24;
}
if (current2 != null) {
env31518[2] = await Promise.all([new Promise((c31995_0) => {
env31518[0].measure((a0, a1, a2, a3, a4) => c31995_0({
scrollWidth: a2,
scrollPageX: a4
}));
}), new Promise((c31996_0) => {
env31518[1].measure((a0, a1, a2, a3, a4) => c31996_0({
width: a2,
pageX: a4
}));
}), new Promise((c31997_0) => {
env31518[1].measureLayout(env31518[0], (a0) => c31997_0({
x: a0
}));
})]);
env31518[3] = (0, _slicedToArray)(env31518[2], 3);
env31518[4] = env31518[3][0];
env31518[5] = env31518[4].scrollWidth;
env31518[6] = env31518[4].scrollPageX;
env31518[7] = env31518[3][1];
env31518[8] = env31518[7].width;
env31518[9] = env31518[7].pageX;
env31518[10] = env31518[3][2].x;
env31518[11] = !AccessibilityStore.useReducedMotion;
if (ref3.current) {
if (env31518[9] < env31518[6]) {
const current4 = ref.current;
if (current4 == null) {
break L22;
}
current4.scrollTo({
x: env31518[10] - 16,
y: 0,
animated: env31518[11]
});
break L22;
}
if (!(env31518[9] + env31518[8] > env31518[6] + env31518[5])) {
break L22;
}
const current5 = ref.current;
if (current5 == null) {
break L22;
}
current5.scrollTo({
x: env31518[10] + env31518[8] - env31518[5] + 16,
y: 0,
animated: env31518[11]
});
break L22;
}
const current3 = ref.current;
if (current3 != null) {
current3.scrollTo({
x: env31518[10] + env31518[8] / 2 - env31518[5] / 2,
y: 0,
animated: env31518[11]
});
}
ref3.current = true;
break L16;
}
break L24;
}
return void 0;
}
return void 0;
}
}, 0);
}, [selectedAnswerId]);
const memo = useMemo(() => Gesture.Native().disallowInterruption(true), []);
return message.poll == null ? null : <View>
<Text style={styles.headerText} variant="redesign/heading-18/bold" color="mobile-text-heading-primary" accessibilityRole="header">{message.poll.question.text}</Text>
<Text style={styles.subheaderText} variant="text-md/medium" color="text-default">
{intl.format(t.XRkuof, {
count: memo2
})}
</Text>
<GestureDetector gesture={memo}>
<ScrollView ref={ref} style={styles.answerScroll} contentContainerStyle={styles.answerScrollContainer} horizontal showsHorizontalScrollIndicator={false} accessibilityRole="tablist" accessibilityLabel={intl.string(t["qbir+4"])}>
{message.poll.answers.map((a0) => {
const selected = selectedAnswerId === String(a0.answer_id);
return <Component key={a0.answer_id} ref={selected ? ref2 : void 0} answer={a0} selected={selected} reaction={reactionForId(message.reactions, String(a0.answer_id))} setSelectedAnswerId={setSelectedAnswerId} />;
})}
</ScrollView>
</GestureDetector>
</View>;
};
VotersList = function VotersList(props) {
let sharedValue;
const { channelId, messageId, reaction } = props;
sharedValue = void 0;
const styles = useStyles();
const analyticsLocations = useAnalyticsLocations().analyticsLocations;
const voteReactors = useVoteReactors({
channelId,
messageId,
reaction
});
const reactors = voteReactors.reactors;
const reactorsOnScrollNative = useReactorsOnScrollNative({
channelId,
messageId,
reactionSelected: reaction,
reactors,
reactorsHasMore: voteReactors.hasMore,
reactionType: ReactionTypes.VOTE
});
const stateFromStores = useStateFromStores([ChannelStore], () => ChannelStore.getChannel(channelId));
const callback = useCallback(({ item, index }) => {
let r21 = NicknameUtils.getNickname(stateFromStores?.guild_id, stateFromStores?.id, item);
if (r21 == null) {
r21 = UserUtils.getGlobalName(item);
}
const userTag = UserUtils.getUserTag(item);
let user = UserStore.getUser(item.id);
const guild_id = stateFromStores?.guild_id;
if (user == null) {
user = item;
}
const props = {
start: index === 0,
end: reactors.length - 1 === index,
icon: <Avatar guildId={guild_id} user={user} size={AvatarSizes.SMALL} />,
label: null,
subLabel: null,
onPress: null
};
let label = r21;
if (label == null) {
label = <DiscordTag user={item} />;
}
props.label = label;
props.subLabel = r21 != null ? userTag : null;
props.onPress = () => showUserProfileActionSheet({
userId: item.id,
localUser: item,
sourceAnalyticsLocations: analyticsLocations,
channelId,
messageId
});
return <TableRow {...props} />;
}, [stateFromStores, reactors.length, channelId, messageId, analyticsLocations]);
sharedValue = useSharedValue(reactors.length === 0 ? 0 : 1);
useEffect(() => {
if (reactors.length !== 0) {
sharedValue.set(withTiming(1, {
duration: 200
}));
} else {
sharedValue.set(0);
}
}, [sharedValue, reactors.length]);
const I = function I() {
return {
flex: 1,
opacity: sharedValue.get(),
marginBottom: 32
};
};
I.__closure = {
opacity: sharedValue
};
I.__workletHash = 8593850252158;
I.__initData = __initData;
return <ReanimatedRexport.View style={useAnimatedStyle(I)}>
<BottomSheetFlashList contentContainerStyle={styles.list} data={reactors} renderItem={callback} onScroll={reactorsOnScrollNative} />
</ReanimatedRexport.View>;
};
NoResults = function NoResults() {
const styles = useStyles();
return <View style={styles.noResultsContainer}>
<Image2 style={styles.noResultsImage} source={isThemeDark(useTheme()) ? Module9961 : Module9962} />
<Text style={styles.noResultsTitle} variant="heading-md/bold" color="mobile-text-heading-primary">
{intl.string(t.vhQK3o)}
</Text>
<Text style={styles.noResultsSubtitle} variant="text-sm/semibold" color="text-default">
{intl.string(t.bwytdh)}
</Text>
</View>;
};
useStyles = createStyles({
headerText: {
textAlign: "center",
paddingHorizontal: 16
},
subheaderText: {
textAlign: "center",
marginTop: 2,
paddingHorizontal: 16
},
answerScroll: {
marginTop: 24
},
answerScrollContainer: {
gap: 4,
paddingHorizontal: 16
},
answerName: {
marginTop: 16,
marginHorizontal: 16,
marginBottom: 8
},
list: {
paddingHorizontal: 16
},
answerButton: {
padding: 8,
flexDirection: "row",
alignItems: "center",
borderRadius: Module712.radii.xs,
maxWidth: 200
},
answerSelected: {
backgroundColor: Module712.colors.BORDER_SUBTLE
},
answerEmoji: {
marginRight: 8
},
answerText: {
flexShrink: 1
},
emojiText: {
fontSize: 16
},
emojiImage: {
height: 16,
width: 16,
flexShrink: 0
},
noResultsContainer: {
flexDirection: "column",
alignItems: "center",
paddingHorizontal: 16
},
noResultsImage: {
marginTop: 32,
width: 138
},
noResultsTitle: {
marginTop: 16,
textAlign: "center"
},
noResultsSubtitle: {
marginTop: 4,
textAlign: "center"
}
});
Component = forwardRef(function({ answer, reaction, selected, setSelectedAnswerId: setSelectedAnswerId2 }, a1) {
const styles = useStyles();
let numVotes = reaction == null ? void 0 : reaction.count_details?.vote;
if (numVotes == null) {
numVotes = 0;
}
const callback = useCallback(() => {
setSelectedAnswerId2(String(answer.answer_id));
}, [setSelectedAnswerId2, answer.answer_id]);
const color = selected ? "interactive-text-active" : "text-default";
return <PressableHighlight ref={a1} onPress={callback} style={[styles.answerButton, selected ? styles.answerSelected : void 0]} accessibilityRole="tab" accessibilityState={{
selected
}} accessibilityLabel={intl.formatToPlainString(t.wqBc7A, {
numVotes,
option: answer.poll_media.text
})}>
{answer.poll_media.emoji != null ? <PollEmoji style={styles.answerEmoji} emoji={answer.poll_media.emoji} /> : null}
{answer.poll_media.text != null ? <Text style={styles.answerText} variant="text-sm/semibold" color={color} lineClamp={1}>{answer.poll_media.text}</Text> : null}
<Text variant="text-sm/semibold" color={color} lineClamp={1}>
{" "}
(
{numVotes.toLocaleString()}
)
</Text>
</PressableHighlight>;
});
__initData = {
code: "function PollVotesActionSheetTsx1(){const{opacity}=this.__closure;return{flex:1,opacity:opacity.get(),marginBottom:32};}"
};
export default function PollVotesActionSheet(props) {
let c17586_4;
const { channelId: channelId2, messageId: messageId2, initialAnswerId } = props;
c17586_4 = void 0;
const styles = useStyles();
const analyticsLocations2 = useAnalyticsLocations(AnalyticsLocation.POLL_VOTES).analyticsLocations;
const [state, setSelectedAnswerId3] = useState(initialAnswerId);
const stateFromStores2 = useStateFromStores([MessageStore], () => MessageStore.getMessage(channelId2, messageId2));
const r2 = stateFromStores2 != null && stateFromStores2.poll != null;
c17586_4 = r2;
useEffect(() => {
if (!c17586_4) {
ActionSheetActionCreators.hideActionSheet("PollVotesActionSheet");
}
}, [r2]);
const memo = useMemo(() => {
if (stateFromStores2?.reactions != null) {
return reactionForId(stateFromStores2.reactions, state);
}
}, [stateFromStores2?.reactions, state]);
if (r2) {
const r50 = stateFromStores2 == null;
let r18 = void 0;
if (!r50) {
const poll = stateFromStores2.poll;
r18 = poll == null ? void 0 : poll.answers.find((answer) => String(answer.answer_id) === state);
}
let count = memo == null ? void 0 : memo.count_details?.vote;
if (count == null) {
count = 0;
}
return <AnalyticsLocationProvider value={analyticsLocations2}>
<BottomSheet scrollable header={<PollVotesHeader message={stateFromStores2} selectedAnswerId={state} setSelectedAnswerId={setSelectedAnswerId3} />}>
<Text style={styles.answerName} variant="text-sm/semibold" color="text-default">
{r18 == null ? void 0 : r18.poll_media.text}
{" - "}
{intl.format(t["SG/Cyy"], {
count
})}
</Text>
{memo != null && count > 0 ? <VotersList channelId={channelId2} messageId={messageId2} reaction={memo} /> : <NoResults />}
</BottomSheet>
</AnalyticsLocationProvider>;
}
return null;
};