{
+// Tab Panel Component
+function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
@@ -31,18 +34,30 @@ const TabPanel = (props) => {
{value === index && {children}}
);
-};
+}
const DashBoard = () => {
const classes = DatasetStyle();
const navigate = useNavigate();
const dispatch = useDispatch();
- const [value, setValue] = useState(0);
+ // Fetch userData from Redux
+ const userData = useSelector((state) => state.getLoggedInUserDetails.data);
+
+ const [value, setValue] = useState(0);
const [addUserDialog, setAddUserDialog] = useState(false);
const [newMemberEmail, setNewMemberEmail] = useState("");
const [openMemberDialog, setOpenMemberDialog] = useState(false);
+ // Fetch user data on component mount
+ useEffect(() => {
+ const fetchUserData = () => {
+ const loggedInUserObj = new FetchLoggedInUserDetailsAPI();
+ dispatch(APITransport(loggedInUserObj));
+ };
+ fetchUserData();
+ }, [dispatch]);
+
const addNewMemberHandler = async () => {
const data = {
role: "ORG_OWNER",
@@ -55,146 +70,137 @@ const DashBoard = () => {
setNewMemberEmail("");
};
+ const handleTabChange = (event, newValue) => {
+ setValue(newValue);
+ };
+
+ const adminTabs = [
+ { label: "Organizations", component: },
+ { label: "Members", component: },
+ { label: "Reports", component: },
+ { label: "Newsletter", component: },
+ { label: "Onboarding Requests", component: },
+ ];
+
+ const orgOwnerTabs = [
+ { label: "Video Task Details", component: },
+ { label: "Task Details", component: },
+ ];
+
+ const isAdmin = userData?.role === "ADMIN";
+ const isOrgOwner = userData?.role === "ORG_OWNER";
+
return (
- setValue(newValue)}
- aria-label="basic tabs example"
- >
-
-
-
-
-
+
+ {isAdmin &&
+ adminTabs.map((tab, index) => (
+
+ ))}
+
+ {isOrgOwner &&
+ orgOwnerTabs.map((tab, index) => (
+
+ ))}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ {isAdmin && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+ {isOrgOwner && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+ {/* Dialogs */}
{addUserDialog && (
{
/>
)}
- {openMemberDialog && (
- setOpenMemberDialog(false)}
- />
- )}
+ {openMemberDialog && setOpenMemberDialog(false)} />}
);
};
-export default DashBoard;
+export default DashBoard;
\ No newline at end of file
diff --git a/src/containers/Admin/TaskDetails.jsx b/src/containers/Admin/TaskDetails.jsx
new file mode 100644
index 00000000..baf0d3d2
--- /dev/null
+++ b/src/containers/Admin/TaskDetails.jsx
@@ -0,0 +1,142 @@
+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 { snakeToTitleCase } from '../../utils/utils.js';
+
+function TaskDetails() {
+ const [taskId, setTaskId] = useState('');
+ const [tabValue, setTabValue] = useState(0);
+ const [taskDetails, setTaskDetails] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const fetchTaskDetails = async () => {
+ setLoading(true);
+ setTaskDetails(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);
+ });
+ };
+
+ const theme = {
+ extend: {
+ base00: '#000',
+ base01: '#383830',
+ base02: '#49483e',
+ base03: '#75715e',
+ base04: '#a59f85',
+ base05: '#f8f8f2',
+ base06: '#f5f4f1',
+ base07: '#f9f8f5',
+ base08: '#f92672',
+ base09: '#fd971f', //orange
+ base0A: '#f4bf75',
+ base0B: '#a6e22e', //green
+ 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 (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+ }
+
+ return (
+
+
+
+ setTaskId(event.target.value)}
+ />
+
+
+
+ {loading && (
+
+
+
+ )}
+ {taskDetails && (
+ <>
+
+ setTabValue(v)} aria-label="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 TaskDetails;
diff --git a/src/containers/Admin/VideoTaskDetails.jsx b/src/containers/Admin/VideoTaskDetails.jsx
new file mode 100644
index 00000000..572c422f
--- /dev/null
+++ b/src/containers/Admin/VideoTaskDetails.jsx
@@ -0,0 +1,231 @@
+import React, { useState } from 'react';
+import { Grid, TextField, Button, Tab, Tabs, Box, Typography, CircularProgress } from '@mui/material';
+import { JSONTree } from 'react-json-tree';
+import GetAllTranscriptionsAPI from "redux/actions/api/Admin/GetAllTranscriptions.js";
+import GetAllTranslationsAPI from "redux/actions/api/Admin/GetAllTranslations.js";
+import GetVideoTaskDetailsAPI from "redux/actions/api/Admin/GetVideoTaskDetails.js";
+import { snakeToTitleCase } from '../../utils/utils.js';
+
+function VideoTaskDetails() {
+ const [videoId, setVideoId] = 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 fetchVideoTaskDetails = async () => {
+ setLoading(true);
+ setTaskDetails(null);
+ setTranscriptions(null);
+ setTranslations(null);
+
+ const apiObj = new GetVideoTaskDetailsAPI(videoId);
+ 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);
+ fetchTranscriptions();
+ fetchTranslations();
+ });
+ };
+
+ const fetchTranscriptions = async () => {
+ setLoadingTranscriptions(true);
+ const apiObj = new GetAllTranscriptionsAPI(videoId);
+ fetch(apiObj.apiEndPoint(), apiObj.getHeaders())
+ .then(async (res) => {
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else {
+ return { error: 'Failed to fetch transcriptions' };
+ }
+ })
+ .then(data => {
+ setTranscriptions(data.transcripts);
+ setLoadingTranscriptions(false);
+ });
+ };
+
+ const fetchTranslations = async () => {
+ setLoadingTranslations(true);
+ const apiObj = new GetAllTranslationsAPI(videoId);
+ fetch(apiObj.apiEndPoint(), apiObj.getHeaders())
+ .then(async (res) => {
+ if (res.status === 200) {
+ const data = await res.json();
+ return data;
+ } else {
+ return { error: 'Failed to fetch translations' };
+ }
+ })
+ .then(data => {
+ setTranslations(data);
+ setLoadingTranslations(false);
+ });
+ };
+
+ 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 (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+ }
+
+ return (
+
+
+
+ setVideoId(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}
+ />
+
+
+ {loadingTranscriptions ? (
+
+
+
+ ) : transcriptions ? (
+ {typeof key === "string" ? snakeToTitleCase(key) : key}}
+ valueRenderer={(raw) => {typeof raw === "string" && raw.match(/^"(.*)"$/) ? raw.slice(1, -1) : raw}}
+ theme={theme}
+ />
+ ) : (
+ No transcriptions available.
+ )}
+
+
+ {loadingTranslations ? (
+
+
+
+ ) : translations ? (
+ {typeof key === "string" ? snakeToTitleCase(key) : key}}
+ valueRenderer={(raw) => {typeof raw === "string" && raw.match(/^"(.*)"$/) ? raw.slice(1, -1) : raw}}
+ theme={theme}
+ />
+ ) : (
+ No translations available.
+ )}
+
+
+ >
+ )}
+
+ );
+}
+
+export default VideoTaskDetails;
diff --git a/src/redux/actions/api/Admin/GetAllTranscriptions.js b/src/redux/actions/api/Admin/GetAllTranscriptions.js
new file mode 100644
index 00000000..48a6cae4
--- /dev/null
+++ b/src/redux/actions/api/Admin/GetAllTranscriptions.js
@@ -0,0 +1,43 @@
+import API from "../../../api";
+import ENDPOINTS from "../../../../config/apiendpoint";
+import constants from "../../../constants";
+
+export default class GetAllTranscriptions extends API {
+ constructor(videoId, timeout = 2000) {
+ super("GET", timeout, false);
+ this.type = constants.GET_ALL_TRANSCRIPTIONS;
+ this.endpoint = `${super.apiEndPointAuto()}${ENDPOINTS.GetAllTranscriptions}?video_id=${videoId}`;
+ }
+
+ processResponse(res) {
+ super.processResponse(res);
+ if (res) {
+ this.taskDetails = res;
+ } else {
+ this.taskDetails = { error: 'No data received' };
+ }
+ }
+
+ apiEndPoint() {
+ return this.endpoint;
+ }
+
+ getHeaders() {
+ const token = localStorage.getItem('token');
+ if (!token) {
+ console.warn('Authorization token not found in localStorage');
+ }
+
+ this.headers = {
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `JWT ${token}`,
+ },
+ };
+ return this.headers;
+ }
+
+ getPayload() {
+ return this.taskDetails;
+ }
+}
diff --git a/src/redux/actions/api/Admin/GetAllTranslations.js b/src/redux/actions/api/Admin/GetAllTranslations.js
new file mode 100644
index 00000000..c535f824
--- /dev/null
+++ b/src/redux/actions/api/Admin/GetAllTranslations.js
@@ -0,0 +1,43 @@
+import API from "../../../api";
+import ENDPOINTS from "../../../../config/apiendpoint";
+import constants from "../../../constants";
+
+export default class GetAllTranslationsAPI extends API {
+ constructor(videoId, timeout = 2000) {
+ super("GET", timeout, false);
+ this.type = constants.GET_ALL_TRANSLATIONS;
+ this.endpoint = `${super.apiEndPointAuto()}${ENDPOINTS.GetAllTranslations}?video_id=${videoId}`;
+ }
+
+ processResponse(res) {
+ super.processResponse(res);
+ if (res) {
+ this.taskDetails = res;
+ } else {
+ this.taskDetails = { error: 'No data received' };
+ }
+ }
+
+ apiEndPoint() {
+ return this.endpoint;
+ }
+
+ getHeaders() {
+ const token = localStorage.getItem('token');
+ if (!token) {
+ console.warn('Authorization token not found in localStorage');
+ }
+
+ this.headers = {
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `JWT ${token}`,
+ },
+ };
+ return this.headers;
+ }
+
+ getPayload() {
+ return this.taskDetails;
+ }
+}
diff --git a/src/redux/actions/api/Admin/GetTaskDetails.js b/src/redux/actions/api/Admin/GetTaskDetails.js
new file mode 100644
index 00000000..5516edf0
--- /dev/null
+++ b/src/redux/actions/api/Admin/GetTaskDetails.js
@@ -0,0 +1,47 @@
+/**
+ * GetTaskDetails
+ */
+
+import API from "../../../api";
+import ENDPOINTS from "../../../../config/apiendpoint";
+import constants from "../../../constants";
+
+export default class GetTaskDetailsAPI extends API {
+ constructor(taskId, timeout = 2000) {
+ super("GET", timeout, false);
+ this.type = constants.GET_TASK_DETAILS;
+ this.endpoint = `${super.apiEndPointAuto()}${ENDPOINTS.task}${taskId}/`;
+ }
+
+ processResponse(res) {
+ super.processResponse(res);
+ if (res) {
+ this.taskDetails = res;
+ }
+ }
+
+ apiEndPoint() {
+ return this.endpoint;
+ }
+
+ getBody() {}
+
+ getHeaders() {
+ const token = localStorage.getItem('token');
+ if (!token) {
+ console.warn('Authorization token not found in localStorage');
+ }
+
+ this.headers = {
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `JWT ${token}`,
+ },
+ };
+ return this.headers;
+ }
+
+ getPayload() {
+ return this.taskDetails
+ }
+}
diff --git a/src/redux/actions/api/Admin/GetVideoTaskDetails.js b/src/redux/actions/api/Admin/GetVideoTaskDetails.js
new file mode 100644
index 00000000..99e0bbb6
--- /dev/null
+++ b/src/redux/actions/api/Admin/GetVideoTaskDetails.js
@@ -0,0 +1,43 @@
+import API from "../../../api";
+import ENDPOINTS from "../../../../config/apiendpoint";
+import constants from "../../../constants";
+
+export default class GetVideoTaskDetailsAPI extends API {
+ constructor(videoId, timeout = 2000) {
+ super("GET", timeout, false);
+ this.type = constants.GET_VIDEO_TASK_DETAILS;
+ this.endpoint = `${super.apiEndPointAuto()}${ENDPOINTS.getVideoTasks}?video_id=${videoId}`;
+ }
+
+ processResponse(res) {
+ super.processResponse(res);
+ if (res) {
+ this.taskDetails = res;
+ } else {
+ this.taskDetails = { error: 'No data received' };
+ }
+ }
+
+ apiEndPoint() {
+ return this.endpoint;
+ }
+
+ getHeaders() {
+ const token = localStorage.getItem('token');
+ if (!token) {
+ console.warn('Authorization token not found in localStorage');
+ }
+
+ this.headers = {
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `JWT ${token}`,
+ },
+ };
+ return this.headers;
+ }
+
+ getPayload() {
+ return this.taskDetails;
+ }
+}
diff --git a/src/redux/constants.js b/src/redux/constants.js
index 1298aa6b..abe48a61 100644
--- a/src/redux/constants.js
+++ b/src/redux/constants.js
@@ -72,6 +72,9 @@ const constants = {
ONBOARDING: "ONBOARDING",
//Task
+ GET_ALL_TRANSCRIPTIONS:"GET_ALL_TRANSCRIPTIONS",
+ GET_TASK_ANNOTATIONS:"GET_TASK_ANNOTATIONS",
+ GET_ALL_TRANSLATIONS:"GET_ALL_TRANSLATIONS",
CREATE_NEW_TASk: "CREATE_NEW_TASk",
GET_TASK_LIST: "GET_TASK_LIST",
GET_TASK_DETAILS: "GET_TASK_DETAILS",
@@ -137,6 +140,7 @@ const constants = {
CREATE_MEMBER: "CREATE_MEMBER",
UPDATE_ONBOARDING_FORM: "UPDATE_ONBOARDING_FORM",
GET_ONBOARDING_LIST: "GET_ONBOARDING_LIST",
+ GET_VIDEO_TASK_DETAILS:"GET_VIDEO_TASK_DETAILS",
//clear state
CLEAR_STATE: "CLEAR_STATE",
@@ -167,4 +171,4 @@ const constants = {
GET_VOICEOVER_CHART: "GET_VOICEOVER_CHART",
};
-export default constants;
+export default constants;
\ No newline at end of file