diff --git a/.github/workflows/all-dev-tn-new.yml b/.github/workflows/all-dev-tn-new.yml new file mode 100644 index 00000000..481aff75 --- /dev/null +++ b/.github/workflows/all-dev-tn-new.yml @@ -0,0 +1,95 @@ +name: ALL tn new dev Deployment + +on: + push: + branches: + - all-1.3-tn-dev + +jobs: + deploy: + runs-on: ubuntu-latest + environment: all-dev-tn + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "18" + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Clean up node_modules and package-lock.json + run: | + rm -rf node_modules + rm -f package-lock.json + + - name: Install Dependencies + run: npm install --legacy-peer-deps + + - name: Run Husky Install + run: npm run prepare + + - name: Build and Package Application + env: + SKIP_PREFLIGHT_CHECK: ${{ vars.SKIP_PREFLIGHT_CHECK }} + REACT_APP_MODE: ${{ vars.REACT_APP_MODE }} + REACT_APP_authToken: ${{ vars.REACT_APP_authToken }} + REACT_APP_PID: ${{ vars.REACT_APP_PID }} + REACT_APP_UID: ${{ vars.REACT_APP_UID }} + REACT_APP_ID: ${{ vars.REACT_APP_ID }} + REACT_APP_VER: ${{ vars.REACT_APP_VER }} + REACT_APP_TIMEDIFF: ${{ vars.REACT_APP_TIMEDIFF }} + REACT_APP_HOST: ${{ vars.REACT_APP_HOST }} + REACT_APP_ENDPOINT: ${{ vars.REACT_APP_ENDPOINT }} + REACT_APP_APISLUG: ${{ vars.REACT_APP_APISLUG }} + REACT_APP_CHANNEL: ${{ vars.REACT_APP_CHANNEL }} + REACT_APP_ENV: ${{ vars.REACT_APP_ENV }} + REACT_APP_BATCHSIZE: ${{ vars.REACT_APP_BATCHSIZE }} + REACT_APP_CONTENT_SIZE: ${{ vars.REACT_APP_CONTENT_SIZE }} + REACT_APP_LANGUAGE: ${{ vars.REACT_APP_LANGUAGE }} + REACT_APP_TELEMETRY_MODE: ${{ vars.REACT_APP_TELEMETRY_MODE }} + REACT_APP_VIRTUAL_ID_HOST: ${{ vars.REACT_APP_VIRTUAL_ID_HOST }} + REACT_APP_LEARNER_AI_ORCHESTRATION_HOST: ${{ vars.REACT_APP_LEARNER_AI_ORCHESTRATION_HOST }} + REACT_APP_LEARNER_AI_APP_HOST: ${{ vars.REACT_APP_LEARNER_AI_APP_HOST }} + REACT_APP_CONTENT_SERVICE_APP_HOST: ${{ vars.REACT_APP_CONTENT_SERVICE_APP_HOST }} + REACT_APP_CAPTURE_AUDIO: ${{ vars.REACT_APP_CAPTURE_AUDIO }} + REACT_APP_AWS_S3_BUCKET_NAME: ${{ vars.REACT_APP_AWS_S3_BUCKET_NAME }} + REACT_APP_AWS_S3_BUCKET_URL: ${{ vars.REACT_APP_AWS_S3_BUCKET_URL }} + REACT_APP_AWS_S3_REGION: ${{ vars.REACT_APP_AWS_S3_REGION }} + REACT_APP_AWS_S3_BUCKET_CONTENT_URL: ${{ vars.REACT_APP_AWS_S3_BUCKET_CONTENT_URL }} + REACT_APP_MIN_DECIBELS: ${{ vars.REACT_APP_MIN_DECIBELS }} + REACT_APP_IS_AUDIOPREPROCESSING: ${{ vars.REACT_APP_IS_AUDIOPREPROCESSING }} + REACT_APP_POST_LEARNER_PROGRESS: ${{ vars.REACT_APP_POST_LEARNER_PROGRESS }} + REACT_APP_IS_APP_IFRAME: ${{ vars.REACT_APP_IS_APP_IFRAME }} + REACT_APP_IS_IN_APP_AUTHORISATION: ${{ vars.REACT_APP_IS_IN_APP_AUTHORISATION }} + REACT_APP_LANGUAGES: ${{ vars.REACT_APP_LANGUAGES }} + REACT_APP_AWS_ACCESS_KEY_ID: ${{ secrets.REACT_APP_AWS_ACCESS_KEY_ID }} + REACT_APP_AWS_SECRET_ACCESS_KEY: ${{ secrets.REACT_APP_AWS_SECRET_ACCESS_KEY }} + CI: false # Disabling CI to not treat warnings as errors + run: npm run build + + - name: Deploy to S3 Bucket + run: aws s3 sync ./build s3://all-tn-app-dev/assets/test-rig/ + + - name: Debug Environment Variables + run: | + echo "REACT_APP_AWS_S3_BUCKET_NAME: $REACT_APP_AWS_S3_BUCKET_NAME" + echo "AWS_REGION: $AWS_REGION" + echo "secrate": ${{ vars.REACT_APP_AWS_S3_BUCKET_NAME }} + + - name: Cloudfront Invalidation + uses: chetan/invalidate-cloudfront-action@master + env: + DISTRIBUTION: ${{ secrets.AWS_DISTRIBUTION_NEW }} + PATHS: "/*" + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/src/components/Practice/Mechanics3.jsx b/src/components/Practice/Mechanics3.jsx index 76f1756e..1d26fccc 100644 --- a/src/components/Practice/Mechanics3.jsx +++ b/src/components/Practice/Mechanics3.jsx @@ -15,7 +15,11 @@ import correctSound from "../../assets/audio/correct.wav"; import wrongSound from "../../assets/audio/wrong.wav"; import removeSound from "../../assets/audio/remove.wav"; import VoiceAnalyser from "../../utils/VoiceAnalyser"; +import { Modal } from "@mui/material"; +import ZoomInIcon from "@mui/icons-material/ZoomIn"; +import CloseIcon from "@mui/icons-material/Close"; +// TODO: update it as per File name OR update file name as per export variable name const Mechanics2 = ({ page, setPage, @@ -54,7 +58,7 @@ const Mechanics2 = ({ }) => { const [words, setWords] = useState([]); const [sentences, setSentences] = useState([]); - + const [zoomOpen, setZoomOpen] = useState(false); const [selectedWord, setSelectedWord] = useState(""); // const [loading, setLoading] = useState(false); const [shake, setShake] = useState(false); @@ -68,111 +72,9 @@ const Mechanics2 = ({ }); const lang = getLocalData("lang"); - let wordToCheck = type === "audio" ? parentWords : wordToFill; //console.log('Mechanics3', answer); - useEffect(() => { - const initializeFillInTheBlank = async () => { - if (type === "fillInTheBlank" && parentWords?.length) { - let wordsArr = parentWords.split(" "); - let randomIndex = Math.floor(Math.random() * wordsArr.length); - try { - await getSimilarWords(wordsArr[randomIndex]); - setWordToFill(wordsArr[randomIndex]); - // wordsArr[randomIndex] = "dash"; - setSentences(wordsArr); - setSelectedWord(""); - } catch (error) { - console.error("Error in initializeFillInTheBlank:", error); - } - } - }; - initializeFillInTheBlank(); - }, [contentId, parentWords]); - - useEffect(() => { - const initializeAudio = async () => { - if (type === "audio" && parentWords) { - setDisabledWords(true); - setSelectedWord(""); - try { - await getSimilarWords(parentWords); - } catch (error) { - console.error("Error in initializeAudio:", error); - } - } - }; - initializeAudio(); - }, [contentId, parentWords]); - - const getSimilarWords = async (wordForFindingHomophones) => { - const lang = getLocalData("lang"); - // const isFillInTheBlanks = type === "fillInTheBlank"; - const wordToSimilar = wordForFindingHomophones - ? wordForFindingHomophones - : parentWords; - - if (lang === "en") { - const finder = new HomophonesFinder(); - const homophones = await finder.find(wordToSimilar); - let wordsArr = [homophones[8], wordToSimilar, homophones[6]]; - setWords(randomizeArray(wordsArr)); - } else { - let wordsToShow = []; - if (type == "audio") { - wordsToShow = allWords?.filter((elem) => elem != wordToSimilar); - } - if (type == "fillInTheBlank") { - wordsToShow = allWords - ?.join(" ") - ?.split(" ") - .filter((elem) => elem !== wordToSimilar && elem.length > 2); - } - - wordsToShow = randomizeArray(wordsToShow).slice(0, 2); - wordsToShow.push(wordToSimilar); - setWords(randomizeArray(wordsToShow)); - } - }; - - const handleWord = (word, removeWord) => { - if (removeWord) { - setWords([...words, word]); - setSelectedWord(""); - setEnableNext(false); - } else { - let wordsArr = [...words]; - - if (type !== "audio") { - let index = wordsArr?.findIndex((elem) => elem === word); - if (index !== -1) { - wordsArr?.splice(index, 1); - } - } - - if (selectedWord && type !== "audio") { - wordsArr.push(selectedWord); - } - - // if (type === "audio") { - const isSoundCorrect = word === wordToCheck; - let audio = new Audio(isSoundCorrect ? correctSound : wrongSound); - if (!isSoundCorrect) { - setEnableNext(false); - } - audio.play(); - setShake(true); - setTimeout(() => { - setShake(false); - }, 800); - // } - - setWords(wordsArr); - setSelectedWord(word); - } - }; - useEffect(() => { if (!enableNext) { setAnswer({ text: "", audio_url: "", image_url: "", isAns: false }); @@ -201,6 +103,7 @@ const Mechanics2 = ({ setEnableNext(false); }; + // TODO: Constants declaration Need to move up const audioRef = createRef(null); const [duration, setDuration] = useState(0); const [isReady, setIsReady] = React.useState(false); @@ -219,25 +122,17 @@ const Mechanics2 = ({ } }; + // TODO: all the constants declaration Need to move up const [currrentProgress, setCurrrentProgress] = React.useState(0); const progressBarWidth = Number.isNaN(currrentProgress / duration) ? 0 : currrentProgress / duration; - const getEnableButton = () => { - if (type === "fillInTheBlank") { - return enableNext; - } - if (type === "audio") { - return selectedWord === wordToCheck; - } - return false; - }; return ( - {image && ( - + {image && ( + setZoomOpen(true)} + src={image} + style={{ + borderRadius: "20px", + maxWidth: "100%", + height: "clamp(150px, 20vw, 220px)", + }} + alt="" + /> + )} + + {/* Subtle gradient overlay across the top */} + - )} + > + {/* Zoom icon positioned in the top-left corner */} + setZoomOpen(true)} + sx={{ color: "white", fontSize: "22px", cursor: "pointer" }} + /> + + + setZoomOpen(false)} + sx={{ + display: "flex", + alignItems: "center", + justifyContent: "center", + }} + > + + {/* Subtle gradient overlay at the top of the zoomed image */} + + {/* Close icon positioned within the gradient overlay */} + setZoomOpen(false)} + sx={{ + color: "white", + fontSize: "24px", + cursor: "pointer", + backgroundColor: "rgba(0, 0, 0, 0.5)", + borderRadius: "50%", + padding: "4px", + }} + /> + + + Zoomed content + + {answer?.text !== "" ? ( <> - {parentWords?.split("_____")[0]} {/* Before the blank */} + {parentWords?.split(/_+/)[0]} {answer?.text} - {parentWords?.split("_____")[1]} {/* After the blank */} + {parentWords?.split(/_+/)[1]} ) : ( <>{parentWords} @@ -438,52 +421,9 @@ const Mechanics2 = ({ justifyContent: "center", marginTop: "20px", marginBottom: "30px", + flexWrap: "wrap", }} > - {type === "audio" && - words?.map((elem, ind) => ( - handleWord(elem)} - sx={{ - textAlign: "center", - px: "25px", - py: "12px", - // background: "transparent", - m: 1, - textTransform: "none", - borderRadius: "12px", - border: `1px solid rgba(51, 63, 97, 0.10)`, - background: "#FFF", - cursor: "pointer", - opacity: disabledWords ? 0.25 : 1, - pointerEvents: disabledWords ? "none" : "initial", - }} - > - - {elem} - - - ))} <> {type === "fillInTheBlank" && Array.isArray(options) && @@ -550,7 +490,7 @@ const Mechanics2 = ({ dontShowListen={type === "image" || isDiscover} // updateStory={updateStory} originalText={parentWords} - enableNext={getEnableButton()} + enableNext={enableNext} handleNext={handleNext} audioLink={audio ? audio : null} {...{ diff --git a/src/components/Practice/Mechanics4.jsx b/src/components/Practice/Mechanics4.jsx index 08a1d0f1..5b22c6c0 100644 --- a/src/components/Practice/Mechanics4.jsx +++ b/src/components/Practice/Mechanics4.jsx @@ -1,5 +1,5 @@ import { Box } from "@mui/material"; -import { useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; import VoiceAnalyser from "../../utils/VoiceAnalyser"; import MainLayout from "../Layouts.jsx/MainLayout"; // import useSound from "use-sound"; @@ -133,7 +133,7 @@ const Mechanics4 = ({ setSelectedWords([...selectedWords, word]); if (selectedWords?.length + 1 === wordsAfterSplit?.length) { let audio = new Audio( - [...selectedWords, word]?.join("") === parentWords + [...selectedWords, word]?.join(" ") === parentWords ? correctSound : wrongSound ); @@ -192,6 +192,7 @@ const Mechanics4 = ({ minHeight: "75px", display: "flex", justifyContent: "center", + flexWrap: "wrap", alignItems: "center", borderRadius: "15px", border: `2px solid ${ @@ -241,7 +242,7 @@ const Mechanics4 = ({ ? "#C30303" : "#333F61", fontWeight: type === "word" ? 600 : 700, - fontSize: "40px", + fontSize: "clamp(1.5rem, 2.5vw, 2.5rem)", fontFamily: "Quicksand", cursor: "pointer", marginLeft: @@ -253,9 +254,16 @@ const Mechanics4 = ({ ))} - + {words?.map((elem) => ( - <> + {type === "word" ? ( handleWords(elem)} @@ -263,20 +271,26 @@ const Mechanics4 = ({ display: "flex", justifyContent: "center", alignItems: "center", - height: "60px", - minWidth: "60px", + height: { xs: "50px", sm: "60px", md: "70px" }, + minWidth: { xs: "50px", sm: "60px", md: "70px" }, background: "#1897DE", - m: 1, + m: { xs: 0.5, sm: 1 }, cursor: "pointer", borderRadius: "12px", border: "5px solid #10618E", + fontSize: { xs: "25px", sm: "30px", md: "35px", lg: "40px" }, }} > @@ -288,22 +302,21 @@ const Mechanics4 = ({ onClick={() => handleWords(elem)} sx={{ textAlign: "center", - px: "25px", - py: "12px", - // background: "transparent", - m: 1, + px: { xs: "15px", sm: "20px", md: "25px" }, + py: { xs: "8px", sm: "10px", md: "12px" }, + m: { xs: 0.5, sm: 1 }, textTransform: "none", borderRadius: "12px", border: `1px solid rgba(51, 63, 97, 0.10)`, background: "#FFF", cursor: "pointer", + fontSize: { xs: "25px", sm: "30px", md: "35px", lg: "40px" }, }} > @@ -311,9 +324,10 @@ const Mechanics4 = ({ )} - + ))} + { React.createRef()) ); + const [zoomOpen, setZoomOpen] = useState(false); const questionAudioRef = useRef(); const [playingIndex, setPlayingIndex] = useState(null); const [selectedOption, setSelectedOption] = useState(null); // Add state to track selected radio button @@ -179,13 +183,109 @@ const Mechanics5 = ({ container sx={{ width: "80%", justifyContent: "center", mb: 2, mt: 8 }} > - - + + {/* Image with full-width gradient overlay on top */} + + contentImage setZoomOpen(true)} // Open modal on click + /> + + {/* Subtle gradient overlay across the top */} + + {/* Zoom icon positioned in the top-left corner */} + setZoomOpen(true)} + sx={{ color: "white", fontSize: "22px", cursor: "pointer" }} + /> + + + + {/* Modal for zoomed image with gradient and close icon */} + setZoomOpen(false)} + sx={{ + display: "flex", + alignItems: "center", + justifyContent: "center", + }} + > + + {/* Subtle gradient overlay at the top of the zoomed image */} + + {/* Close icon positioned within the gradient overlay */} + setZoomOpen(false)} + sx={{ + color: "white", + fontSize: "24px", + cursor: "pointer", + backgroundColor: "rgba(0, 0, 0, 0.5)", + borderRadius: "50%", + padding: "4px", + }} + /> + + + Zoomed content + + +