From 5b84a39e9edf86fbba968cb292d9ddb1082aadfe Mon Sep 17 00:00:00 2001 From: Ajinkya Pande Date: Mon, 23 Dec 2024 13:27:08 +0530 Subject: [PATCH 1/7] Issueid #232034 fix: Sometimes it take time to load icons --- src/components/Assesment/Assesment.jsx | 37 ++++- src/components/AssesmentEnd/AssesmentEnd.jsx | 31 ++++- src/components/DiscoverEnd/DiscoverEnd.jsx | 48 +++++-- .../DiscoverSentance/DiscoverSentance.jsx | 29 +++- src/components/Hooks/useMediaCache.jsx | 82 +++++++++++ src/components/Layouts.jsx/MainLayout.jsx | 130 ++++++++++++++---- src/views/Practice/Practice.jsx | 8 +- 7 files changed, 315 insertions(+), 50 deletions(-) create mode 100644 src/components/Hooks/useMediaCache.jsx diff --git a/src/components/Assesment/Assesment.jsx b/src/components/Assesment/Assesment.jsx index 36a7598f..bb75b02f 100644 --- a/src/components/Assesment/Assesment.jsx +++ b/src/components/Assesment/Assesment.jsx @@ -49,6 +49,7 @@ import panda from "../../assets/images/panda.svg"; import cryPanda from "../../assets/images/cryPanda.svg"; import { uniqueId } from "../../services/utilService"; import { end } from "../../services/telementryService"; +import { useMediaCache } from "../Hooks/useMediaCache"; export const LanguageModal = ({ lang, setLang, setOpenLangModal }) => { const [selectedLang, setSelectedLang] = useState(lang); @@ -552,6 +553,36 @@ const Assesment = ({ discoverStart }) => { username = userDetails.student_name; setLocalData("profileName", username); } + + const { cacheMedia } = useMediaCache(); + const [mediaUrls, setMediaUrls] = useState({}); + const mediaFiles = [ + { key: "desktopLevel1", url: desktopLevel1 }, + { key: "desktopLevel2", url: desktopLevel2 }, + { key: "desktopLevel3", url: desktopLevel3 }, + { key: "desktopLevel4", url: desktopLevel4 }, + { key: "desktopLevel5", url: desktopLevel5 }, + { key: "desktopLevel6", url: desktopLevel6 }, + { key: "desktopLevel7", url: desktopLevel7 }, + { key: "desktopLevel8", url: desktopLevel8 }, + { key: "desktopLevel9", url: desktopLevel9 }, + { key: "assessmentBackground", url: assessmentBackground }, + { key: "HelpLogo", url: HelpLogo }, + ]; + + useEffect(() => { + const cacheAllMedia = async () => { + const urls = {}; + for (const media of mediaFiles) { + const cachedUrl = await cacheMedia(media.key, media.url); + urls[media.key] = cachedUrl; + } + setMediaUrls(urls); + }; + + cacheAllMedia(); + }, []); + // const [searchParams, setSearchParams] = useSearchParams(); // const [profileName, setProfileName] = useState(username); const [openMessageDialog, setOpenMessageDialog] = useState(""); @@ -714,7 +745,7 @@ const Assesment = ({ discoverStart }) => { const sectionStyle = { width: "100vw", height: "100vh", - backgroundImage: `url(${images?.[`desktopLevel${level || 1}`]})`, + backgroundImage: `url(${mediaUrls?.desktopLevel1})`, backgroundRepeat: "round", backgroundSize: "auto", position: "relative", @@ -803,7 +834,7 @@ const Assesment = ({ discoverStart }) => { { textAlign: "center", }} > - help_video_link + help_video_link )} { @@ -25,9 +25,32 @@ const AssesmentEnd = () => { const [previousLevel, setPreviousLevel] = useState(""); const [points, setPoints] = useState(0); + const [audioSrc, setAudioSrc] = useState(null); + + useEffect(() => { + const preloadAudio = async () => { + try { + const response = await fetch(LevelCompleteAudio); + const audioBlob = await response.blob(); + const audioUrl = URL.createObjectURL(audioBlob); + setAudioSrc(audioUrl); + } catch (error) { + console.error("Error loading audio:", error); + } + }; + preloadAudio(); + + return () => { + // Cleanup blob URL to prevent memory leaks + if (audioSrc) { + URL.revokeObjectURL(audioSrc); + } + }; + }, []); + useEffect(() => { (async () => { - let audio = new Audio(LevelCompleteAudio); + let audio = new Audio(audioSrc); audio.play(); const virtualId = getLocalData("virtualId"); const lang = getLocalData("lang"); @@ -40,9 +63,9 @@ const AssesmentEnd = () => { setLevel(data.data.milestone_level); setLocalData("userLevel", data.data.milestone_level?.replace("m", "")); let sessionId = getLocalData("sessionId"); - if (!sessionId){ + if (!sessionId) { sessionId = uniqueId(); - localStorage.setItem("sessionId", sessionId) + localStorage.setItem("sessionId", sessionId); } const getPointersDetails = await axios.get( `${process.env.REACT_APP_LEARNER_AI_ORCHESTRATION_HOST}/${config.URLS.GET_POINTER}/${virtualId}/${sessionId}?language=${lang}` diff --git a/src/components/DiscoverEnd/DiscoverEnd.jsx b/src/components/DiscoverEnd/DiscoverEnd.jsx index 81a96cb3..5c986d2b 100644 --- a/src/components/DiscoverEnd/DiscoverEnd.jsx +++ b/src/components/DiscoverEnd/DiscoverEnd.jsx @@ -8,12 +8,8 @@ import back from "../../assets/images/back-arrow.svg"; import discoverEndLeft from "../../assets/images/discover-end-left.svg"; import discoverEndRight from "../../assets/images/discover-end-right.svg"; import textureImage from "../../assets/images/textureImage.png"; -import { - LetsStart, - getLocalData, - setLocalData, -} from "../../utils/constants"; -import config from '../../utils/urlConstants.json'; +import { LetsStart, getLocalData, setLocalData } from "../../utils/constants"; +import config from "../../utils/urlConstants.json"; const sectionStyle = { backgroundImage: `url(${textureImage})`, @@ -32,12 +28,36 @@ const sectionStyle = { const SpeakSentenceComponent = () => { const [shake, setShake] = useState(true); const [level, setLevel] = useState(""); + const [audioSrc, setAudioSrc] = useState(null); + + useEffect(() => { + const preloadAudio = async () => { + try { + const response = await fetch(LevelCompleteAudio); + const audioBlob = await response.blob(); + const audioUrl = URL.createObjectURL(audioBlob); + setAudioSrc(audioUrl); + } catch (error) { + console.error("Error loading audio:", error); + } + }; + preloadAudio(); + + return () => { + // Cleanup blob URL to prevent memory leaks + if (audioSrc) { + URL.revokeObjectURL(audioSrc); + } + }; + }, []); useEffect(() => { - (async () => { - let audio = new Audio(LevelCompleteAudio); - audio.play(); + if (audioSrc) { + let audio = new Audio(audioSrc); + console.log(audioSrc); + audio.play(); + } const virtualId = getLocalData("virtualId"); const lang = getLocalData("lang"); const getMilestoneDetails = await axios.get( @@ -50,14 +70,14 @@ const SpeakSentenceComponent = () => { setTimeout(() => { setShake(false); }, 4000); - }, []); + }, [audioSrc]); const handleProfileBack = () => { try { - if (process.env.REACT_APP_IS_APP_IFRAME === 'true') { - navigate("/") + if (process.env.REACT_APP_IS_APP_IFRAME === "true") { + navigate("/"); } else { - navigate("/discover-start") + navigate("/discover-start"); } } catch (error) { console.error("Error posting message:", error); @@ -132,7 +152,7 @@ const SpeakSentenceComponent = () => { handleProfileBack()} + onClick={() => handleProfileBack()} sx={{ display: "flex", justifyContent: "center", diff --git a/src/components/DiscoverSentance/DiscoverSentance.jsx b/src/components/DiscoverSentance/DiscoverSentance.jsx index 9b574271..9eaae9d7 100644 --- a/src/components/DiscoverSentance/DiscoverSentance.jsx +++ b/src/components/DiscoverSentance/DiscoverSentance.jsx @@ -36,9 +36,36 @@ const SpeakSentenceComponent = () => { const [openMessageDialog, setOpenMessageDialog] = useState(""); const [totalSyllableCount, setTotalSyllableCount] = useState(""); const [isNextButtonCalled, setIsNextButtonCalled] = useState(false); + const [audioSrc, setAudioSrc] = useState(null); + + useEffect(() => { + const preloadAudio = async () => { + try { + const response = await fetch(LevelCompleteAudio); + const audioBlob = await response.blob(); + const audioUrl = URL.createObjectURL(audioBlob); + setAudioSrc(audioUrl); + } catch (error) { + console.error("Error loading audio:", error); + } + }; + preloadAudio(); + + return () => { + // Cleanup blob URL to prevent memory leaks + if (audioSrc) { + URL.revokeObjectURL(audioSrc); + } + }; + }, []); const callConfettiAndPlay = () => { - let audio = new Audio(LevelCompleteAudio); + let audio; + if (audioSrc) { + audio = new Audio(audioSrc); + } else { + audio = new Audio(LevelCompleteAudio); + } audio.play(); callConfetti(); }; diff --git a/src/components/Hooks/useMediaCache.jsx b/src/components/Hooks/useMediaCache.jsx new file mode 100644 index 00000000..0053f826 --- /dev/null +++ b/src/components/Hooks/useMediaCache.jsx @@ -0,0 +1,82 @@ +import { useEffect } from "react"; + +export function useMediaCache(dbName = "MediaCacheDB", storeName = "media") { + useEffect(() => { + // Initialize IndexedDB + const openDB = indexedDB.open(dbName, 1); + openDB.onupgradeneeded = () => { + const db = openDB.result; + if (!db.objectStoreNames.contains(storeName)) { + db.createObjectStore(storeName, { keyPath: "key" }); // Ensure keyPath matches the stored object structure + } + }; + + openDB.onerror = (e) => { + console.error("IndexedDB initialization error:", e.target.error); + }; + }, [dbName, storeName]); + + // Save media to IndexedDB + const saveMedia = async (key, blob) => { + return new Promise((resolve, reject) => { + const openDB = indexedDB.open(dbName, 1); + openDB.onsuccess = () => { + const db = openDB.result; + const tx = db.transaction(storeName, "readwrite"); + const store = tx.objectStore(storeName); + + // Put media object into the store + const putRequest = store.put({ key, blob }); + + putRequest.onsuccess = () => resolve(true); + putRequest.onerror = () => reject(putRequest.error); + tx.oncomplete = () => db.close(); // Close the connection + }; + + openDB.onerror = () => reject(openDB.error); + }); + }; + + // Fetch media from IndexedDB + const getMedia = async (key) => { + return new Promise((resolve, reject) => { + const openDB = indexedDB.open(dbName, 1); + openDB.onsuccess = () => { + const db = openDB.result; + const tx = db.transaction(storeName, "readonly"); + const store = tx.objectStore(storeName); + + // Get the media object + const getRequest = store.get(key); + + getRequest.onsuccess = () => resolve(getRequest.result?.blob || null); + getRequest.onerror = () => reject(getRequest.error); + tx.oncomplete = () => db.close(); // Close the connection + }; + + openDB.onerror = () => reject(openDB.error); + }); + }; + + // Cache media + const cacheMedia = async (key, url) => { + try { + const cachedBlob = await getMedia(key); + if (cachedBlob) { + // console.log(`Media for key "${key}" found in cache.`); + return URL.createObjectURL(cachedBlob); + } else { + console.log(`Fetching media for key "${key}" from URL.`); + const response = await fetch(url); + const blob = await response.blob(); + await saveMedia(key, blob); + return URL.createObjectURL(blob); + } + } catch (error) { + console.error(`Error caching media for key "${key}":`, error); + throw error; + } + }; + + return { cacheMedia }; +} diff --git a/src/components/Layouts.jsx/MainLayout.jsx b/src/components/Layouts.jsx/MainLayout.jsx index e875a708..2faeef8d 100644 --- a/src/components/Layouts.jsx/MainLayout.jsx +++ b/src/components/Layouts.jsx/MainLayout.jsx @@ -18,6 +18,7 @@ import textureImage from "../../assets/images/textureImage.png"; import timer from "../../assets/images/timer.svg"; import playButton from "../../assets/listen.png"; import pauseButton from "../../assets/pause.png"; +import { useMediaCache } from "../Hooks/useMediaCache"; import { GreenTick, HeartBlack, @@ -46,55 +47,88 @@ import { useEffect, useState, useRef } from "react"; import { useNavigate } from "react-router-dom"; const MainLayout = (props) => { + const [mediaUrls, setMediaUrls] = useState({}); + const { cacheMedia } = useMediaCache(); + + const mediaFiles = [ + { key: "practicebgstone", url: practicebgstone }, + { key: "practicebgstone2", url: practicebgstone2 }, + { key: "practicebgstone3", url: practicebgstone3 }, + { key: "practicebg", url: practicebg }, + { key: "practicebg2", url: practicebg2 }, + { key: "practicebg3", url: practicebg3 }, + { key: "gameWon", url: gameWon }, + { key: "gameLost", url: gameLost }, + { key: "textureImage", url: textureImage }, + { key: "timer", url: timer }, + { key: "playButton", url: playButton }, + { key: "playButton", url: playButton }, + { key: "clouds", url: clouds }, + { key: "catLoading", url: catLoading }, + ]; + + useEffect(() => { + const cacheAllMedia = async () => { + const urls = {}; + for (const media of mediaFiles) { + const cachedUrl = await cacheMedia(media.key, media.url); + urls[media.key] = cachedUrl; + } + setMediaUrls(urls); + }; + + cacheAllMedia(); + }, []); + const levelsImages = { 1: { milestone: , - backgroundAddOn: practicebgstone, + backgroundAddOn: mediaUrls.practicebgstone, background: practicebg, }, 2: { milestone: , - backgroundAddOn: practicebgstone2, + backgroundAddOn: mediaUrls.practicebgstone2, background: practicebg2, }, 3: { milestone: , - backgroundAddOn: practicebgstone3, + backgroundAddOn: mediaUrls.practicebgstone3, background: practicebg3, }, 4: { milestone: , - backgroundAddOn: practicebgstone, + backgroundAddOn: mediaUrls.practicebgstone, background: practicebg3, backgroundColor: `${levelConfig[4].color}60`, }, 5: { milestone: , - backgroundAddOn: practicebgstone3, + backgroundAddOn: mediaUrls.practicebgstone3, background: practicebg3, backgroundColor: `${levelConfig[5].color}60`, }, 6: { milestone: , - backgroundAddOn: practicebgstone3, + backgroundAddOn: mediaUrls.practicebgstone3, background: practicebg3, backgroundColor: `${levelConfig[6].color}60`, }, 7: { milestone: , - backgroundAddOn: practicebgstone3, + backgroundAddOn: mediaUrls.practicebgstone3, background: practicebg3, backgroundColor: `${levelConfig[7].color}60`, }, 8: { milestone: , - backgroundAddOn: practicebgstone3, + backgroundAddOn: mediaUrls.practicebgstone3, background: practicebg3, backgroundColor: `${levelConfig[8].color}60`, }, 9: { milestone: , - backgroundAddOn: practicebgstone3, + backgroundAddOn: mediaUrls.practicebgstone3, background: practicebg3, backgroundColor: `${levelConfig[9].color}60`, }, @@ -163,27 +197,65 @@ const MainLayout = (props) => { } }; + const [audioCache, setAudioCache] = useState({}); + + useEffect(() => { + const preloadAudio = async () => { + try { + const urls = [LevelCompleteAudio, gameLoseAudio]; + const cache = {}; + + for (const url of urls) { + const response = await fetch(url); + const audioBlob = await response.blob(); + const audioUrl = URL.createObjectURL(audioBlob); + cache[url] = audioUrl; + } + + setAudioCache(cache); + } catch (error) { + console.error("Error preloading audio:", error); + } + }; + + preloadAudio(); + + // Cleanup cached audio URLs on unmount + return () => { + Object.values(audioCache).forEach((audioUrl) => + URL.revokeObjectURL(audioUrl) + ); + }; + }, []); + useEffect(() => { if (isShowCase && gameOverData) { setShake(gameOverData ? gameOverData.userWon : true); - let audio = ""; - if (gameOverData) { - audio = new Audio( - gameOverData.userWon ? LevelCompleteAudio : gameLoseAudio - ); + const audioSrc = gameOverData + ? audioCache[gameOverData.userWon ? LevelCompleteAudio : gameLoseAudio] + : audioCache[LevelCompleteAudio]; + + if (audioSrc) { + const audio = new Audio(audioSrc); + audio.play().catch((error) => { + console.error("Error playing audio:", error); + }); + if (!gameOverData?.userWon) { callConfettiSnow(); } - } else { - audio = new Audio(LevelCompleteAudio); } - audio.play(); - setTimeout(() => { + + const shakeTimeout = setTimeout(() => { setShake(false); }, 4000); + + return () => { + clearTimeout(shakeTimeout); + }; } - }, [startShowCase, isShowCase, gameOverData]); + }, [startShowCase, isShowCase, gameOverData, audioCache]); let currentPracticeStep = progressData?.currentPracticeStep; let currentPracticeProgress = progressData?.currentPracticeProgress || 0; @@ -284,7 +356,7 @@ const MainLayout = (props) => { flexDirection: "column", justifyContent: "center", alignItems: "center", - backgroundImage: `url(${cardBackground || textureImage})`, + backgroundImage: `url(${cardBackground || mediaUrls.textureImage})`, backgroundSize: "contain", backgroundRepeat: "round", boxShadow: "0px 4px 20px -1px rgba(0, 0, 0, 0.00)", @@ -294,7 +366,7 @@ const MainLayout = (props) => { > catLoading @@ -313,7 +385,9 @@ const MainLayout = (props) => { display: "flex", flexDirection: "column", justifyContent: "space-between", - backgroundImage: `url(${cardBackground || textureImage})`, + backgroundImage: `url(${ + cardBackground || mediaUrls?.textureImage + })`, backgroundRepeat: "no-repeat", backgroundSize: "cover", boxShadow: "0px 4px 20px -1px rgba(0, 0, 0, 0.00)", @@ -331,7 +405,7 @@ const MainLayout = (props) => { {showTimer && ( timer @@ -663,7 +737,9 @@ const MainLayout = (props) => { display: "flex", flexDirection: "column", justifyContent: "space-between", - backgroundImage: `url(${cardBackground || textureImage})`, + backgroundImage: `url(${ + cardBackground || mediaUrls.textureImage + })`, backgroundSize: "contain", backgroundRepeat: "round", boxShadow: "0px 4px 20px -1px rgba(0, 0, 0, 0.00)", @@ -723,7 +799,7 @@ const MainLayout = (props) => { > {!gameOverData?.userWon && ( clouds @@ -739,7 +815,7 @@ const MainLayout = (props) => { > {gameOverData?.userWon ? ( gameWon @@ -752,7 +828,7 @@ const MainLayout = (props) => { > gameLost diff --git a/src/views/Practice/Practice.jsx b/src/views/Practice/Practice.jsx index 206d8107..6de6c92d 100644 --- a/src/views/Practice/Practice.jsx +++ b/src/views/Practice/Practice.jsx @@ -14,7 +14,6 @@ import { import axios from "axios"; import WordsOrImage from "../../components/Mechanism/WordsOrImage"; import { uniqueId } from "../../services/utilService"; -import useSound from "use-sound"; import LevelCompleteAudio from "../../assets/audio/levelComplete.wav"; import { splitGraphemes } from "split-graphemes"; import { Typography } from "@mui/material"; @@ -84,6 +83,13 @@ const Practice = () => { } }; preloadAudio(); + + return () => { + // Cleanup blob URL to prevent memory leaks + if (audioSrc) { + URL.revokeObjectURL(audioSrc); + } + }; }, []); const callConfettiAndPlay = () => { From b92f545832fae1a55e7c76087c0f816441b02a67 Mon Sep 17 00:00:00 2001 From: Ajinkya Pande Date: Mon, 23 Dec 2024 15:05:20 +0530 Subject: [PATCH 2/7] Issueid #232034 fix: Sometimes it take time to load icons --- src/views/Practice/Practice.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/Practice/Practice.jsx b/src/views/Practice/Practice.jsx index 6de6c92d..c81f162e 100644 --- a/src/views/Practice/Practice.jsx +++ b/src/views/Practice/Practice.jsx @@ -98,7 +98,6 @@ const Practice = () => { const audio = new Audio(audioSrc); audio.play(); } else { - // Fallback to LevelCompleteAudio if preloaded audio is not available const fallbackAudio = new Audio(LevelCompleteAudio); fallbackAudio.play(); } From 554a0724f6d716361d0c320c444aefc42ad63982 Mon Sep 17 00:00:00 2001 From: Ajinkya Pande Date: Mon, 23 Dec 2024 23:48:49 +0530 Subject: [PATCH 3/7] Issueid #232034 fix: Sometimes it take time to load icons --- src/components/Hooks/useMediaCache.jsx | 101 +++++++++++++------------ 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/src/components/Hooks/useMediaCache.jsx b/src/components/Hooks/useMediaCache.jsx index 0053f826..d8655f5d 100644 --- a/src/components/Hooks/useMediaCache.jsx +++ b/src/components/Hooks/useMediaCache.jsx @@ -2,81 +2,88 @@ import { useEffect } from "react"; export function useMediaCache(dbName = "MediaCacheDB", storeName = "media") { useEffect(() => { - // Initialize IndexedDB + initializeDB(dbName, storeName); + }, [dbName, storeName]); + + const initializeDB = (dbName, storeName) => { const openDB = indexedDB.open(dbName, 1); + openDB.onupgradeneeded = () => { const db = openDB.result; if (!db.objectStoreNames.contains(storeName)) { - db.createObjectStore(storeName, { keyPath: "key" }); // Ensure keyPath matches the stored object structure + db.createObjectStore(storeName, { keyPath: "key" }); } }; openDB.onerror = (e) => { console.error("IndexedDB initialization error:", e.target.error); }; - }, [dbName, storeName]); + }; - // Save media to IndexedDB const saveMedia = async (key, blob) => { - return new Promise((resolve, reject) => { - const openDB = indexedDB.open(dbName, 1); - openDB.onsuccess = () => { - const db = openDB.result; - const tx = db.transaction(storeName, "readwrite"); - const store = tx.objectStore(storeName); - - // Put media object into the store - const putRequest = store.put({ key, blob }); - - putRequest.onsuccess = () => resolve(true); - putRequest.onerror = () => reject(putRequest.error); - tx.oncomplete = () => db.close(); // Close the connection - }; - - openDB.onerror = () => reject(openDB.error); - }); + const db = await openDatabase(dbName); + return await putMedia(db, storeName, { key, blob }); }; - // Fetch media from IndexedDB const getMedia = async (key) => { - return new Promise((resolve, reject) => { - const openDB = indexedDB.open(dbName, 1); - openDB.onsuccess = () => { - const db = openDB.result; - const tx = db.transaction(storeName, "readonly"); - const store = tx.objectStore(storeName); - - // Get the media object - const getRequest = store.get(key); - - getRequest.onsuccess = () => resolve(getRequest.result?.blob || null); - getRequest.onerror = () => reject(getRequest.error); - tx.oncomplete = () => db.close(); // Close the connection - }; - - openDB.onerror = () => reject(openDB.error); - }); + const db = await openDatabase(dbName); + return await fetchMedia(db, storeName, key); }; - // Cache media const cacheMedia = async (key, url) => { try { const cachedBlob = await getMedia(key); if (cachedBlob) { - // console.log(`Media for key "${key}" found in cache.`); return URL.createObjectURL(cachedBlob); - } else { - console.log(`Fetching media for key "${key}" from URL.`); - const response = await fetch(url); - const blob = await response.blob(); - await saveMedia(key, blob); - return URL.createObjectURL(blob); } + return await fetchAndCacheMedia(key, url); } catch (error) { console.error(`Error caching media for key "${key}":`, error); throw error; } }; + const openDatabase = (dbName) => { + return new Promise((resolve, reject) => { + const openDB = indexedDB.open(dbName, 1); + + openDB.onsuccess = () => resolve(openDB.result); + openDB.onerror = () => reject(openDB.error); + }); + }; + + const putMedia = (db, storeName, media) => { + return new Promise((resolve, reject) => { + const tx = db.transaction(storeName, "readwrite"); + const store = tx.objectStore(storeName); + const putRequest = store.put(media); + + putRequest.onsuccess = () => resolve(true); + putRequest.onerror = () => reject(putRequest.error); + + tx.oncomplete = () => db.close(); + }); + }; + + const fetchMedia = (db, storeName, key) => { + return new Promise((resolve, reject) => { + const tx = db.transaction(storeName, "readonly"); + const store = tx.objectStore(storeName); + const getRequest = store.get(key); + + getRequest.onsuccess = () => resolve(getRequest.result?.blob || null); + getRequest.onerror = () => reject(getRequest.error); + + tx.oncomplete = () => db.close(); + }); + }; + + const fetchAndCacheMedia = async (key, url) => { + const response = await fetch(url); + const blob = await response.blob(); + await saveMedia(key, blob); + return URL.createObjectURL(blob); + }; + return { cacheMedia }; } From cfca254a0d96f35f6b5e9eaef86ac9735eafa2b7 Mon Sep 17 00:00:00 2001 From: Ajinkya Pande Date: Mon, 23 Dec 2024 23:53:25 +0530 Subject: [PATCH 4/7] Issueid #232034 fix: Sometimes it take time to load icons --- src/components/Layouts.jsx/MainLayout.jsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/Layouts.jsx/MainLayout.jsx b/src/components/Layouts.jsx/MainLayout.jsx index 2faeef8d..1d062dde 100644 --- a/src/components/Layouts.jsx/MainLayout.jsx +++ b/src/components/Layouts.jsx/MainLayout.jsx @@ -230,11 +230,16 @@ const MainLayout = (props) => { useEffect(() => { if (isShowCase && gameOverData) { - setShake(gameOverData ? gameOverData.userWon : true); + setShake(gameOverData.userWon ?? true); - const audioSrc = gameOverData - ? audioCache[gameOverData.userWon ? LevelCompleteAudio : gameLoseAudio] - : audioCache[LevelCompleteAudio]; + let audioSrc; + if (gameOverData) { + audioSrc = gameOverData.userWon + ? audioCache[LevelCompleteAudio] + : audioCache[gameLoseAudio]; + } else { + audioSrc = audioCache[LevelCompleteAudio]; + } if (audioSrc) { const audio = new Audio(audioSrc); @@ -1272,6 +1277,9 @@ MainLayout.propTypes = { storedData: PropTypes.array, resetStoredData: PropTypes.func, pageName: PropTypes.string, + gameOverData: PropTypes.shape({ + userWon: PropTypes.bool, + }), }; export default MainLayout; From bcefb1eb554748edfad869369f37c322ecc5e052 Mon Sep 17 00:00:00 2001 From: Ajinkya Pande Date: Tue, 24 Dec 2024 10:11:50 +0530 Subject: [PATCH 5/7] Issueid #232034 fix: Sometimes it take time to load icons --- src/components/AssesmentEnd/AssesmentEnd.jsx | 8 +++++--- src/components/DiscoverEnd/DiscoverEnd.jsx | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/AssesmentEnd/AssesmentEnd.jsx b/src/components/AssesmentEnd/AssesmentEnd.jsx index c8420b75..ba54b5e4 100644 --- a/src/components/AssesmentEnd/AssesmentEnd.jsx +++ b/src/components/AssesmentEnd/AssesmentEnd.jsx @@ -50,8 +50,10 @@ const AssesmentEnd = () => { useEffect(() => { (async () => { - let audio = new Audio(audioSrc); - audio.play(); + if (audioSrc) { + let audio = new Audio(audioSrc); + audio.play(); + } const virtualId = getLocalData("virtualId"); const lang = getLocalData("lang"); const previous_level = getLocalData("previous_level"); @@ -75,7 +77,7 @@ const AssesmentEnd = () => { setTimeout(() => { setShake(false); }, 4000); - }, []); + }, [audioSrc]); const navigate = useNavigate(); let newLevel = level.replace("m", ""); diff --git a/src/components/DiscoverEnd/DiscoverEnd.jsx b/src/components/DiscoverEnd/DiscoverEnd.jsx index 5c986d2b..a58cbdfd 100644 --- a/src/components/DiscoverEnd/DiscoverEnd.jsx +++ b/src/components/DiscoverEnd/DiscoverEnd.jsx @@ -55,7 +55,6 @@ const SpeakSentenceComponent = () => { (async () => { if (audioSrc) { let audio = new Audio(audioSrc); - console.log(audioSrc); audio.play(); } const virtualId = getLocalData("virtualId"); From 36fe0100d7e37ebaa252e31769b92140b15e8755 Mon Sep 17 00:00:00 2001 From: Ajinkya Pande Date: Tue, 24 Dec 2024 11:50:56 +0530 Subject: [PATCH 6/7] Issueid #232034 fix: Sometimes it take time to load icons --- src/utils/VoiceAnalyser.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/VoiceAnalyser.js b/src/utils/VoiceAnalyser.js index b5b4de74..e575bb54 100644 --- a/src/utils/VoiceAnalyser.js +++ b/src/utils/VoiceAnalyser.js @@ -276,8 +276,6 @@ function VoiceAnalyser(props) { fetchASROutput(lang, recordedAudioBase64); setLoader(true); setEnableAfterLoad(false); - } else { - alert("please record again"); } } }, [props.isNextButtonCalled]); From a0a667d536777b2d5851aa25e3b9727eb4ef8dbd Mon Sep 17 00:00:00 2001 From: Ajinkya Pande Date: Tue, 7 Jan 2025 17:22:02 +0530 Subject: [PATCH 7/7] Issueid #232285 fix: Jumble the word - Invalid content displays.PFA --- src/components/Practice/Mechanics4.jsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Practice/Mechanics4.jsx b/src/components/Practice/Mechanics4.jsx index 5b22c6c0..f3c3ec14 100644 --- a/src/components/Practice/Mechanics4.jsx +++ b/src/components/Practice/Mechanics4.jsx @@ -210,8 +210,9 @@ const Mechanics4 = ({ paddingX: type === "word" ? 0 : "20px", }} > - {selectedWords?.map((elem) => ( + {selectedWords?.map((elem, ind) => ( handleWords(elem, true)} className={ answer === "wrong" @@ -262,8 +263,8 @@ const Mechanics4 = ({ mb: 3, }} > - {words?.map((elem) => ( - + {words?.map((elem, ind) => ( + {type === "word" ? ( handleWords(elem)}