Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to implement this library with React? #124

Open
danhddao1997 opened this issue Sep 28, 2022 · 3 comments
Open

How to implement this library with React? #124

danhddao1997 opened this issue Sep 28, 2022 · 3 comments
Labels

Comments

@danhddao1997
Copy link

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.

@DiegoGonzalezCruz
Copy link

DiegoGonzalezCruz commented Mar 14, 2023

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

@angryBirdGuy
Copy link

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.

@DiegoGonzalezCruz
Copy link

DiegoGonzalezCruz commented Jul 7, 2023

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',

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants