@100mslive/react-native-room-kit
Version:
100ms Room Kit provides simple & easy to use UI components to build Live Streaming & Video Conferencing experiences in your apps.
275 lines • 9.31 kB
JavaScript
import * as React from 'react';
import { Text, StyleSheet, View, Keyboard, TouchableOpacity, ActivityIndicator } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { FlashList } from '@shopify/flash-list';
import { useHMSInstance, useHMSRoomColorPalette, useHMSRoomStyleSheet } from '../hooks-util';
import { popFromNavigationStack } from '../redux/actions';
import { BottomSheet } from './BottomSheet';
import { ChevronIcon, CloseIcon } from '../Icons';
import { PollAndQuizzStateLabel } from './PollAndQuizzStateLabel';
import { LeaderboardEntry } from './LeaderboardEntry';
export const QuizLeaderboardEntriesScreen = ({
currentIdx,
dismissModal,
unmountScreenWithAnimation
}) => {
var _selectedPoll$questio, _selectedPoll$questio2;
const hmsInstance = useHMSInstance();
const dispatch = useDispatch();
const selectedPoll = useSelector(state => {
const pollsData = state.polls;
if (pollsData.selectedPollId !== null) {
return pollsData.polls[pollsData.selectedPollId] || null;
}
return null;
});
const initialLeaderboardEntries = useSelector(state => {
var _state$polls$leaderbo;
return selectedPoll !== null && selectedPoll !== void 0 && selectedPoll.pollId ? (_state$polls$leaderbo = state.polls.leaderboards[selectedPoll.pollId]) === null || _state$polls$leaderbo === void 0 ? void 0 : _state$polls$leaderbo.entries : null;
});
const [leaderboardEntries, setLeaderboardEntries] = React.useState(initialLeaderboardEntries ? [...initialLeaderboardEntries] : []);
const startIndexRef = React.useRef(leaderboardEntries.length);
const {
primary_default: primaryDefaultColor
} = useHMSRoomColorPalette();
const hmsRoomStyles = useHMSRoomStyleSheet((theme, typography) => ({
regularHighText: {
color: theme.palette.on_surface_high,
fontFamily: `${typography.font_family}-Regular`
},
regularMediumText: {
color: theme.palette.on_surface_medium,
fontFamily: `${typography.font_family}-Regular`
},
semiBoldMediumText: {
color: theme.palette.on_surface_medium,
fontFamily: `${typography.font_family}-SemiBold`
},
semiBoldHighText: {
color: theme.palette.on_surface_high,
fontFamily: `${typography.font_family}-SemiBold`
},
headerText: {
color: theme.palette.on_surface_high,
fontFamily: `${typography.font_family}-SemiBold`
},
container: {
backgroundColor: theme.palette.surface_dim
},
summaryContainer: {
backgroundColor: theme.palette.surface_default
},
entriesCard: {
backgroundColor: theme.palette.surface_default
},
divider: {
backgroundColor: theme.palette.border_bright
}
}));
const handleBackPress = () => {
Keyboard.dismiss();
if (typeof unmountScreenWithAnimation === 'function') {
unmountScreenWithAnimation(() => dispatch(popFromNavigationStack()));
} else {
dispatch(popFromNavigationStack());
}
};
const handleClosePress = () => {
Keyboard.dismiss();
dismissModal();
};
const [loading, setLoading] = React.useState(false);
const loadingRef = React.useRef(false);
const mounted = React.useRef(true);
const canFetchMore = React.useRef(true);
const fetchLeaderboard = React.useCallback(async () => {
if (selectedPoll !== null && selectedPoll !== void 0 && selectedPoll.pollId && canFetchMore.current && !loadingRef.current) {
setLoading(true);
loadingRef.current = true;
const response = await hmsInstance.interactivityCenter.fetchLeaderboard(selectedPoll.pollId, 50, startIndexRef.current + 1,
// Indexing starts from 1
false);
if (mounted) {
setLoading(false);
loadingRef.current = false;
if (Array.isArray(response.entries)) {
const entries = response.entries;
setLeaderboardEntries(prev => {
const list = [...prev, ...entries];
startIndexRef.current = list.length;
return list;
});
if (entries.length <= 0) {
canFetchMore.current = false;
}
}
if (response.hasNext === false) {
canFetchMore.current = false;
}
}
}
}, [selectedPoll === null || selectedPoll === void 0 ? void 0 : selectedPoll.pollId]);
const totalPoints = (selectedPoll === null || selectedPoll === void 0 || (_selectedPoll$questio = selectedPoll.questions) === null || _selectedPoll$questio === void 0 ? void 0 : _selectedPoll$questio.reduce((acc, curr) => {
acc += curr.weight;
return acc;
}, 0)) ?? 0;
const totalQuestions = (selectedPoll === null || selectedPoll === void 0 || (_selectedPoll$questio2 = selectedPoll.questions) === null || _selectedPoll$questio2 === void 0 ? void 0 : _selectedPoll$questio2.length) ?? 0;
const _keyExtractor = React.useCallback((item, index) => {
var _item$peer;
return ((_item$peer = item.peer) === null || _item$peer === void 0 ? void 0 : _item$peer.peerId) ?? index.toString();
}, []);
const _renderItem = React.useCallback(data => {
return /*#__PURE__*/React.createElement(LeaderboardEntry, {
totalPoints: totalPoints,
totalQuestions: totalQuestions,
entry: data.item,
style: {
marginBottom: 16
}
});
}, [totalPoints, totalQuestions]);
return /*#__PURE__*/React.createElement(View, {
style: [styles.fullView, hmsRoomStyles.container]
}, /*#__PURE__*/React.createElement(View, {
style: styles.header
}, /*#__PURE__*/React.createElement(View, {
style: styles.headerControls
}, currentIdx > 0 ? /*#__PURE__*/React.createElement(TouchableOpacity, {
onPress: handleBackPress,
hitSlop: styles.closeIconHitSlop,
style: styles.backIcon
}, /*#__PURE__*/React.createElement(ChevronIcon, {
direction: "left"
})) : null, /*#__PURE__*/React.createElement(Text, {
numberOfLines: 2,
style: [styles.headerText, {
flexShrink: 1
}, hmsRoomStyles.headerText]
}, selectedPoll === null || selectedPoll === void 0 ? void 0 : selectedPoll.title), selectedPoll !== null && selectedPoll !== void 0 && selectedPoll.state ? /*#__PURE__*/React.createElement(PollAndQuizzStateLabel, {
state: selectedPoll === null || selectedPoll === void 0 ? void 0 : selectedPoll.state
}) : null), /*#__PURE__*/React.createElement(TouchableOpacity, {
onPress: handleClosePress,
hitSlop: styles.closeIconHitSlop,
style: {
marginLeft: 16
}
}, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(BottomSheet.Divider, {
style: styles.halfDivider
}), /*#__PURE__*/React.createElement(FlashList, {
data: leaderboardEntries,
ListHeaderComponent: () => /*#__PURE__*/React.createElement(View, {
style: {
paddingTop: 24,
paddingBottom: 28
}
}, /*#__PURE__*/React.createElement(Text, {
style: [styles.normalText, hmsRoomStyles.semiBoldHighText]
}, "Leaderboard"), /*#__PURE__*/React.createElement(Text, {
style: [styles.smallerText, hmsRoomStyles.regularMediumText]
}, "Based on time taken to cast the correct answer")),
ListFooterComponent: () => loading ? /*#__PURE__*/React.createElement(ActivityIndicator, {
size: "small",
color: primaryDefaultColor
}) : null,
estimatedItemSize: 56,
onEndReached: () => {
fetchLeaderboard();
}
// showsVerticalScrollIndicator={Platform.OS !== 'android'}
,
contentContainerStyle: {
paddingHorizontal: 24
}
// keyboardShouldPersistTaps="always"
// ItemSeparatorComponent={() => <View style={{ height: 16 }} />} // TODO: There is a bug related to this: https://github.com/Shopify/flash-list/issues/638
,
renderItem: _renderItem,
keyExtractor: _keyExtractor
}));
};
const styles = StyleSheet.create({
tinyText: {
fontSize: 10,
lineHeight: 16,
letterSpacing: 1.5
},
smallerText: {
fontSize: 12,
lineHeight: 16
},
smallText: {
fontSize: 14,
lineHeight: 20
},
normalText: {
fontSize: 16,
lineHeight: 24
},
marginBottom16: {
marginBottom: 16
},
iconWrapper: {
flexDirection: 'row',
alignItems: 'center',
marginLeft: 12
},
// Utilities
fullView: {
flex: 1
},
// Header
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginTop: 24,
marginHorizontal: 24
},
headerControls: {
flexDirection: 'row',
alignItems: 'center',
flexShrink: 1
},
headerText: {
fontSize: 20,
lineHeight: 24,
letterSpacing: 0.15,
marginRight: 12
},
closeIconHitSlop: {
bottom: 16,
left: 16,
right: 16,
top: 16
},
backIcon: {
marginRight: 8
},
// Divider
halfDivider: {
marginHorizontal: 24,
marginVertical: 0,
marginTop: 24,
width: undefined
},
divider: {
height: 1,
width: '100%'
},
viewAllBtn: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end',
paddingVertical: 12,
paddingHorizontal: 16
},
leaderboardEntry: {
marginBottom: 16,
marginHorizontal: 16
},
entriesCard: {
paddingTop: 12,
borderRadius: 8
}
});
//# sourceMappingURL=QuizLeaderboardEntriesScreen.js.map