diff --git a/src/config/apiendpoint.js b/src/config/apiendpoint.js index 136b51a1..1fdb90c3 100644 --- a/src/config/apiendpoint.js +++ b/src/config/apiendpoint.js @@ -24,6 +24,7 @@ const endpoints = { //Video video: "/video/", getVideoTasks: '/video/list_tasks', + listVideosTasks:'/video/get_listings', transcript: "/transcript/", GetAllTranscriptions:"/transcript/retrieve_all_transcriptions/", GetAllTranslations:"/translation/retrieve_all_translations/", diff --git a/src/containers/Admin/Dashboard.jsx b/src/containers/Admin/Dashboard.jsx index 0d13c1a3..a326b154 100644 --- a/src/containers/Admin/Dashboard.jsx +++ b/src/containers/Admin/Dashboard.jsx @@ -14,6 +14,7 @@ import AdminLevelReport from "./AdminLevelReport"; import NewsLetter from "./NewsLetterTemplate"; import OnboardingRequests from "./OnboardingRequests"; import VideoTaskDetails from "./VideoTaskDetails"; +import VideoDetails from "./VideoDetails"; import TaskDetails from "./TaskDetails"; // APIs @@ -83,6 +84,7 @@ const DashBoard = () => { ]; const orgOwnerTabs = [ + { label: "Video Details", component: }, { label: "Video Task Details", component: }, { label: "Task Details", component: }, ]; @@ -94,9 +96,7 @@ const DashBoard = () => { - + {isAdmin && adminTabs.map((tab, index) => ( @@ -186,11 +186,17 @@ const DashBoard = () => { <> - + + + + + + + diff --git a/src/containers/Admin/TaskDetails.jsx b/src/containers/Admin/TaskDetails.jsx index baf0d3d2..cc73ab1c 100644 --- a/src/containers/Admin/TaskDetails.jsx +++ b/src/containers/Admin/TaskDetails.jsx @@ -2,30 +2,108 @@ import React, { useState } from 'react'; import { Grid, TextField, Button, Box, Typography, CircularProgress, Tabs, Tab } from '@mui/material'; import { JSONTree } from 'react-json-tree'; import GetTaskDetailsAPI from "redux/actions/api/Admin/GetTaskDetails.js"; +import GetAllTranscriptionsAPI from "redux/actions/api/Admin/GetAllTranscriptions.js"; +import GetAllTranslationsAPI from "redux/actions/api/Admin/GetAllTranslations.js"; import { snakeToTitleCase } from '../../utils/utils.js'; function TaskDetails() { const [taskId, setTaskId] = useState(''); const [tabValue, setTabValue] = useState(0); const [taskDetails, setTaskDetails] = useState(null); + const [transcriptions, setTranscriptions] = useState(null); + const [translations, setTranslations] = useState(null); const [loading, setLoading] = useState(false); + const [loadingTranscriptions, setLoadingTranscriptions] = useState(false); + const [loadingTranslations, setLoadingTranslations] = useState(false); const fetchTaskDetails = async () => { setLoading(true); setTaskDetails(null); + setTranscriptions(null); + setTranslations(null); + const apiObj = new GetTaskDetailsAPI(taskId); - fetch(apiObj.apiEndPoint(), apiObj.getHeaders()) - .then(async (res) => { - if (res.status === 200) { - const data = await res.json(); - setTaskDetails(data); - } else if (res.status === 404) { - setTaskDetails({ error: 'Task not found' }); - } else { - setTaskDetails({ error: 'Something went wrong' }); - } - setLoading(false); - }); + try { + const res = await fetch(apiObj.apiEndPoint(), apiObj.getHeaders()); + let data; + if (res.status === 200) { + data = await res.json(); + } else if (res.status === 404) { + data = { error: 'Task not found' }; + } else { + data = { error: 'Something went wrong' }; + } + + setLoading(false); + if (data.error) { + setTaskDetails({ error: data.error }); + return; + } + + setTaskDetails(data); + const videoId = data.video; + + setTabValue(0); + + if (["TRANSCRIPTION_EDIT", "TRANSCRIPTION_REVIEW"].includes(data.task_type)) { + fetchTranscriptions(videoId); + } else if (["TRANSLATION_EDIT", "TRANSLATION_REVIEW", "TRANSLATION_VOICEOVER_EDIT", "TRANSLATION_VOICEOVER_REVIEW"].includes(data.task_type)) { + fetchTranslations(videoId); + } + + } catch (error) { + setLoading(false); + setTaskDetails({ error: 'Network error' }); + console.error(error); + } + }; + + const fetchTranscriptions = async (videoId) => { + setLoadingTranscriptions(true); + const apiObj = new GetAllTranscriptionsAPI(videoId); + try { + const res = await fetch(apiObj.apiEndPoint(), apiObj.getHeaders()); + let data; + if (res.status === 200) { + data = await res.json(); + } else { + data = { error: 'Failed to fetch transcriptions' }; + } + + if (data.error) { + setTranscriptions({ error: data.error }); + } else { + setTranscriptions(data.transcripts); + } + } catch (error) { + setTranscriptions({ error: 'Network error' }); + console.error(error); + } + setLoadingTranscriptions(false); + }; + + const fetchTranslations = async (videoId) => { + setLoadingTranslations(true); + const apiObj = new GetAllTranslationsAPI(videoId); + try { + const res = await fetch(apiObj.apiEndPoint(), apiObj.getHeaders()); + let data; + if (res.status === 200) { + data = await res.json(); + } else { + data = { error: 'Failed to fetch translations' }; + } + + if (data.error) { + setTranslations({ error: data.error }); + } else { + setTranslations(data); + } + } catch (error) { + setTranslations({ error: 'Network error' }); + console.error(error); + } + setLoadingTranslations(false); }; const theme = { @@ -39,9 +117,9 @@ function TaskDetails() { base06: '#f5f4f1', base07: '#f9f8f5', base08: '#f92672', - base09: '#fd971f', //orange + base09: '#fd971f', base0A: '#f4bf75', - base0B: '#a6e22e', //green + base0B: '#a6e22e', base0C: '#a1efe4', base0D: '#66d9ef', base0E: '#ae81ff', @@ -86,7 +164,7 @@ function TaskDetails() { > {value === index && ( - {children} + {children} )} @@ -119,19 +197,80 @@ function TaskDetails() { setTabValue(v)} aria-label="task-details-tabs"> + {["TRANSCRIPTION_EDIT", "TRANSCRIPTION_REVIEW"].includes(taskDetails.task_type) && ( + + )} + {["TRANSLATION_EDIT", "TRANSLATION_REVIEW", "TRANSLATION_VOICEOVER_EDIT", "TRANSLATION_VOICEOVER_REVIEW"].includes(taskDetails.task_type) && ( + + )} + - {typeof key === "string" ? snakeToTitleCase(key) : key}} - valueRenderer={(raw) => {typeof raw === "string" && raw.match(/^"(.*)"$/) ? raw.slice(1, -1) : raw}} - theme={theme} - /> + {taskDetails.error ? ( + {taskDetails.error} + ) : ( + {typeof key === "string" ? snakeToTitleCase(key) : key}} + valueRenderer={(raw) => {typeof raw === "string" && raw.match(/^"(.*)"$/) ? raw.slice(1, -1) : raw}} + theme={theme} + /> + )} + + {["TRANSCRIPTION_EDIT", "TRANSCRIPTION_REVIEW"].includes(taskDetails.task_type) && ( + + {loadingTranscriptions ? ( + + + + ) : transcriptions ? ( + transcriptions.error ? ( + {transcriptions.error} + ) : ( + {typeof key === "string" ? snakeToTitleCase(key) : key}} + valueRenderer={(raw) => {typeof raw === "string" && raw.match(/^"(.*)"$/) ? raw.slice(1, -1) : raw}} + theme={theme} + /> + ) + ) : ( + No transcriptions available. + )} + + )} + + {["TRANSLATION_EDIT", "TRANSLATION_REVIEW", "TRANSLATION_VOICEOVER_EDIT", "TRANSLATION_VOICEOVER_REVIEW"].includes(taskDetails.task_type) && ( + + {loadingTranslations ? ( + + + + ) : translations ? ( + translations.error ? ( + {translations.error} + ) : ( + {typeof key === "string" ? snakeToTitleCase(key) : key}} + valueRenderer={(raw) => {typeof raw === "string" && raw.match(/^"(.*)"$/) ? raw.slice(1, -1) : raw}} + theme={theme} + /> + ) + ) : ( + No translations available. + )} + + )} )} diff --git a/src/containers/Admin/VideoDetails.jsx b/src/containers/Admin/VideoDetails.jsx new file mode 100644 index 00000000..93c01395 --- /dev/null +++ b/src/containers/Admin/VideoDetails.jsx @@ -0,0 +1,147 @@ +import React, { useState } from 'react'; +import { Grid, TextField, Button, Tab, Tabs, Box, Typography, CircularProgress } from '@mui/material'; +import { JSONTree } from 'react-json-tree'; +import GetVideoDetailsAPI from "redux/actions/api/Admin/GetVideoDetails.js"; +import { snakeToTitleCase } from '../../utils/utils.js'; + +function VideoDetails() { + const [videoUrl, setVideoUrl] = useState(''); + const [tabValue, setTabValue] = useState(0); + const [taskDetails, setTaskDetails] = useState(null); + const [loading, setLoading] = useState(false); + + const fetchVideoDetails = async () => { + setLoading(true); + setTaskDetails(null); + + const apiObj = new GetVideoDetailsAPI(videoUrl); + fetch(apiObj.apiEndPoint(), apiObj.getHeaders()) + .then(async (res) => { + if (res.status === 200) { + const data = await res.json(); + return data; + } else if (res.status === 404) { + return { error: 'Task not found' }; + } else { + return { error: 'Something went wrong' }; + } + }) + .then(data => { + setLoading(false); + setTaskDetails(data); + }); + }; + + const theme = { + extend: { + base00: '#000', + base01: '#383830', + base02: '#49483e', + base03: '#75715e', + base04: '#a59f85', + base05: '#f8f8f2', + base06: '#f5f4f1', + base07: '#f9f8f5', + base08: '#f92672', + base09: '#fd971f', + base0A: '#f4bf75', + base0B: '#a6e22e', + base0C: '#a1efe4', + base0D: '#66d9ef', + base0E: '#ae81ff', + base0F: '#cc6633', + }, + value: ({ style }, nodeType, keyPath) => ({ + style: { + ...style, + borderLeft: '2px solid #ccc', + marginLeft: '1.375em', + paddingLeft: '2em', + }, + }), + nestedNode: ({ style }, nodeType, keyPath) => ({ + style: { + ...style, + borderLeft: '2px solid #ccc', + marginLeft: keyPath.length > 1 ? '1.375em' : 0, + textIndent: '-0.375em', + }, + }), + arrowContainer: ({ style }, arrowStyle) => ({ + style: { + ...style, + paddingRight: '1.375rem', + textIndent: '0rem', + backgroundColor: 'white', + }, + }), + }; + + function TabPanel(props) { + const { children, value, index, ...other } = props; + + return ( + + ); + } + + return ( + + + + setVideoUrl(event.target.value)} + /> + + + + {loading && ( + + + + )} + {taskDetails && ( + <> + + setTabValue(v)} aria-label="video-task-details-tabs"> + + + + + + + {typeof key === "string" ? snakeToTitleCase(key) : key}} + valueRenderer={(raw) => {typeof raw === "string" && raw.match(/^"(.*)"$/) ? raw.slice(1, -1) : raw}} + theme={theme} + /> + + + + )} + + ); +} + +export default VideoDetails; diff --git a/src/containers/Organization/OrgLevelTaskList.jsx b/src/containers/Organization/OrgLevelTaskList.jsx index 75964686..f9cbeaf5 100644 --- a/src/containers/Organization/OrgLevelTaskList.jsx +++ b/src/containers/Organization/OrgLevelTaskList.jsx @@ -55,6 +55,7 @@ import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; import ImportExportIcon from "@mui/icons-material/ImportExport"; import AudiotrackOutlinedIcon from '@mui/icons-material/AudiotrackOutlined'; +import { Loader } from "common"; // Utils import getLocalStorageData from "utils/getLocalStorageData"; @@ -1263,6 +1264,7 @@ const OrgLevelTaskList = () => { return ( <> + {loading && }