h5p-standalone
h5p-standalone copied to clipboard
How to implement this library with React?
Hello,
I'm currently trying to implement this package inside a React app, but when I run I got this error: SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Below is my code:
import React, { useEffect } from "react";
import { H5P } from "h5p-standalone";
const App = () => {
useEffect(() => {
const el = document.getElementById("h5p-container");
const options = {
h5pJsonPath: "./h5p-folder",
frameJs: "./h5p-assets/frame.bundle.js",
frameCss: "./h5p-assets/styles/h5p.css",
};
const h5p = new H5P(el, options);
h5p.then(() => {
console.log('Loaded')
}).catch((e) => {
console.log(e)
})
}, []);
return (
<div id="h5p-container"></div>
);
};
export default App;
Is there anything that is wrong in my code?
Thank you for your time.
Hello @danhddao1997 , could you figure it out? It would be great if you provide feedback, as I'm in the same path as you. I tried this:
import { useCallback, useEffect, useState } from 'react'
import { Loading } from '../../../Animations/Loading'
import { useSession } from 'next-auth/react'
const H5PContainer = ({ location, course, topic }) => {
const session = useSession()
const initH5p = useCallback(
async (contentLocation) => {
const { H5P: H5PStandalone } = require('h5p-standalone')
const h5pPath = `https://cdn.thinkeyschool.com/h5p/${contentLocation}`
const options = {
id: 'THINKeyLesson',
h5pJsonPath: h5pPath,
frameJs: '/h5p/dist/frame.bundle.js',
frameCss: '/h5p/dist/styles/h5p.css',
}
let element = document.getElementById('h5p_container')
// removeAllChildNodes(element)
const h5pObject = await new H5PStandalone(element, options)
console.log(h5pObject, 'h5pObject')
// fireCompleteH5PTopic(H5P)
setIsLoaderVisible(false)
}, [location]
)
const [isLoaderVisible, setIsLoaderVisible] = useState(true)
function removeAllChildNodes(parent) {
// console.log(parent)
while (parent.firstChild) {
parent.removeChild(parent.firstChild)
}
}
useEffect(() => {
initH5p(location)
}, [location, session.data.user.id, course.slug, topic])
return (
<div className='w-full mx-auto relative'>
<div className={`${!isLoaderVisible ? 'hidden' : "flex"} absolute mx-auto my-auto left-1/2 top-1/2`}>
<Loading />
</div>
{/* // H5P Container */}
<div className="h5p-container-wrapper" id={'h5p_container'} />
</div>
)
}
export default H5PContainer
I have the same problem. @DiegoGonzalezCruz can you give me the folder structure? I wonder if the h5p-folder and h5p-assets is located in the correct location.
Hey! I ended up syncing my wordpress folder to a s3 bucket with a cron (configured with a cdn). Then, I read the cdn with my react app like this:
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Loading } from '../../../Animations/Loading'
import { completeH5PTopic } from '../../../../lib/sinapsis/gamification'
import { useSession } from 'next-auth/react' // ES6
import ToastGamification from '../../../Notificaciones/ToastGamification'
import { toast } from 'react-hot-toast'
import { useRef } from 'react'
const POINTS_PER_TOPIC_COMPLETED = 5
const H5PContainer = ({ location, course, topic }) => {
// console.log(topic, 'topic')
const H5PStandalone = useMemo(() => require('h5p-standalone').H5P, [])
const removeAllChildNodes = useCallback((parent) => {
while (parent.firstChild) {
parent.removeChild(parent.firstChild)
}
}, [])
const session = useSession()
const containerRef = useRef(null)
const fireCompleteH5PTopic = useRef(false)
const [isLoaderVisible, setIsLoaderVisible] = useState(true)
useEffect(() => {
const initH5p = async (contentLocation) => {
const h5pPath = `https://[CDNURL]/h5p/${contentLocation}`
const options = {
id: 'THINKeyLesson',
h5pJsonPath: h5pPath,
frameJs: '/h5p/dist/frame.bundle.js',
frameCss: '/h5p/dist/styles/h5p.css',
// fullScreen: true
}
removeAllChildNodes(containerRef.current)
const h5pInstance = await new H5PStandalone(containerRef.current, options)
// console.log(sss, 'fired H5PStandalone')
// fireCompleteH5PTopic()
if (!fireCompleteH5PTopic.current) {
fireCompleteH5PTopic.current = true
fireCompleteH5PTopicFn(H5P, session.data.user.id, course.slug, topic)
}
setIsLoaderVisible(false)
}
initH5p(location)
}, [
location,
session.data.user.id,
course,
topic,
H5PStandalone,
removeAllChildNodes,
])
return (
<div className=" w-full h-full ">
{/* <div
className={`${!isLoaderVisible ? 'hidden' : 'flex'
} absolute mx-auto my-auto left-1/2 top-1/2`}
>
<Loading />
</div> */}
{/* // H5P Container */}
{isLoaderVisible && (<Loading />)}
<div className=" p-5 h-full flex flex-col overflow-scroll " ref={containerRef} style={{ width: '100%' }} />
</div>
)
}
export default H5PContainer
async function fireCompleteH5PTopicFn(H5P, userId, courseSlug, topic) {
H5P.externalDispatcher.on('xAPI', async (event) => {
if (event?.data?.statement?.result?.completion) {
const res = await completeH5PTopic(event, userId, courseSlug, topic)
toast.dismiss()
if (res.status === 200) {
toast.custom(
(t) => (
<ToastGamification
isVisible={t.visible}
onDismiss={() => toast.dismiss(t.id)}
points={POINTS_PER_TOPIC_COMPLETED}
/>
),
)
}
return true
}
})
}
These are relative to my nextjs project, in the public folder. frameJs: '/h5p/dist/frame.bundle.js', frameCss: '/h5p/dist/styles/h5p.css',