@100mslive/roomkit-react 0.3.10-alpha.9 → 0.3.11-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{HLSView-UIAB54GS.js → HLSView-HJ44JWJK.js} +18 -3
- package/dist/HLSView-HJ44JWJK.js.map +7 -0
- package/dist/{HLSView-5TZVXD62.css → HLSView-IBWU4R7W.css} +16 -3
- package/dist/{HLSView-5TZVXD62.css.map → HLSView-IBWU4R7W.css.map} +3 -3
- package/dist/Prebuilt/common/constants.d.ts +0 -2
- package/dist/Prebuilt/common/hooks.d.ts +8 -1
- package/dist/Prebuilt/components/MoreSettings/CaptionContent.d.ts +5 -0
- package/dist/Prebuilt/components/MoreSettings/CaptionModal.d.ts +4 -0
- package/dist/Prebuilt/components/Polls/Voting/StandardVoting.d.ts +4 -2
- package/dist/Prebuilt/components/Polls/Voting/TimedVoting.d.ts +4 -2
- package/dist/Prebuilt/layouts/WaitingView.d.ts +6 -0
- package/dist/{chunk-GQGXO6NF.js → chunk-WDZ4KRYM.js} +2148 -1858
- package/dist/chunk-WDZ4KRYM.js.map +7 -0
- package/dist/index.cjs.css +15 -2
- package/dist/index.cjs.css.map +3 -3
- package/dist/index.cjs.js +2790 -2484
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.css +15 -2
- package/dist/index.css.map +3 -3
- package/dist/index.js +1 -1
- package/dist/meta.cjs.json +296 -118
- package/dist/meta.esbuild.json +318 -139
- package/package.json +7 -7
- package/src/Prebuilt/common/constants.ts +0 -2
- package/src/Prebuilt/common/hooks.ts +34 -1
- package/src/Prebuilt/common/utils.js +11 -11
- package/src/Prebuilt/components/AppData/AppData.tsx +2 -4
- package/src/Prebuilt/components/AppData/useUISettings.js +0 -3
- package/src/Prebuilt/components/Chat/Chat.tsx +26 -6
- package/src/Prebuilt/components/Chat/ChatFooter.tsx +18 -2
- package/src/Prebuilt/components/Chat/ChatStates.tsx +1 -1
- package/src/Prebuilt/components/Footer/ChatToggle.tsx +5 -1
- package/src/Prebuilt/components/Footer/ParticipantList.tsx +4 -2
- package/src/Prebuilt/components/Footer/PollsToggle.tsx +1 -1
- package/src/Prebuilt/components/MoreSettings/CaptionContent.tsx +132 -0
- package/src/Prebuilt/components/MoreSettings/CaptionModal.tsx +37 -0
- package/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +40 -3
- package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +19 -19
- package/src/Prebuilt/components/Polls/CreatePollQuiz/PollsQuizMenu.tsx +2 -15
- package/src/Prebuilt/components/Polls/Voting/LeaderboardSummary.tsx +71 -66
- package/src/Prebuilt/components/Polls/Voting/QuestionCard.jsx +39 -40
- package/src/Prebuilt/components/Polls/Voting/StandardVoting.tsx +12 -6
- package/src/Prebuilt/components/Polls/Voting/TimedVoting.tsx +21 -10
- package/src/Prebuilt/components/Polls/Voting/Voting.tsx +44 -2
- package/src/Prebuilt/components/VideoLayouts/EqualProminence.tsx +13 -17
- package/src/Prebuilt/components/VideoLayouts/GridLayout.tsx +17 -0
- package/src/Prebuilt/layouts/HLSView.jsx +14 -11
- package/src/Prebuilt/layouts/VideoStreamingSection.tsx +43 -9
- package/src/Prebuilt/layouts/WaitingView.tsx +52 -0
- package/dist/HLSView-UIAB54GS.js.map +0 -7
- package/dist/chunk-GQGXO6NF.js.map +0 -7
- package/src/Prebuilt/layouts/NonPublisherView.jsx +0 -51
- package/src/Prebuilt/layouts/WaitingView.jsx +0 -51
| @@ -29,7 +29,7 @@ import { | |
| 29 29 | 
             
              SettingsIcon,
         | 
| 30 30 | 
             
              VirtualBackgroundIcon,
         | 
| 31 31 | 
             
            } from '@100mslive/react-icons';
         | 
| 32 | 
            -
            import { Box, Loading, Tooltip } from '../../../..';
         | 
| 32 | 
            +
            import { Box, Loading, Text, Tooltip } from '../../../..';
         | 
| 33 33 | 
             
            import { Sheet } from '../../../../Sheet';
         | 
| 34 34 | 
             
            // @ts-ignore: No implicit any
         | 
| 35 35 | 
             
            import IconButton from '../../../IconButton';
         | 
| @@ -43,6 +43,7 @@ import SettingsModal from '../../Settings/SettingsModal'; | |
| 43 43 | 
             
            import { ToastManager } from '../../Toast/ToastManager';
         | 
| 44 44 | 
             
            // @ts-ignore: No implicit any
         | 
| 45 45 | 
             
            import { ActionTile } from '../ActionTile';
         | 
| 46 | 
            +
            import { CaptionModal } from '../CaptionModal';
         | 
| 46 47 | 
             
            // @ts-ignore: No implicit any
         | 
| 47 48 | 
             
            import { ChangeNameModal } from '../ChangeNameModal';
         | 
| 48 49 | 
             
            // @ts-ignore: No implicit any
         | 
| @@ -73,6 +74,7 @@ const MODALS = { | |
| 73 74 | 
             
              BULK_ROLE_CHANGE: 'bulkRoleChange',
         | 
| 74 75 | 
             
              MUTE_ALL: 'muteAll',
         | 
| 75 76 | 
             
              EMBED_URL: 'embedUrl',
         | 
| 77 | 
            +
              CAPTION: 'caption',
         | 
| 76 78 | 
             
            };
         | 
| 77 79 |  | 
| 78 80 | 
             
            export const MwebOptions = ({
         | 
| @@ -106,9 +108,9 @@ export const MwebOptions = ({ | |
| 106 108 | 
             
              const isLocalVideoEnabled = useHMSStore(selectIsLocalVideoEnabled);
         | 
| 107 109 | 
             
              const { startRecording, isRecordingLoading } = useRecordingHandler();
         | 
| 108 110 |  | 
| 109 | 
            -
              const  | 
| 111 | 
            +
              const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled);
         | 
| 110 112 |  | 
| 111 | 
            -
              const [isCaptionEnabled | 
| 113 | 
            +
              const [isCaptionEnabled] = useSetIsCaptionEnabled();
         | 
| 112 114 | 
             
              useDropdownList({ open: openModals.size > 0 || openOptionsSheet || openSettingsSheet, name: 'MoreSettings' });
         | 
| 113 115 |  | 
| 114 116 | 
             
              const updateState = (modalName: string, value: boolean) => {
         | 
| @@ -193,21 +195,17 @@ export const MwebOptions = ({ | |
| 193 195 | 
             
                            <ActionTile.Title>{isHandRaised ? 'Lower' : 'Raise'} Hand</ActionTile.Title>
         | 
| 194 196 | 
             
                          </ActionTile.Root>
         | 
| 195 197 | 
             
                        ) : null}
         | 
| 196 | 
            -
                         | 
| 197 | 
            -
                           | 
| 198 | 
            -
                             | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 201 | 
            -
             | 
| 202 | 
            -
             | 
| 203 | 
            -
             | 
| 204 | 
            -
                             | 
| 205 | 
            -
             | 
| 206 | 
            -
             | 
| 207 | 
            -
                            <ActionTile.Title>{isCaptionEnabled ? 'Hide Captions' : 'Captions Disabled'}</ActionTile.Title>
         | 
| 208 | 
            -
                          </ActionTile.Root>
         | 
| 209 | 
            -
                        ) : null}
         | 
| 210 | 
            -
             | 
| 198 | 
            +
                        <ActionTile.Root
         | 
| 199 | 
            +
                          onClick={() => {
         | 
| 200 | 
            +
                            setOpenOptionsSheet(false);
         | 
| 201 | 
            +
                            updateState(MODALS.CAPTION, true);
         | 
| 202 | 
            +
                          }}
         | 
| 203 | 
            +
                        >
         | 
| 204 | 
            +
                          {isTranscriptionEnabled && isCaptionEnabled ? <ClosedCaptionIcon /> : <OpenCaptionIcon />}
         | 
| 205 | 
            +
                          <Text variant="sm" css={{ ml: '$4', color: '$on_surface_high', flexGrow: '1' }}>
         | 
| 206 | 
            +
                            Closed Caption
         | 
| 207 | 
            +
                          </Text>
         | 
| 208 | 
            +
                        </ActionTile.Root>
         | 
| 211 209 | 
             
                        {isLocalVideoEnabled && !!elements?.virtual_background ? (
         | 
| 212 210 | 
             
                          <ActionTile.Root
         | 
| 213 211 | 
             
                            onClick={() => {
         | 
| @@ -323,7 +321,9 @@ export const MwebOptions = ({ | |
| 323 321 | 
             
                      openParentSheet={() => setOpenOptionsSheet(true)}
         | 
| 324 322 | 
             
                    />
         | 
| 325 323 | 
             
                  )}
         | 
| 326 | 
            -
             | 
| 324 | 
            +
                  {openModals.has(MODALS.CAPTION) && (
         | 
| 325 | 
            +
                    <CaptionModal onOpenChange={(value: boolean) => updateState(MODALS.CAPTION, value)} />
         | 
| 326 | 
            +
                  )}
         | 
| 327 327 | 
             
                  {showEmojiCard && (
         | 
| 328 328 | 
             
                    <Box
         | 
| 329 329 | 
             
                      ref={emojiCardRef}
         | 
| @@ -152,18 +152,6 @@ const AddMenu = () => { | |
| 152 152 | 
             
                        Hide Vote Count
         | 
| 153 153 | 
             
                      </Text>
         | 
| 154 154 | 
             
                    </Flex>
         | 
| 155 | 
            -
                    {/* <Flex align="center" css={{ mt: '$10' }}>
         | 
| 156 | 
            -
                      <Switch onCheckedChange={value => setAnonymous(value)} css={{ mr: '$6' }} />
         | 
| 157 | 
            -
                      <Text variant="body2" css={{ c: '$on_surface_medium' }}>
         | 
| 158 | 
            -
                        Make Results Anonymous
         | 
| 159 | 
            -
                      </Text>
         | 
| 160 | 
            -
                    </Flex> */}
         | 
| 161 | 
            -
                    {/* <Timer
         | 
| 162 | 
            -
                    timer={timer}
         | 
| 163 | 
            -
                    setTimer={setTimer}
         | 
| 164 | 
            -
                    showTimerDropDown={showTimerDropDown}
         | 
| 165 | 
            -
                    setShowTimerDropDown={setShowTimerDropDown}
         | 
| 166 | 
            -
                  /> */}
         | 
| 167 155 |  | 
| 168 156 | 
             
                    <Button
         | 
| 169 157 | 
             
                      variant="primary"
         | 
| @@ -198,8 +186,8 @@ const PrevMenu = () => { | |
| 198 186 | 
             
              const sortedPolls = useMemo(
         | 
| 199 187 | 
             
                () =>
         | 
| 200 188 | 
             
                  polls
         | 
| 201 | 
            -
                    ?.sort((a, b) => (b | 
| 202 | 
            -
                    ?.sort((a, b) => (b | 
| 189 | 
            +
                    ?.sort((a, b) => (b?.createdAt?.getTime?.() || 0) - (a?.createdAt?.getTime?.() || 0))
         | 
| 190 | 
            +
                    ?.sort((a, b) => (b?.state === 'started' ? 1 : 0) - (a?.state === 'started' ? 1 : 0)),
         | 
| 203 191 | 
             
                [polls],
         | 
| 204 192 | 
             
              );
         | 
| 205 193 | 
             
              const permissions = useHMSStore(selectPermissions);
         | 
| @@ -208,7 +196,6 @@ const PrevMenu = () => { | |
| 208 196 | 
             
                const updatePolls = async () => {
         | 
| 209 197 | 
             
                  await hmsActions.interactivityCenter.getPolls();
         | 
| 210 198 | 
             
                };
         | 
| 211 | 
            -
             | 
| 212 199 | 
             
                updatePolls();
         | 
| 213 200 | 
             
              }, [hmsActions.interactivityCenter]);
         | 
| 214 201 |  | 
| @@ -4,6 +4,8 @@ import { ChevronLeftIcon, ChevronRightIcon, CrossIcon } from '@100mslive/react-i | |
| 4 4 | 
             
            import { Box, Flex } from '../../../../Layout';
         | 
| 5 5 | 
             
            import { Loading } from '../../../../Loading';
         | 
| 6 6 | 
             
            import { Text } from '../../../../Text';
         | 
| 7 | 
            +
            // @ts-ignore
         | 
| 8 | 
            +
            import { Container } from '../../Streaming/Common';
         | 
| 7 9 | 
             
            import { LeaderboardEntry } from './LeaderboardEntry';
         | 
| 8 10 | 
             
            import { PeerParticipationSummary } from './PeerParticipationSummary';
         | 
| 9 11 | 
             
            // @ts-ignore
         | 
| @@ -32,80 +34,83 @@ export const LeaderboardSummary = ({ pollID }: { pollID: string }) => { | |
| 32 34 | 
             
              const questionCount = quiz.questions?.length || 0;
         | 
| 33 35 |  | 
| 34 36 | 
             
              return (
         | 
| 35 | 
            -
                < | 
| 36 | 
            -
                  <Flex  | 
| 37 | 
            -
                    <Flex align="center" css={{  | 
| 37 | 
            +
                <Container rounded>
         | 
| 38 | 
            +
                  <Flex direction="column" css={{ size: '100%', p: '$8' }}>
         | 
| 39 | 
            +
                    <Flex justify="between" align="center" css={{ pb: '$6', borderBottom: '1px solid $border_bright', mb: '$8' }}>
         | 
| 40 | 
            +
                      <Flex align="center" css={{ gap: '$4' }}>
         | 
| 41 | 
            +
                        <Flex
         | 
| 42 | 
            +
                          css={{ color: '$on_surface_medium', '&:hover': { color: '$on_surface_high', cursor: 'pointer' } }}
         | 
| 43 | 
            +
                          onClick={() => setPollView(POLL_VIEWS.VOTE)}
         | 
| 44 | 
            +
                        >
         | 
| 45 | 
            +
                          <ChevronLeftIcon />
         | 
| 46 | 
            +
                        </Flex>
         | 
| 47 | 
            +
                        <Text variant="lg" css={{ fontWeight: '$semiBold' }}>
         | 
| 48 | 
            +
                          {quiz.title}
         | 
| 49 | 
            +
                        </Text>
         | 
| 50 | 
            +
                        <StatusIndicator status={quiz.state} />
         | 
| 51 | 
            +
                      </Flex>
         | 
| 38 52 | 
             
                      <Flex
         | 
| 39 53 | 
             
                        css={{ color: '$on_surface_medium', '&:hover': { color: '$on_surface_high', cursor: 'pointer' } }}
         | 
| 40 | 
            -
                        onClick={ | 
| 54 | 
            +
                        onClick={toggleSidepane}
         | 
| 41 55 | 
             
                      >
         | 
| 42 | 
            -
                        < | 
| 56 | 
            +
                        <CrossIcon />
         | 
| 43 57 | 
             
                      </Flex>
         | 
| 44 | 
            -
                      <Text variant="lg" css={{ fontWeight: '$semiBold' }}>
         | 
| 45 | 
            -
                        {quiz.title}
         | 
| 46 | 
            -
                      </Text>
         | 
| 47 | 
            -
                      <StatusIndicator status={quiz.state} />
         | 
| 48 58 | 
             
                    </Flex>
         | 
| 49 | 
            -
                    < | 
| 50 | 
            -
                       | 
| 51 | 
            -
                      onClick={toggleSidepane}
         | 
| 52 | 
            -
                    >
         | 
| 53 | 
            -
                      <CrossIcon />
         | 
| 54 | 
            -
                    </Flex>
         | 
| 55 | 
            -
                  </Flex>
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                  {!viewAllEntries ? <PeerParticipationSummary quiz={quiz} /> : null}
         | 
| 59 | 
            +
                    <Box css={{ overflowY: 'auto', mr: '-$4', pr: '$4' }}>
         | 
| 60 | 
            +
                      {!viewAllEntries ? <PeerParticipationSummary quiz={quiz} /> : null}
         | 
| 58 61 |  | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
                    css={{
         | 
| 67 | 
            -
                      mt: '$8',
         | 
| 68 | 
            -
                      overflowY: 'auto',
         | 
| 69 | 
            -
                      flex: viewAllEntries ? '1 1 0' : 'unset',
         | 
| 70 | 
            -
                      mr: viewAllEntries ? '-$6' : 'unset',
         | 
| 71 | 
            -
                      px: viewAllEntries ? '0' : '$4',
         | 
| 72 | 
            -
                      pr: viewAllEntries ? '$6' : '$4',
         | 
| 73 | 
            -
                      backgroundColor: viewAllEntries ? '' : '$surface_default',
         | 
| 74 | 
            -
                      borderRadius: '$1',
         | 
| 75 | 
            -
                    }}
         | 
| 76 | 
            -
                  >
         | 
| 77 | 
            -
                    {quizLeaderboard?.entries &&
         | 
| 78 | 
            -
                      quizLeaderboard.entries
         | 
| 79 | 
            -
                        .slice(0, viewAllEntries ? undefined : 5)
         | 
| 80 | 
            -
                        .map(question => (
         | 
| 81 | 
            -
                          <LeaderboardEntry
         | 
| 82 | 
            -
                            key={question.position}
         | 
| 83 | 
            -
                            position={question.position}
         | 
| 84 | 
            -
                            score={question.score}
         | 
| 85 | 
            -
                            questionCount={questionCount}
         | 
| 86 | 
            -
                            correctResponses={question.correctResponses}
         | 
| 87 | 
            -
                            userName={question.peer.username || ''}
         | 
| 88 | 
            -
                            maxPossibleScore={maxPossibleScore}
         | 
| 89 | 
            -
                            duration={question.duration}
         | 
| 90 | 
            -
                          />
         | 
| 91 | 
            -
                        ))}
         | 
| 92 | 
            -
                    {quizLeaderboard?.entries?.length > 5 && !viewAllEntries ? (
         | 
| 93 | 
            -
                      <Flex
         | 
| 94 | 
            -
                        align="center"
         | 
| 95 | 
            -
                        justify="end"
         | 
| 62 | 
            +
                      <Text variant="sm" css={{ fontWeight: '$semiBold', mt: '$4' }}>
         | 
| 63 | 
            +
                        Leaderboard
         | 
| 64 | 
            +
                      </Text>
         | 
| 65 | 
            +
                      <Text variant="xs" css={{ color: '$on_surface_medium' }}>
         | 
| 66 | 
            +
                        Based on score and time taken to cast the correct answer
         | 
| 67 | 
            +
                      </Text>
         | 
| 68 | 
            +
                      <Box
         | 
| 96 69 | 
             
                        css={{
         | 
| 97 | 
            -
                           | 
| 98 | 
            -
                           | 
| 99 | 
            -
                           | 
| 100 | 
            -
                           | 
| 101 | 
            -
                           | 
| 70 | 
            +
                          mt: '$8',
         | 
| 71 | 
            +
                          overflowY: 'auto',
         | 
| 72 | 
            +
                          flex: viewAllEntries ? '1 1 0' : 'unset',
         | 
| 73 | 
            +
                          mr: viewAllEntries ? '-$6' : 'unset',
         | 
| 74 | 
            +
                          px: viewAllEntries ? '0' : '$4',
         | 
| 75 | 
            +
                          pr: viewAllEntries ? '$6' : '$4',
         | 
| 76 | 
            +
                          backgroundColor: viewAllEntries ? '' : '$surface_default',
         | 
| 77 | 
            +
                          borderRadius: '$1',
         | 
| 102 78 | 
             
                        }}
         | 
| 103 | 
            -
                        onClick={() => setViewAllEntries(true)}
         | 
| 104 79 | 
             
                      >
         | 
| 105 | 
            -
                         | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 80 | 
            +
                        {quizLeaderboard?.entries &&
         | 
| 81 | 
            +
                          quizLeaderboard.entries
         | 
| 82 | 
            +
                            .slice(0, viewAllEntries ? undefined : 5)
         | 
| 83 | 
            +
                            .map(question => (
         | 
| 84 | 
            +
                              <LeaderboardEntry
         | 
| 85 | 
            +
                                key={question.position}
         | 
| 86 | 
            +
                                position={question.position}
         | 
| 87 | 
            +
                                score={question.score}
         | 
| 88 | 
            +
                                questionCount={questionCount}
         | 
| 89 | 
            +
                                correctResponses={question.correctResponses}
         | 
| 90 | 
            +
                                userName={question.peer.username || ''}
         | 
| 91 | 
            +
                                maxPossibleScore={maxPossibleScore}
         | 
| 92 | 
            +
                                duration={question.duration}
         | 
| 93 | 
            +
                              />
         | 
| 94 | 
            +
                            ))}
         | 
| 95 | 
            +
                        {quizLeaderboard?.entries?.length > 5 && !viewAllEntries ? (
         | 
| 96 | 
            +
                          <Flex
         | 
| 97 | 
            +
                            align="center"
         | 
| 98 | 
            +
                            justify="end"
         | 
| 99 | 
            +
                            css={{
         | 
| 100 | 
            +
                              w: '100%',
         | 
| 101 | 
            +
                              borderTop: '1px solid $border_bright',
         | 
| 102 | 
            +
                              cursor: 'pointer',
         | 
| 103 | 
            +
                              color: '$on_surface_high',
         | 
| 104 | 
            +
                              p: '$6 $2',
         | 
| 105 | 
            +
                            }}
         | 
| 106 | 
            +
                            onClick={() => setViewAllEntries(true)}
         | 
| 107 | 
            +
                          >
         | 
| 108 | 
            +
                            <Text variant="sm">View All</Text> <ChevronRightIcon />
         | 
| 109 | 
            +
                          </Flex>
         | 
| 110 | 
            +
                        ) : null}
         | 
| 111 | 
            +
                      </Box>
         | 
| 112 | 
            +
                    </Box>
         | 
| 113 | 
            +
                  </Flex>
         | 
| 114 | 
            +
                </Container>
         | 
| 110 115 | 
             
              );
         | 
| 111 116 | 
             
            };
         | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            // @ts-check
         | 
| 2 | 
            -
            import React, { useCallback, useMemo, useRef, useState } from 'react';
         | 
| 2 | 
            +
            import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
         | 
| 3 3 | 
             
            import { match } from 'ts-pattern';
         | 
| 4 4 | 
             
            import { selectLocalPeer, selectLocalPeerRoleName, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
         | 
| 5 5 | 
             
            import { CheckCircleIcon, ChevronDownIcon, CrossCircleIcon } from '@100mslive/react-icons';
         | 
| @@ -21,15 +21,12 @@ export const QuestionCard = ({ | |
| 21 21 | 
             
              text,
         | 
| 22 22 | 
             
              options = [],
         | 
| 23 23 | 
             
              answer,
         | 
| 24 | 
            -
               | 
| 25 | 
            -
               | 
| 24 | 
            +
              localPeerResponse,
         | 
| 25 | 
            +
              updateSavedResponses,
         | 
| 26 26 | 
             
              rolesThatCanViewResponses,
         | 
| 27 27 | 
             
            }) => {
         | 
| 28 28 | 
             
              const actions = useHMSActions();
         | 
| 29 29 | 
             
              const localPeer = useHMSStore(selectLocalPeer);
         | 
| 30 | 
            -
              const localPeerResponse = responses?.find(
         | 
| 31 | 
            -
                response => response.peer?.peerid === localPeer?.id || response.peer?.userid === localPeer?.customerUserId,
         | 
| 32 | 
            -
              );
         | 
| 33 30 |  | 
| 34 31 | 
             
              const isLocalPeerCreator = localPeer?.id === startedBy;
         | 
| 35 32 | 
             
              const localPeerRoleName = useHMSStore(selectLocalPeerRoleName);
         | 
| @@ -37,20 +34,26 @@ export const QuestionCard = ({ | |
| 37 34 | 
             
                !rolesThatCanViewResponses ||
         | 
| 38 35 | 
             
                rolesThatCanViewResponses.length === 0 ||
         | 
| 39 36 | 
             
                rolesThatCanViewResponses.includes(localPeerRoleName || '');
         | 
| 37 | 
            +
              const [localPeerChoice, setLocalPeerChoice] = useState(localPeerResponse);
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              useEffect(() => {
         | 
| 40 | 
            +
                setLocalPeerChoice(localPeerResponse);
         | 
| 41 | 
            +
              }, [localPeerResponse]);
         | 
| 42 | 
            +
             | 
| 40 43 | 
             
              const showVoteCount =
         | 
| 41 | 
            -
                roleCanViewResponse && ( | 
| 44 | 
            +
                roleCanViewResponse && (localPeerChoice || (isLocalPeerCreator && pollState === 'stopped')) && !isQuiz;
         | 
| 42 45 |  | 
| 43 46 | 
             
              const isLive = pollState === 'started';
         | 
| 44 47 | 
             
              const pollEnded = pollState === 'stopped';
         | 
| 45 | 
            -
              const canRespond = isLive && ! | 
| 48 | 
            +
              const canRespond = isLive && !localPeerChoice;
         | 
| 46 49 | 
             
              const startTime = useRef(Date.now());
         | 
| 47 | 
            -
              const isCorrectAnswer = checkCorrectAnswer(answer,  | 
| 50 | 
            +
              const isCorrectAnswer = checkCorrectAnswer(answer, localPeerChoice, type);
         | 
| 48 51 |  | 
| 49 52 | 
             
              const [singleOptionAnswer, setSingleOptionAnswer] = useState();
         | 
| 50 53 | 
             
              const [multipleOptionAnswer, setMultipleOptionAnswer] = useState(new Set());
         | 
| 51 54 | 
             
              const [showOptions, setShowOptions] = useState(true);
         | 
| 52 55 |  | 
| 53 | 
            -
              const respondedToQuiz = isQuiz &&  | 
| 56 | 
            +
              const respondedToQuiz = isQuiz && localPeerChoice && !localPeerChoice.skipped;
         | 
| 54 57 |  | 
| 55 58 | 
             
              const isValidVote = useMemo(() => {
         | 
| 56 59 | 
             
                if (type === QUESTION_TYPE.SINGLE_CHOICE) {
         | 
| @@ -64,17 +67,28 @@ export const QuestionCard = ({ | |
| 64 67 | 
             
                if (!isValidVote) {
         | 
| 65 68 | 
             
                  return;
         | 
| 66 69 | 
             
                }
         | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
                   | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 70 | 
            +
                const submittedResponse = {
         | 
| 71 | 
            +
                  questionIndex: index,
         | 
| 72 | 
            +
                  option: singleOptionAnswer,
         | 
| 73 | 
            +
                  options: Array.from(multipleOptionAnswer),
         | 
| 74 | 
            +
                  duration: Date.now() - startTime.current,
         | 
| 75 | 
            +
                };
         | 
| 76 | 
            +
                await actions.interactivityCenter.addResponsesToPoll(pollID, [submittedResponse]);
         | 
| 77 | 
            +
                updateSavedResponses(prev => {
         | 
| 78 | 
            +
                  const prevCopy = { ...prev };
         | 
| 79 | 
            +
                  prevCopy[index] = { option: singleOptionAnswer, options: Array.from(multipleOptionAnswer) };
         | 
| 80 | 
            +
                  return prevCopy;
         | 
| 81 | 
            +
                });
         | 
| 76 82 | 
             
                startTime.current = Date.now();
         | 
| 77 | 
            -
              }, [ | 
| 83 | 
            +
              }, [
         | 
| 84 | 
            +
                isValidVote,
         | 
| 85 | 
            +
                index,
         | 
| 86 | 
            +
                singleOptionAnswer,
         | 
| 87 | 
            +
                multipleOptionAnswer,
         | 
| 88 | 
            +
                actions.interactivityCenter,
         | 
| 89 | 
            +
                pollID,
         | 
| 90 | 
            +
                updateSavedResponses,
         | 
| 91 | 
            +
              ]);
         | 
| 78 92 |  | 
| 79 93 | 
             
              return (
         | 
| 80 94 | 
             
                <Box
         | 
| @@ -147,7 +161,7 @@ export const QuestionCard = ({ | |
| 147 161 | 
             
                        setAnswer={setSingleOptionAnswer}
         | 
| 148 162 | 
             
                        totalResponses={result?.totalResponses}
         | 
| 149 163 | 
             
                        showVoteCount={showVoteCount}
         | 
| 150 | 
            -
                        localPeerResponse={ | 
| 164 | 
            +
                        localPeerResponse={localPeerChoice}
         | 
| 151 165 | 
             
                        isStopped={pollState === 'stopped'}
         | 
| 152 166 | 
             
                      />
         | 
| 153 167 | 
             
                    ) : null}
         | 
| @@ -163,27 +177,19 @@ export const QuestionCard = ({ | |
| 163 177 | 
             
                        setSelectedOptions={setMultipleOptionAnswer}
         | 
| 164 178 | 
             
                        totalResponses={result?.totalResponses}
         | 
| 165 179 | 
             
                        showVoteCount={showVoteCount}
         | 
| 166 | 
            -
                        localPeerResponse={ | 
| 180 | 
            +
                        localPeerResponse={localPeerChoice}
         | 
| 167 181 | 
             
                        isStopped={pollState === 'stopped'}
         | 
| 168 182 | 
             
                      />
         | 
| 169 183 | 
             
                    ) : null}
         | 
| 170 184 | 
             
                  </Box>
         | 
| 171 185 | 
             
                  {isLive && (
         | 
| 172 | 
            -
                    <QuestionActions
         | 
| 173 | 
            -
                      isValidVote={isValidVote}
         | 
| 174 | 
            -
                      onVote={handleVote}
         | 
| 175 | 
            -
                      response={localPeerResponse}
         | 
| 176 | 
            -
                      isQuiz={isQuiz}
         | 
| 177 | 
            -
                      incrementIndex={() => {
         | 
| 178 | 
            -
                        setCurrentIndex(curr => Math.min(totalQuestions, curr + 1));
         | 
| 179 | 
            -
                      }}
         | 
| 180 | 
            -
                    />
         | 
| 186 | 
            +
                    <QuestionActions isValidVote={isValidVote} onVote={handleVote} response={localPeerChoice} isQuiz={isQuiz} />
         | 
| 181 187 | 
             
                  )}
         | 
| 182 188 | 
             
                </Box>
         | 
| 183 189 | 
             
              );
         | 
| 184 190 | 
             
            };
         | 
| 185 191 |  | 
| 186 | 
            -
            const QuestionActions = ({ isValidVote, response, isQuiz, onVote | 
| 192 | 
            +
            const QuestionActions = ({ isValidVote, response, isQuiz, onVote }) => {
         | 
| 187 193 | 
             
              return (
         | 
| 188 194 | 
             
                <Flex align="center" justify="end" css={{ gap: '$4', w: '100%' }}>
         | 
| 189 195 | 
             
                  {response ? (
         | 
| @@ -193,14 +199,7 @@ const QuestionActions = ({ isValidVote, response, isQuiz, onVote, incrementIndex | |
| 193 199 | 
             
                      {!isQuiz && !response.skipped ? 'Voted' : null}
         | 
| 194 200 | 
             
                    </Text>
         | 
| 195 201 | 
             
                  ) : (
         | 
| 196 | 
            -
                    <Button
         | 
| 197 | 
            -
                      css={{ p: '$xs $10', fontWeight: '$semiBold' }}
         | 
| 198 | 
            -
                      disabled={!isValidVote}
         | 
| 199 | 
            -
                      onClick={() => {
         | 
| 200 | 
            -
                        onVote();
         | 
| 201 | 
            -
                        incrementIndex();
         | 
| 202 | 
            -
                      }}
         | 
| 203 | 
            -
                    >
         | 
| 202 | 
            +
                    <Button css={{ p: '$xs $10', fontWeight: '$semiBold' }} disabled={!isValidVote} onClick={onVote}>
         | 
| 204 203 | 
             
                      {isQuiz ? 'Answer' : 'Vote'}
         | 
| 205 204 | 
             
                    </Button>
         | 
| 206 205 | 
             
                  )}
         | 
| @@ -1,10 +1,18 @@ | |
| 1 | 
            -
            import React from 'react';
         | 
| 1 | 
            +
            import React, { Dispatch, SetStateAction } from 'react';
         | 
| 2 2 | 
             
            import { HMSPoll } from '@100mslive/react-sdk';
         | 
| 3 3 | 
             
            import { PeerParticipationSummary } from './PeerParticipationSummary';
         | 
| 4 4 | 
             
            // @ts-ignore
         | 
| 5 5 | 
             
            import { QuestionCard } from './QuestionCard';
         | 
| 6 6 |  | 
| 7 | 
            -
            export const StandardView = ({ | 
| 7 | 
            +
            export const StandardView = ({
         | 
| 8 | 
            +
              poll,
         | 
| 9 | 
            +
              localPeerResponses,
         | 
| 10 | 
            +
              updateSavedResponses,
         | 
| 11 | 
            +
            }: {
         | 
| 12 | 
            +
              poll: HMSPoll;
         | 
| 13 | 
            +
              localPeerResponses: Record<number, number | number[] | undefined>;
         | 
| 14 | 
            +
              updateSavedResponses: Dispatch<SetStateAction<Record<any, any>>>;
         | 
| 15 | 
            +
            }) => {
         | 
| 8 16 | 
             
              if (!poll?.questions) {
         | 
| 9 17 | 
             
                return null;
         | 
| 10 18 | 
             
              }
         | 
| @@ -28,11 +36,9 @@ export const StandardView = ({ poll }: { poll: HMSPoll }) => { | |
| 28 36 | 
             
                      result={question.result}
         | 
| 29 37 | 
             
                      totalQuestions={poll.questions?.length || 0}
         | 
| 30 38 | 
             
                      options={question.options}
         | 
| 31 | 
            -
                       | 
| 39 | 
            +
                      localPeerResponse={localPeerResponses?.[question.index]}
         | 
| 32 40 | 
             
                      answer={question.answer}
         | 
| 33 | 
            -
                       | 
| 34 | 
            -
                        return;
         | 
| 35 | 
            -
                      }}
         | 
| 41 | 
            +
                      updateSavedResponses={updateSavedResponses}
         | 
| 36 42 | 
             
                      rolesThatCanViewResponses={poll.rolesThatCanViewResponses}
         | 
| 37 43 | 
             
                    />
         | 
| 38 44 | 
             
                  ))}
         | 
| @@ -1,16 +1,27 @@ | |
| 1 | 
            -
            import React, { useState } from 'react';
         | 
| 2 | 
            -
            import { HMSPoll | 
| 1 | 
            +
            import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
         | 
| 2 | 
            +
            import { HMSPoll } from '@100mslive/react-sdk';
         | 
| 3 3 | 
             
            // @ts-ignore
         | 
| 4 4 | 
             
            import { QuestionCard } from './QuestionCard';
         | 
| 5 5 | 
             
            // @ts-ignore
         | 
| 6 | 
            -
            import {  | 
| 6 | 
            +
            import { getIndexToShow } from '../../../common/utils';
         | 
| 7 7 |  | 
| 8 | 
            -
            export const TimedView = ({ | 
| 9 | 
            -
               | 
| 10 | 
            -
               | 
| 11 | 
            -
               | 
| 8 | 
            +
            export const TimedView = ({
         | 
| 9 | 
            +
              poll,
         | 
| 10 | 
            +
              localPeerResponses,
         | 
| 11 | 
            +
              updateSavedResponses,
         | 
| 12 | 
            +
            }: {
         | 
| 13 | 
            +
              poll: HMSPoll;
         | 
| 14 | 
            +
              localPeerResponses?: Record<number, number | number[] | undefined>;
         | 
| 15 | 
            +
              updateSavedResponses: Dispatch<SetStateAction<Record<any, any>>>;
         | 
| 16 | 
            +
            }) => {
         | 
| 17 | 
            +
              const [currentIndex, setCurrentIndex] = useState(getIndexToShow(localPeerResponses));
         | 
| 12 18 | 
             
              const activeQuestion = poll.questions?.find(question => question.index === currentIndex);
         | 
| 13 | 
            -
              const attemptedAll = poll.questions?.length  | 
| 19 | 
            +
              const attemptedAll = (poll.questions?.length || 0) < currentIndex;
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              // Handles increments so only one question is shown at a time in quiz
         | 
| 22 | 
            +
              useEffect(() => {
         | 
| 23 | 
            +
                setCurrentIndex(getIndexToShow(localPeerResponses));
         | 
| 24 | 
            +
              }, [localPeerResponses]);
         | 
| 14 25 |  | 
| 15 26 | 
             
              if ((!activeQuestion && !attemptedAll) || !poll.questions?.length) {
         | 
| 16 27 | 
             
                return null;
         | 
| @@ -32,10 +43,10 @@ export const TimedView = ({ poll }: { poll: HMSPoll }) => { | |
| 32 43 | 
             
                        result={question?.result}
         | 
| 33 44 | 
             
                        totalQuestions={poll.questions?.length || 0}
         | 
| 34 45 | 
             
                        options={question.options}
         | 
| 35 | 
            -
                         | 
| 46 | 
            +
                        localPeerResponse={localPeerResponses?.[question.index]}
         | 
| 36 47 | 
             
                        answer={question.answer}
         | 
| 37 | 
            -
                        setCurrentIndex={setCurrentIndex}
         | 
| 38 48 | 
             
                        rolesThatCanViewResponses={poll.rolesThatCanViewResponses}
         | 
| 49 | 
            +
                        updateSavedResponses={updateSavedResponses}
         | 
| 39 50 | 
             
                      />
         | 
| 40 51 | 
             
                    ) : null;
         | 
| 41 52 | 
             
                  })}
         | 
| @@ -1,5 +1,6 @@ | |
| 1 | 
            -
            import React from 'react';
         | 
| 1 | 
            +
            import React, { useEffect, useRef, useState } from 'react';
         | 
| 2 2 | 
             
            import {
         | 
| 3 | 
            +
              selectLocalPeerID,
         | 
| 3 4 | 
             
              selectPeerNameByID,
         | 
| 4 5 | 
             
              selectPermissions,
         | 
| 5 6 | 
             
              selectPollByID,
         | 
| @@ -14,6 +15,8 @@ import { StandardView } from './StandardVoting'; | |
| 14 15 | 
             
            import { TimedView } from './TimedVoting';
         | 
| 15 16 | 
             
            // @ts-ignore
         | 
| 16 17 | 
             
            import { usePollViewState } from '../../AppData/useUISettings';
         | 
| 18 | 
            +
            // @ts-ignore
         | 
| 19 | 
            +
            import { getPeerResponses } from '../../../common/utils';
         | 
| 17 20 | 
             
            import { StatusIndicator } from '../common/StatusIndicator';
         | 
| 18 21 | 
             
            import { POLL_VIEWS } from '../../../common/constants';
         | 
| 19 22 |  | 
| @@ -26,6 +29,41 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v | |
| 26 29 | 
             
              const { setPollView } = usePollViewState();
         | 
| 27 30 | 
             
              // Sets view - linear or vertical, toggles timer indicator
         | 
| 28 31 | 
             
              const showSingleView = poll?.type === 'quiz' && poll.state === 'started';
         | 
| 32 | 
            +
              const fetchedInitialResponses = useRef(false);
         | 
| 33 | 
            +
              const [savedResponses, setSavedResponses] = useState<Record<any, any>>({});
         | 
| 34 | 
            +
              const localPeerId = useHMSStore(selectLocalPeerID);
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              // To reset whenever a different poll is opened
         | 
| 37 | 
            +
              useEffect(() => {
         | 
| 38 | 
            +
                fetchedInitialResponses.current = false;
         | 
| 39 | 
            +
                setSavedResponses({});
         | 
| 40 | 
            +
              }, [id, setSavedResponses]);
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              useEffect(() => {
         | 
| 43 | 
            +
                const getResponses = async () => {
         | 
| 44 | 
            +
                  if (poll && actions.interactivityCenter && !fetchedInitialResponses.current) {
         | 
| 45 | 
            +
                    await actions.interactivityCenter.getPollResponses(poll, true);
         | 
| 46 | 
            +
                    fetchedInitialResponses.current = true;
         | 
| 47 | 
            +
                  }
         | 
| 48 | 
            +
                };
         | 
| 49 | 
            +
                getResponses();
         | 
| 50 | 
            +
              }, [poll, actions.interactivityCenter]);
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              useEffect(() => {
         | 
| 53 | 
            +
                if (poll?.questions) {
         | 
| 54 | 
            +
                  const localPeerResponses = getPeerResponses(poll.questions, localPeerId);
         | 
| 55 | 
            +
                  // @ts-ignore
         | 
| 56 | 
            +
                  localPeerResponses?.forEach(response => {
         | 
| 57 | 
            +
                    if (response) {
         | 
| 58 | 
            +
                      setSavedResponses(prev => {
         | 
| 59 | 
            +
                        const prevCopy = { ...prev };
         | 
| 60 | 
            +
                        prevCopy[response[0]?.questionIndex] = { option: response[0]?.option, options: response[0]?.options };
         | 
| 61 | 
            +
                        return prevCopy;
         | 
| 62 | 
            +
                      });
         | 
| 63 | 
            +
                    }
         | 
| 64 | 
            +
                  });
         | 
| 65 | 
            +
                }
         | 
| 66 | 
            +
              }, [localPeerId, poll?.questions, id]);
         | 
| 29 67 |  | 
| 30 68 | 
             
              if (!poll) {
         | 
| 31 69 | 
             
                return null;
         | 
| @@ -74,7 +112,11 @@ export const Voting = ({ id, toggleVoting }: { id: string; toggleVoting: () => v | |
| 74 112 | 
             
                      </Text>
         | 
| 75 113 | 
             
                    ) : null}
         | 
| 76 114 |  | 
| 77 | 
            -
                    {showSingleView ?  | 
| 115 | 
            +
                    {showSingleView ? (
         | 
| 116 | 
            +
                      <TimedView poll={poll} localPeerResponses={savedResponses} updateSavedResponses={setSavedResponses} />
         | 
| 117 | 
            +
                    ) : (
         | 
| 118 | 
            +
                      <StandardView poll={poll} localPeerResponses={savedResponses} updateSavedResponses={setSavedResponses} />
         | 
| 119 | 
            +
                    )}
         | 
| 78 120 | 
             
                  </Flex>
         | 
| 79 121 | 
             
                  <Flex
         | 
| 80 122 | 
             
                    css={{ w: '100%', justifyContent: 'end', alignItems: 'center', p: '$8', borderTop: '1px solid $border_bright' }}
         | 
| @@ -1,8 +1,9 @@ | |
| 1 | 
            -
            import React, { useEffect,  | 
| 1 | 
            +
            import React, { useEffect, useState } from 'react';
         | 
| 2 2 | 
             
            import { useMedia } from 'react-use';
         | 
| 3 | 
            -
            import {  | 
| 3 | 
            +
            import { PeopleAddIcon } from '@100mslive/react-icons';
         | 
| 4 4 | 
             
            import { Flex } from '../../../Layout';
         | 
| 5 5 | 
             
            import { config as cssConfig } from '../../../Theme';
         | 
| 6 | 
            +
            import { WaitingView } from '../../layouts/WaitingView';
         | 
| 6 7 | 
             
            import { InsetTile } from '../InsetTile';
         | 
| 7 8 | 
             
            import { Pagination } from '../Pagination';
         | 
| 8 9 | 
             
            import { Grid } from './Grid';
         | 
| @@ -13,26 +14,14 @@ import { usePagesWithTiles, useTileLayout } from '../hooks/useTileLayout'; | |
| 13 14 | 
             
            import { UI_SETTINGS } from '../../common/constants';
         | 
| 14 15 |  | 
| 15 16 | 
             
            export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, onPageSize, edgeToEdge }: LayoutProps) {
         | 
| 16 | 
            -
              const localPeer = useHMSStore(selectLocalPeer);
         | 
| 17 17 | 
             
              const isMobile = useMedia(cssConfig.media.md);
         | 
| 18 18 | 
             
              let maxTileCount = useUISettings(UI_SETTINGS.maxTileCount);
         | 
| 19 19 | 
             
              maxTileCount = isMobile ? Math.min(maxTileCount, 6) : maxTileCount;
         | 
| 20 | 
            -
               | 
| 20 | 
            +
              const pageList = usePagesWithTiles({
         | 
| 21 21 | 
             
                peers,
         | 
| 22 22 | 
             
                maxTileCount,
         | 
| 23 23 | 
             
              });
         | 
| 24 | 
            -
             | 
| 25 | 
            -
              const inputPeers = useMemo(() => {
         | 
| 26 | 
            -
                if (pageList.length === 0) {
         | 
| 27 | 
            -
                  return localPeer ? [localPeer] : [];
         | 
| 28 | 
            -
                }
         | 
| 29 | 
            -
                return peers;
         | 
| 30 | 
            -
              }, [pageList.length, peers, localPeer]);
         | 
| 31 | 
            -
              // Pass local peer to main grid if no other peer has tiles
         | 
| 32 | 
            -
              pageList = usePagesWithTiles({
         | 
| 33 | 
            -
                peers: inputPeers,
         | 
| 34 | 
            -
                maxTileCount,
         | 
| 35 | 
            -
              });
         | 
| 24 | 
            +
             | 
| 36 25 | 
             
              const { ref, pagesWithTiles } = useTileLayout({
         | 
| 37 26 | 
             
                pageList,
         | 
| 38 27 | 
             
                maxTileCount,
         | 
| @@ -60,7 +49,14 @@ export function EqualProminence({ isInsetEnabled = false, peers, onPageChange, o | |
| 60 49 | 
             
                      numPages={pagesWithTiles.length}
         | 
| 61 50 | 
             
                    />
         | 
| 62 51 | 
             
                  )}
         | 
| 63 | 
            -
                  { | 
| 52 | 
            +
                  {pageList.length === 0 ? (
         | 
| 53 | 
            +
                    <WaitingView
         | 
| 54 | 
            +
                      title="Waiting for Host to join"
         | 
| 55 | 
            +
                      subtitle="Sit back and relax till others join"
         | 
| 56 | 
            +
                      icon={<PeopleAddIcon width="56px" height="56px" style={{ color: 'white' }} />}
         | 
| 57 | 
            +
                    />
         | 
| 58 | 
            +
                  ) : null}
         | 
| 59 | 
            +
                  {isInsetEnabled && <InsetTile />}
         | 
| 64 60 | 
             
                </Flex>
         | 
| 65 61 | 
             
              );
         | 
| 66 62 | 
             
            }
         |