Jump to content

Implementação do SCORM com react.js


Postagens Recomendadas

Nesse arquivo implemento a leitura do SCORM com a lib pipwerks, e com o iframe renderizo o conteúdo WBT, porém me deparo com esse erro:

 Error grabbing 1.2 API-SecurityError:Failed to read a named property 'API_1484_11' from 'Window': Blocked a frame with origin "https://........." from accessing a cross-origin frame.
36:Sat Sep 07 2024 09:42:17 GMT-0300 (Horário Padrão de Brasília) - Unable to acquire SCORM API:
37:Sat Sep 07 2024 09:42:17 GMT-0300 (Horário Padrão de Brasília) - SCORM2004_objAPI=object
38:Sat Sep 07 2024 09:42:17 GMT-0300 (Horário Padrão de Brasília) - In InitializeExecuted, blnSuccess=false, strErrorMessage=Error - unable to acquire LMS API, content may not play properly and results may not be recorded. Please contact technical support.
39:Sat Sep 07 2024 09:42:17 GMT-0300 (Horário Padrão de Brasília) - ERROR - LMS Initialize Failed
40:Sat Sep 07 2024 09:42:17 GMT-0300 (Horário Padrão de Brasília) - In DisplayError, strMessage=Error - unable to acquire LMS API, content may not play properly and results may not be recorded. Please contact technical support.

 

Código:

/* eslint-disable consistent-return */

/* eslint-disable import/no-extraneous-dependencies */

/* eslint-disable import/extensions */

import { memo, useCallback, useEffect, useRef, useState } from 'react';

import { useCourseDetails } from '@context';

import {

 LessonVideoProgressBody,

 ListUserCourseResponse,

 updateLessonVideoProgress,

} from '@api';

import { useMutation, useQueryClient } from '@tanstack/react-query';

import { http } from '@services';

import pipwerks from 'pipwerks-scorm-api-wrapper';

import { Box, Icon } from '@/components';

import { PlayerEventListener } from '@/components/display/VideoPlayer/interface';

import {

 CustomPlayer,

 FullScreenButton,

 IframeContainer,

 VideoIFrame,

 WaitingScreenContainer,

 WaitingScreenDescription,

 WaitingScreenIcon,

 WaitingScreenTitle,

} from './styles';

import { SecurityOverlay } from '@/components/feedback/SecurityOverlay';

 

function VideoPlayerContent() {

 const {

  currentTimer,

  lesson,

  refetchCourseDetails,

  setCourseProgress,

  courseId,

 } = useCourseDetails();

 const iframeRef = useRef<HTMLIFrameElement>(null);

 const timerRef = useRef<number | undefined>(Number(lesson?.pauseAt));

 

 const [isFullScreenButtonVisible, setIsFullScreenButtonVisible] =

  useState(true);

 

 let timeoutId: NodeJS.Timeout;

 

 useEffect(() => {

  if (isFullScreenButtonVisible) {

   // eslint-disable-next-line react-hooks/exhaustive-deps

   timeoutId = setTimeout(() => {

    setIsFullScreenButtonVisible(false);

   }, 2000);

  }

 

  return () => timeoutId && clearTimeout(timeoutId);

 }, []);

 

 const onMouseEnter = () => {

  clearTimeout(timeoutId);

  setIsFullScreenButtonVisible(true);

 };

 

 const onMouseLeave = () => {

  if (isFullScreenButtonVisible) {

   timeoutId = setTimeout(() => {

    setIsFullScreenButtonVisible(false);

   }, 2000);

  }

 };

 

 const queryClient = useQueryClient();

 useEffect(() => {

  if (lesson?.contentType === 'WBT') {

   (async () => {

    const getCMIroute = `/course/lesson/${lesson.id}/cmi`;

    console.log('Lesson ID:', lesson?.id);

    const strObjCMI = await http.get(getCMIroute);

    const strCMI = strObjCMI.data.cmi;

    console.log('strCMI: ', strCMI);

    const api = pipwerks.SCORM.API.find(window);

    if (api) {

     console.log('SCORM API encontrada:', api);

 

     // pipwerks.SCORM.version = '2004';

     pipwerks.SCORM.init();

 

     if (strCMI) {

      const jsonCMI = JSON.parse(strCMI);

      pipwerks.SCORM.set('cmi.core.student_name', jsonCMI.studentName);

     }

 

     pipwerks.SCORM.save = async () => {

      const postCMIroute = `/course/lesson/${lesson.id}/cmi`;

      const cmi = JSON.stringify(

       pipwerks.SCORM.get('cmi.core.lesson_status')

      );

      const response = await http.post(postCMIroute, { cmi });

      if (response.data) {

       if (

        'certificateAuthenticationId' in response.data &&

        'progress' in response.data

       ) {

        const { progress, certificateAuthenticationId } = response.data;

        setCourseProgress(progress);

 

        queryClient.setQueryData<{ data: ListUserCourseResponse }>(

         ['listCourseDetails', courseId],

         (dadosAntigos: any) => {

          const updatedData = {

           ...dadosAntigos,

           data: {

            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion

            ...dadosAntigos!.data,

            certificateAuthenticationId,

           },

          };

 

          return updatedData;

         }

        );

 

        refetchCourseDetails();

       }

      }

     };

    } else {

     console.error('SCORM API não encontrada no contexto da janela.');

    }

   })();

 

   return () => {

    pipwerks.SCORM.quit();

   };

  }

  // eslint-disable-next-line react-hooks/exhaustive-deps

 }, [lesson, pipwerks]);

 

 const { mutate } = useMutation({

  mutationFn: updateLessonVideoProgress,

 });

 

 const updateVideoProgress = useCallback(

  (body: LessonVideoProgressBody) => {

   const data = {

    id: lesson?.id,

    body,

   };

 

   mutate(data);

  },

  [lesson?.id, mutate]

 );

 

 const getEventListeners = (player: PlayerEventListener) => {

  switch (player.event) {

   case 'onProgress':

    if (typeof player.eventParam === 'number') {

     timerRef.current = Number(player.eventParam?.toFixed(6));

    }

    break;

 

   case 'onStart':

    updateVideoProgress({

     smbVideosMediaId: lesson?.smbVideosMediaId,

    });

    break;

 

   case 'onPause':

   case 'onCuepoint':

    if (

     typeof player.eventParam === 'object' &&

     player.duration === player.eventParam.time

    ) {

     refetchCourseDetails();

    }

 

    updateVideoProgress({

     smbVideosMediaId: lesson?.smbVideosMediaId,

     pauseAt: Number(timerRef.current),

    });

    break;

 

   default:

    break;

  }

 };

 

 const enterFullScreen = () => {

  const iframe = iframeRef.current;

 

  if (iframe) {

   if (iframe.requestFullscreen) {

    iframe.requestFullscreen();

   }

  }

 };

 

 if (

  import.meta.env.VITE_REACT_APP_ENV === 'production' &&

  lesson?.contentType !== 'WBT' &&

  lesson?.smbVideosMediaStatus === 'EMPTY'

 ) {

  return (

   <Box>

    <WaitingScreenContainer>

     <WaitingScreenIcon name="AccessTime" size="xxl" variant="secondary" />

     <WaitingScreenTitle variant="h2">

      Aguarde o processamento da aula

     </WaitingScreenTitle>

     <WaitingScreenDescription variant="h6">

      O arquivo cadastrado está sendo processado pelo nosso sistema, em

      instantes estará disponível para visualização.

     </WaitingScreenDescription>

    </WaitingScreenContainer>

   </Box>

  );

 }

 

 if (lesson?.contentType === 'WBT') {

  return (

   <Box onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>

    {isFullScreenButtonVisible && (

     <FullScreenButton variant="contained" onClick={enterFullScreen}>

      <Icon name="ZoomOutMap" variant="white" />

     </FullScreenButton>

    )}

    <IframeContainer ref={iframeRef}>

     <VideoIFrame

      id="embeded-scorm"

      src={lesson?.file}

      title={lesson?.title}

      allow="geolocation; microphone; camera; encrypted-media; midi"

     />

     <SecurityOverlay />

    </IframeContainer>

   </Box>

  );

 }

 

 return (

  <CustomPlayer

   {...{ getEventListeners }}

   playerHash="56085afe3398157772a2bce2d2cd6606"

   resume={currentTimer ?? false}

   hasOverlay

   midiaId={`${lesson?.smbVideosMediaId}`}

   duration={lesson?.smbVideosMediaDuration}

  />

 );

}

export default memo(VideoPlayerContent)

 

O erro pode está realmente relacionado a forma de montar o componente ou pode ser falha do back? 

Editado por Yuri Ruan
Modificações
Link to comment
Compartilhe em outros sites

Crie uma conta ou entre para comentar 😀

Você precisa ser um membro para deixar um comentário.

Crie a sua conta

Participe da nossa comunidade, crie sua conta.
É bem rápido!

Criar minha conta agora

Entrar

Você já tem uma conta?
Faça o login agora.

Entrar agora
×
×
  • Create New...