Skip to content

Commit

Permalink
Merge pull request #7 from GuiLeme/new-set-state-function
Browse files Browse the repository at this point in the history
feat: Add new setCurrentState flow to live-updates logic
  • Loading branch information
TiagoJacobs authored Oct 21, 2024
2 parents b7bab85 + 003420a commit dfdaef7
Show file tree
Hide file tree
Showing 12 changed files with 250 additions and 79 deletions.
4 changes: 2 additions & 2 deletions lib/libraries.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
},
"resume": false,
"majorVersion": 0,
"minorVersion": 5,
"patchVersion": 11,
"minorVersion": 6,
"patchVersion": 1,
"fullscreen": false,
"author": "Language Training Center GmbH, Oliver Tacke",
"runnable": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ function H5pStateRendererComponent(props: H5pPresenterComponentProps) {
contentAsJson, h5pAsJson,
currentH5pStateToBeApplied,
setLatestH5pStates, idOfCurrentState,
isResetH5pComponentFlow, setH5pDomElement,
} = props;

useEffect(() => {
if (setLatestH5pStates && contentRendered) {
// Reset H5P component flow doesn't have the setCurrentState function
if (isResetH5pComponentFlow && setLatestH5pStates && contentRendered) {
setTimeout(() => setLatestH5pStates((prev) => {
const result = prev.map((state) => {
const modifiedState = { ...state };
Expand All @@ -27,8 +29,10 @@ function H5pStateRendererComponent(props: H5pPresenterComponentProps) {
});
return result;
}), 50);
} else if (!isResetH5pComponentFlow && contentRendered) {
setH5pDomElement(document.querySelectorAll('.h5p-iframe')[0] as HTMLIFrameElement);
}
}, [contentRendered, setLatestH5pStates, idOfCurrentState]);
}, [contentRendered, setLatestH5pStates, idOfCurrentState, setH5pDomElement]);

useEffect(() => {
const timeoutReference = setTimeout(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { LatestH5pStateItem } from '../live-update-player/types';

export interface H5pPresenterComponentProps {
isResetH5pComponentFlow: boolean;
contentAsJson: string;
h5pAsJson: string;
indexOfCurrentStateInList: number;
stateListLength: number;
indexOfCurrentStateInList?: number;
currentH5pStateToBeApplied: string;
setLatestH5pStates: React.Dispatch<React.SetStateAction<LatestH5pStateItem[]>>;
idOfCurrentState: string;
setH5pDomElement?: React.Dispatch<React.SetStateAction<HTMLIFrameElement>>;
setLatestH5pStates?: React.Dispatch<React.SetStateAction<LatestH5pStateItem[]>>;
idOfCurrentState?: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as React from 'react';
import { DataChannelTypes } from 'bigbluebutton-html-plugin-sdk';
import * as uuidLib from 'uuid';
import { useEffect, useState } from 'react';
import { LatestH5pStateItem } from '../live-update-player/types';
import { IterativeResetH5PComponentProps } from './types';
import H5pStateRendererComponent from '../h5p-state-renderer/component';
import { UserH5pCurrentState } from '../../../../types';
import { LiveUpdateCommonWrapper } from '../live-update-common-wrapper/component';

export function IterativeResetH5PComponent(props: IterativeResetH5PComponentProps) {
const {
contentAsJson, h5pAsJson, isFullscreen, numberOfItemsPerPage,
pluginApi, userId, userName, setFullscreenItem,
} = props;

const {
data: responseUserH5pCurrentStateList,
} = pluginApi.useDataChannel<UserH5pCurrentState>('testResult', DataChannelTypes.All_ITEMS, 'userH5pCurrentState');

const dataToRender = responseUserH5pCurrentStateList?.data?.filter(
(h5pState) => h5pState.payloadJson.userId === userId,
).map((h5pState) => (
{ entryId: h5pState.entryId, payloadJson: h5pState.payloadJson }))[0]?.payloadJson;

const [latestH5pStates, setLatestH5pStates] = useState<LatestH5pStateItem[]>([]);

useEffect(() => {
const currentH5pStateToBeApplied = dataToRender?.currentState;
if (
currentH5pStateToBeApplied && currentH5pStateToBeApplied !== ''
&& (latestH5pStates.length === 0
|| currentH5pStateToBeApplied !== latestH5pStates[latestH5pStates.length - 1].state)
) {
setLatestH5pStates((list) => {
const resultList = [...list, {
state: currentH5pStateToBeApplied, rendered: false, id: uuidLib.v4(),
}];
return resultList;
});
}
}, [responseUserH5pCurrentStateList]);

return (
<LiveUpdateCommonWrapper
isFullscreen={isFullscreen}
numberOfItemsPerPage={numberOfItemsPerPage}
userId={userId}
userName={userName}
setFullscreenItem={setFullscreenItem}
>
{latestH5pStates.filter(
(state, index) => !state.rendered
|| index === latestH5pStates.length - 1
|| !latestH5pStates[index + 1]?.rendered,
).map((state, index) => (
<H5pStateRendererComponent
key={state.id}
indexOfCurrentStateInList={index}
setLatestH5pStates={setLatestH5pStates}
currentH5pStateToBeApplied={state.state}
idOfCurrentState={state.id}
contentAsJson={contentAsJson}
isResetH5pComponentFlow
h5pAsJson={h5pAsJson}
/>
))}
</LiveUpdateCommonWrapper>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { PluginApi } from 'bigbluebutton-html-plugin-sdk';
import { UserToBeRendered } from '../../../types';

export interface IterativeResetH5PComponentProps {
userName: string;
contentAsJson: string;
pluginApi: PluginApi;
h5pAsJson: string;
userId: string;
isFullscreen: boolean;
numberOfItemsPerPage: number;
setFullscreenItem?: React.Dispatch<React.SetStateAction<UserToBeRendered>>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as React from 'react';
import { DataChannelTypes } from 'bigbluebutton-html-plugin-sdk';
import { useEffect, useState } from 'react';
import { IterativeSyncCurrentStateProps, WindowWithH5p } from './types';
import H5pStateRendererComponent from '../h5p-state-renderer/component';
import { UserH5pCurrentState } from '../../../../types';
import { LiveUpdateCommonWrapper } from '../live-update-common-wrapper/component';

export function IterativeSyncCurrentState(props: IterativeSyncCurrentStateProps) {
const {
contentAsJson, h5pAsJson, isFullscreen, numberOfItemsPerPage,
pluginApi, userId, userName, setFullscreenItem, setHasSyncCurentStateFlow,
} = props;

const [h5pDomElement, setH5pDomElement] = useState<HTMLIFrameElement>(null);
const h5pStateController = h5pDomElement?.contentWindow as WindowWithH5p;

const {
data: responseUserH5pCurrentStateList,
} = pluginApi.useDataChannel<UserH5pCurrentState>('testResult', DataChannelTypes.All_ITEMS, 'userH5pCurrentState');

const dataToRender = responseUserH5pCurrentStateList?.data?.filter(
(h5pState) => h5pState.payloadJson.userId === userId,
).map((h5pState) => (
{ entryId: h5pState.entryId, payloadJson: h5pState.payloadJson }))[0]?.payloadJson;

useEffect(() => {
const currentH5pStateToBeApplied = dataToRender?.currentState;
if (
currentH5pStateToBeApplied && currentH5pStateToBeApplied !== ''
) {
h5pStateController?.H5P?.instances[0].setCurrentState(JSON.parse(currentH5pStateToBeApplied));
}
}, [responseUserH5pCurrentStateList]);

useEffect(() => {
if (h5pDomElement
&& !(h5pDomElement?.contentWindow as WindowWithH5p)?.H5P?.instances[0].setCurrentState) {
setHasSyncCurentStateFlow(false);
}
}, [h5pDomElement]);

if (responseUserH5pCurrentStateList.loading) return null;
return (
<LiveUpdateCommonWrapper
isFullscreen={isFullscreen}
numberOfItemsPerPage={numberOfItemsPerPage}
userId={userId}
userName={userName}
setFullscreenItem={setFullscreenItem}
>
<H5pStateRendererComponent
setH5pDomElement={setH5pDomElement}
isResetH5pComponentFlow={false}
currentH5pStateToBeApplied={dataToRender?.currentState}
contentAsJson={contentAsJson}
h5pAsJson={h5pAsJson}
/>
</LiveUpdateCommonWrapper>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { PluginApi } from 'bigbluebutton-html-plugin-sdk';
import { UserToBeRendered } from '../../../types';

export interface IterativeSyncCurrentStateProps {
userName: string;
contentAsJson: string;
pluginApi: PluginApi;
h5pAsJson: string;
userId: string;
isFullscreen: boolean;
numberOfItemsPerPage: number;
setFullscreenItem?: React.Dispatch<React.SetStateAction<UserToBeRendered>>;
setHasSyncCurentStateFlow: React.Dispatch<React.SetStateAction<boolean>>;
}

export interface WindowWithH5p extends Window {
H5P: {
instances: {
setCurrentState?: (args: object) => void
}[]
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import * as Styled from './styles';
import { LiveUpdateCommonWrapperProps } from './types';

export function LiveUpdateCommonWrapper(props: LiveUpdateCommonWrapperProps) {
const {
isFullscreen, numberOfItemsPerPage, children,
userId, userName, setFullscreenItem,
} = props;
const setFullscreen = (!isFullscreen) ? () => {
if (numberOfItemsPerPage > 1) setFullscreenItem({ userId, userName });
} : null;
return (
<Styled.LiveUpdatePlayerWrapper
key={userId}
>
<Styled.UserNameTitle>
{userName}
</Styled.UserNameTitle>
<Styled.UserLiveUpdatePlayerWrapper>
<Styled.LockedDiv
numberOfItemsPerPage={numberOfItemsPerPage}
onClick={() => {
if (setFullscreen) setFullscreen();
}}
/>
{children}

</Styled.UserLiveUpdatePlayerWrapper>
</Styled.LiveUpdatePlayerWrapper>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { UserToBeRendered } from '../../types';

export interface LiveUpdateCommonWrapperProps extends React.PropsWithChildren {
userName: string;
userId: string;
isFullscreen: boolean;
numberOfItemsPerPage: number;
setFullscreenItem?: React.Dispatch<React.SetStateAction<UserToBeRendered>>;
}
Original file line number Diff line number Diff line change
@@ -1,79 +1,37 @@
import { useState } from 'react';
import * as React from 'react';
import { DataChannelTypes } from 'bigbluebutton-html-plugin-sdk';
import * as uuidLib from 'uuid';
import { useEffect, useState } from 'react';
import { LiveUpdatePlayerComponentProps, LatestH5pStateItem } from './types';
import H5pStateRendererComponent from '../h5p-state-renderer/component';
import * as Styled from './styles';
import { UserH5pCurrentState } from '../../../../types';
import { LiveUpdatePlayerComponentProps } from './types';
import { IterativeSyncCurrentState } from '../iterative-sync-current-state/component';
import { IterativeResetH5PComponent } from '../iterative-reset-h5p-component/component';

export function LiveUpdatePlayerComponent(props: LiveUpdatePlayerComponentProps) {
const {
contentAsJson, h5pAsJson, isFullscreen, numberOfItemsPerPage,
pluginApi, userId, userName, setFullscreenItem,
} = props;

const {
data: responseUserH5pCurrentStateList,
} = pluginApi.useDataChannel<UserH5pCurrentState>('testResult', DataChannelTypes.All_ITEMS, 'userH5pCurrentState');

const dataToRender = responseUserH5pCurrentStateList?.data?.filter(
(h5pState) => h5pState.payloadJson.userId === userId,
).map((h5pState) => (
{ entryId: h5pState.entryId, payloadJson: h5pState.payloadJson }))[0]?.payloadJson;

const [latestH5pStates, setLatestH5pStates] = useState<LatestH5pStateItem[]>([]);

useEffect(() => {
const currentH5pStateToBeApplied = dataToRender?.currentState;
if (
currentH5pStateToBeApplied && currentH5pStateToBeApplied !== ''
&& (latestH5pStates.length === 0
|| currentH5pStateToBeApplied !== latestH5pStates[latestH5pStates.length - 1].state)
) {
setLatestH5pStates((list) => {
const resultList = [...list, {
state: currentH5pStateToBeApplied, rendered: false, id: uuidLib.v4(),
}];
return resultList;
});
}
}, [responseUserH5pCurrentStateList]);

const setFullscreen = (!isFullscreen) ? () => {
if (numberOfItemsPerPage > 1) setFullscreenItem({ userId, userName });
} : null;
return (
<Styled.LiveUpdatePlayerWrapper
key={userId}
>
<Styled.UserNameTitle>
{userName}
</Styled.UserNameTitle>
<Styled.UserLiveUpdatePlayerWrapper>
<Styled.LockedDiv
numberOfItemsPerPage={numberOfItemsPerPage}
onClick={() => {
if (setFullscreen) setFullscreen();
}}
/>
{latestH5pStates.filter(
(state, index) => !state.rendered
|| index === latestH5pStates.length - 1
|| !latestH5pStates[index + 1]?.rendered,
).map((state, index) => (
<H5pStateRendererComponent
key={state.id}
indexOfCurrentStateInList={index}
stateListLength={latestH5pStates.length}
setLatestH5pStates={setLatestH5pStates}
currentH5pStateToBeApplied={state.state}
idOfCurrentState={state.id}
contentAsJson={contentAsJson}
h5pAsJson={h5pAsJson}
/>
))}
</Styled.UserLiveUpdatePlayerWrapper>
</Styled.LiveUpdatePlayerWrapper>
const [hasSyncCurentStateFlow, setHasSyncCurentStateFlow] = useState<boolean>(true);
return (hasSyncCurentStateFlow) ? (
<IterativeSyncCurrentState
contentAsJson={contentAsJson}
h5pAsJson={h5pAsJson}
isFullscreen={isFullscreen}
numberOfItemsPerPage={numberOfItemsPerPage}
pluginApi={pluginApi}
userId={userId}
userName={userName}
setHasSyncCurentStateFlow={setHasSyncCurentStateFlow}
setFullscreenItem={setFullscreenItem}
/>
) : (
<IterativeResetH5PComponent
contentAsJson={contentAsJson}
h5pAsJson={h5pAsJson}
isFullscreen={isFullscreen}
numberOfItemsPerPage={numberOfItemsPerPage}
pluginApi={pluginApi}
userId={userId}
userName={userName}
setFullscreenItem={setFullscreenItem}
/>
);
}
3 changes: 2 additions & 1 deletion src/components/plugin-manager/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ function PluginManager(
const indexOfH5P = longest[0].indexOf('H5P');
const jsonContentWithlinebreaks = longest[0].substring(indexOfH5P + 3);
const jsonContent = jsonContentWithlinebreaks.replace(/-(\r\n|\n|\r)/gm, '-')
.replace(/(\r\n|\n|\r)\./gm, '.').replace(/(\r\n|\n|\r)/gm, ' ');
.replace(/(?<=[\w])(\r\n|\n|\r)(?=[\w])/gm, '').replace(/(\r\n|\n|\r)\./gm, '.')
.replace(/(\r\n|\n|\r)/gm, ' ');
pluginLogger.debug(`Debug log to see what comes from the slide text (jsonContentWithlinebreaks): ${jsonContentWithlinebreaks} \n\n (JSON.parse(jsonContent)): `, JSON.parse(jsonContent));
if (isValidJSON(jsonContent)) {
setLinkThatGeneratedJsonContent(currentTxtUri);
Expand Down

0 comments on commit dfdaef7

Please sign in to comment.