diff --git a/src/common/AddOrganizationMember.jsx b/src/common/AddOrganizationMember.jsx index 32ca81e3..518e7d98 100644 --- a/src/common/AddOrganizationMember.jsx +++ b/src/common/AddOrganizationMember.jsx @@ -1,4 +1,4 @@ -import { Fragment, useEffect } from "react"; +import { Fragment, useEffect,useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { MenuProps } from "utils"; @@ -38,6 +38,7 @@ const AddOrganizationMember = ({ isAdmin, }) => { const dispatch = useDispatch(); + const [inputValue, setInputValue] = useState(""); const userRoles = useSelector((state) => state.getUserRoles.data); @@ -45,6 +46,31 @@ const AddOrganizationMember = ({ const userObj = new FetchUserRolesAPI(); dispatch(APITransport(userObj)); }; + const handleKeyDown = (event) => { + if (event.key === "Enter" || event.key === " " || event.key === ",") { + event.preventDefault(); + if (inputValue.trim()) { + handleTextField((prev) => [...prev, inputValue.trim()]); + setInputValue(""); + } + } + }; + // const save =(event)=>{ + // if (inputValue.trim()) { + // handleTextField((prev) => [...prev, inputValue.trim()]); + // setInputValue(""); + // } + // } + + // const handleAddButtonClick = async() => { + // save(); + // await(handleTextField) + // setTimeout(() => { + // addBtnClickHandler(); + // handleUserDialogClose(); + // }, 1000); + // }; + useEffect(() => { getUserRolesList(); @@ -69,7 +95,10 @@ const AddOrganizationMember = ({ {title} { + addBtnClickHandler() + handleUserDialogClose() + }} sx={{ marginLeft: "auto" }} > @@ -82,10 +111,15 @@ const AddOrganizationMember = ({ freeSolo id="add-members" value={textFieldValue} - onChange={(event) => { - event.target.value.trim().length && - handleTextField((prev) => [...prev, event.target.value]); + onChange={(event, newValue, reason) => { + console.log("hello",event,newValue,reason); + + }} + inputValue={inputValue} + onInputChange={(event, newInputValue) => { + setInputValue(newInputValue); }} + onKeyDown={handleKeyDown} options={[]} renderTags={(tagValue) => { return tagValue.map((option) => ( @@ -150,8 +184,8 @@ const AddOrganizationMember = ({ variant="contained" sx={{ marginLeft: "10px", borderRadius: "8px" }} onClick={() => { - addBtnClickHandler(); - handleUserDialogClose(); + addBtnClickHandler() + handleUserDialogClose() }} disabled={textFieldLabel || selectFieldValue ? false : true} > diff --git a/src/common/AddProjectMembers.jsx b/src/common/AddProjectMembers.jsx index 53650d5b..a41d5439 100644 --- a/src/common/AddProjectMembers.jsx +++ b/src/common/AddProjectMembers.jsx @@ -1,5 +1,5 @@ import React from "react"; - +import { useSelector } from "react-redux"; //Components import { Button, @@ -30,6 +30,13 @@ const AddProjectMembers = ({ handleSelectField, managerNames, }) => { + const alreadyExistingUsers = useSelector((state)=>state. + getProjectMembers.data); + console.log(alreadyExistingUsers); + const acceptedManagers = managerNames.filter((manager) =>manager.has_accepted_invite === true && + !alreadyExistingUsers.some((user) => user.id === manager.id) + ); + console.log(acceptedManagers) const filterOptions = (options, state) => { const newOptions = options.filter((user) => { const { first_name, last_name, email } = user; @@ -72,7 +79,7 @@ const AddProjectMembers = ({ { handleSelectField(newValue); diff --git a/src/common/CreateTaskDialog.jsx b/src/common/CreateTaskDialog.jsx index 8941638d..261991cb 100644 --- a/src/common/CreateTaskDialog.jsx +++ b/src/common/CreateTaskDialog.jsx @@ -62,7 +62,7 @@ const CreateTaskDialog = ({ (state) => state.getSupportedLanguages.voiceoverLanguage ); const bulkTaskTypes = useSelector((state) => state.getBulkTaskTypes.data); - +const[langLabel,setlabel] =useState("") const [taskType, setTaskType] = useState(""); const [description, setDescription] = useState(""); const [user, setUser] = useState(""); @@ -72,7 +72,10 @@ const CreateTaskDialog = ({ const [allowedTaskType, setAllowedTaskType] = useState(""); const [showAllowedTaskList, setShowAllowedTaskList] = useState(false); const [showLimitWarning, setShowLimitWarning] = useState(false); - + const [showPopup, setShowPopup] = useState(false); + const filteredMembers = projectMembers.filter((member) => + member.languages.includes(langLabel) + ); useEffect(() => { const taskObj = new FetchTaskTypeAPI(); dispatch(APITransport(taskObj)); @@ -85,6 +88,15 @@ const CreateTaskDialog = ({ // eslint-disable-next-line }, []); + useEffect(() => { + console.log(filteredMembers.length) + if (filteredMembers.length === 0) { + setShowPopup(true); + } + else{ + setShowPopup(false) + } + }, [filteredMembers]); useEffect(() => { if (taskType.length && !taskType.includes("TRANSCRIPTION")) { @@ -147,8 +159,13 @@ const CreateTaskDialog = ({ const { target: { value }, } = event; - + const selectedLanguage = translationLanguage.find( + (lang) => lang.value === event.target.value + ) || voiceoverLanguage.find( + (lang) => lang.value === event.target.value + ); setLanguage(value); + setlabel(selectedLanguage.label) if (isBulk) { const obj = new FetchProjectMembersAPI(projectId, taskType, "", value); @@ -178,7 +195,7 @@ const CreateTaskDialog = ({ }; const disableBtn = () => { - if (!taskType || !allowedTaskType) { + if (!taskType || !allowedTaskType || !user) { return true; } @@ -367,12 +384,49 @@ const CreateTaskDialog = ({ inputProps={{ "aria-label": "Without label" }} disabled={isAssignUserDropdownDisabled()} > - {projectMembers.map((item, index) => ( - - {`${item.first_name} ${item.last_name} (${item.email})`} - - ))} - + {filteredMembers.map((item, index) => ( + + {`${item.first_name} ${item.last_name} (${item.email})`} + + ))} + + {showPopup && ( +
+
+

Please add a user for the task language

+ +
+
+ )} + diff --git a/src/common/CreateVideoDialog.jsx b/src/common/CreateVideoDialog.jsx index 43196ecc..56a5e92a 100644 --- a/src/common/CreateVideoDialog.jsx +++ b/src/common/CreateVideoDialog.jsx @@ -1,4 +1,4 @@ -import React, { Fragment, useEffect } from "react"; +import React, { Fragment, useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { MenuProps } from "utils"; @@ -78,6 +78,14 @@ const CreateVideoDialog = ({ (state) => state.getSupportedLanguages.transcriptionLanguage ); + const videosInProject = useSelector((state)=>state.getProjectVideoList.data) + const [showPopup, setShowPopup] = useState(false); + useEffect(() => { + if (videosInProject.some((video) => video.url === videoLink)) { + setShowPopup(true); + } + }, [videoLink, videosInProject]); + const handleClear = () => { setLang(""); setVideoLink(""); @@ -241,6 +249,55 @@ const CreateVideoDialog = ({ onChange={(event) => setVideoLink(event.target.value)} sx={{ mt: 3 }} /> + {showPopup && ( +
+
+

This video already exists in the project. Do you want to upload it again?

+ + + +
+
+)} + Voice Selection diff --git a/src/common/DeleteDialog.jsx b/src/common/DeleteDialog.jsx index 76d004bf..bc879d7c 100644 --- a/src/common/DeleteDialog.jsx +++ b/src/common/DeleteDialog.jsx @@ -101,13 +101,13 @@ const DeleteDialog = ({ Cancel diff --git a/src/common/DeleteTaskDialog.jsx b/src/common/DeleteTaskDialog.jsx new file mode 100644 index 00000000..e6c80afd --- /dev/null +++ b/src/common/DeleteTaskDialog.jsx @@ -0,0 +1,52 @@ +import React from "react"; + +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, +} from "@mui/material"; + +const DeleteTaskDialog = ({ + openDialog, + handleClose, + submit, +}) => { + return ( + + + + Do you really want to delete this task? + + + + + + + + ); +}; + +export default DeleteTaskDialog; diff --git a/src/common/Header.jsx b/src/common/Header.jsx index 782d7341..4a2ff3e3 100644 --- a/src/common/Header.jsx +++ b/src/common/Header.jsx @@ -155,10 +155,10 @@ const Header = () => { ]; return ( - <> + {isMobile ? ( - + ) : ( { columnGap={2} rowGap={2} > - {userData?.role !== "ADMIN" && (<> + + <> { Tasks - )} + {userData?.role == "ADMIN" && + + isActive + ? `${classes.highlightedMenu} organizations` + : `${classes.headerMenu} organizations` + } + > + Admin + + } + {/* { handleClose={() => handleClose()} setOpenHelpDialog= {setOpenHelpDialog} />} - + ); }; export default Header; diff --git a/src/common/MobileNavbar.jsx b/src/common/MobileNavbar.jsx index 44c42b20..ba0aa175 100644 --- a/src/common/MobileNavbar.jsx +++ b/src/common/MobileNavbar.jsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; -import { NavLink } from "react-router-dom"; +import { NavLink, useNavigate } from "react-router-dom"; -//Style +//Styles import { headerStyle } from "styles"; //Components @@ -10,40 +10,47 @@ import { IconButton, List, ListItem, - Grid, AppBar, Divider, Avatar, Typography, Box, + Tooltip, } from "@mui/material"; import MenuIcon from "@mui/icons-material/Menu"; +import HourglassBottomIcon from "@mui/icons-material/HourglassBottom"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; -function MobileNavbar({ UserMenu, SettingsMenu }) { +function MobileNavbar({ UserMenu, SettingsMenu, userData }) { const [openDrawer, setOpenDrawer] = useState(false); const classes = headerStyle(); + const navigate = useNavigate(); const tabs = [ { name: "Organizations", onClick: () => { + navigate(`/my-organization/${userData?.organization?.id}`); setOpenDrawer(false); }, }, { - name: "project", + name: "Tasks", onClick: () => { + navigate(`/task-list`); setOpenDrawer(false); }, }, - { - name: "workspace", - onClick: () => { - setOpenDrawer(false); - }, - }, - ]; - + userData?.role === "ADMIN" + ? { + name: "Admin", + onClick: () => { + navigate(`/admin`); + setOpenDrawer(false); + }, + } + : null, + ].filter(Boolean); return ( <> @@ -62,51 +70,45 @@ function MobileNavbar({ UserMenu, SettingsMenu }) { justifyContent: "space-between", height: "100%", paddingBottom: "16px", + }} > - setOpenDrawer(false)} + - + {userData?.first_name?.charAt(0)} + + - - U - - - User - - - + {userData?.first_name} {userData?.last_name} + + - + {tabs.map((tab, index) => ( - setOpenDrawer(false)}> - + + - - - App Settings + + {userData?.role === "ADMIN" || + userData?.role === "ORG_OWNER" || + userData?.role === "PROJECT_MANAGER" ? ( + { + navigate("/task-queue-status"); + setOpenDrawer(false); + }} + className={`${classes.icon} help`} + > + + + + + ) : ( + "" + )} + + { + // Assuming handleClickHelp is a function to open the help dialog + navigate("/help"); + setOpenDrawer(false); + }} + className={`${classes.icon} help`} + > + + + + + + {/* {SettingsMenu.map((setting, index) => ( - + { + setting.onClick(); + setOpenDrawer(false); + }}> ))} - + */} { - setting.onclick(); + setting.onClick(); setOpenDrawer(false); }} > @@ -177,6 +215,7 @@ function MobileNavbar({ UserMenu, SettingsMenu }) { color: "black", fontSize: "1rem", fontWeight: "400", + cursor:"pointer" }} > {setting.name} @@ -189,13 +228,12 @@ function MobileNavbar({ UserMenu, SettingsMenu }) { - @@ -205,22 +243,23 @@ function MobileNavbar({ UserMenu, SettingsMenu }) { className={classes.headerLogo} /> - Chitralekha + Chitralekha - + Powered by EkStep Foundation - - setOpenDrawer(!openDrawer)}> - - - - + setOpenDrawer(!openDrawer)}> + + + ); } + export default MobileNavbar; diff --git a/src/config/taskItems.js b/src/config/taskItems.js index 8085027b..91c55ef2 100644 --- a/src/config/taskItems.js +++ b/src/config/taskItems.js @@ -6,6 +6,7 @@ export const taskStatus = [ { value: "COMPLETE", label: "Complete" }, { value: "FAILED", label: "Failed" }, { value: "REOPEN", label: "Reopen" }, + { value: "PARAPHRASE", label: "Paraphrase" }, ]; export const taskTypes = [ diff --git a/src/containers/Admin/OrganizationList.jsx b/src/containers/Admin/OrganizationList.jsx index 5a538f65..d59108f1 100644 --- a/src/containers/Admin/OrganizationList.jsx +++ b/src/containers/Admin/OrganizationList.jsx @@ -12,14 +12,19 @@ import { TableStyles } from "styles"; import { Box, IconButton, ThemeProvider, Tooltip } from "@mui/material"; import MUIDataTable from "mui-datatables"; import DeleteIcon from "@mui/icons-material/Delete"; +import ArchiveIcon from "@mui/icons-material/Archive"; +import UnarchiveIcon from "@mui/icons-material/Unarchive"; import EditIcon from "@mui/icons-material/Edit"; +import VisibilityIcon from "@mui/icons-material/Visibility"; import { DeleteDialog } from "common"; //APIs import { APITransport, - DeleteOrganizationAPI, + ArchiveOrganizationAPI, + UnarchiveOrganizationAPI, FetchOrganizationListAPI, + DeleteOrganizationAPI, } from "redux/actions"; const OrganizationList = () => { @@ -30,20 +35,23 @@ const OrganizationList = () => { const orgList = useSelector((state) => state.getOrganizationList.data); const apiStatus = useSelector((state) => state.apiStatus); - const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [dialogOpen, setDialogOpen] = useState(false); const [currentOrgId, setCurrentOrgId] = useState(""); + const [isArchived, setIsArchived] = useState(false); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); useEffect(() => { const { progress, success, apiType } = apiStatus; if (!progress) { if (success) { - if (apiType === "DELETE_ORGANIZATION") { + if (apiType === "ARCHIVE_ORGANIZATION" || apiType === "UNARCHIVE_ORGANIZATION") { getOrgList(); } } setDeleteDialogOpen(false); + } // eslint-disable-next-line @@ -59,6 +67,12 @@ const OrganizationList = () => { // eslint-disable-next-line }, []); + const handleArchiveUnarchive = async () => { + setIsArchived(false) + setDialogOpen(false) + }; + const userData = useSelector((state) => state.getLoggedInUserDetails.data); + const columns = getColumns(adminOrgListColumns); columns.push({ name: "Action", @@ -71,19 +85,33 @@ const OrganizationList = () => { className: classes.cellHeaderProps, }), customBodyRender: (_value, tableMeta) => { + const rowIndex = tableMeta.rowIndex; + const archived = orgList[rowIndex]?.archived || false; + return ( + + { + navigate(`/my-organization/${orgList[rowIndex]?.id}`); + }} + // disabled={archived} + > + + + + { - navigate(`/admin/edit-organization/${tableMeta.rowData[0]}`); + navigate(`/admin/edit-organization/${orgList[rowIndex]?.id}`); }} + // disabled={archived} > - - + {/* { setDeleteDialogOpen(true); @@ -92,13 +120,28 @@ const OrganizationList = () => { > - + */} + + {/* + { + setDialogOpen(true); + setCurrentOrgId(orgList[rowIndex]?.id); + setIsArchived(archived); + }} + > + {archived ? ( + + ) : ( + + )} + + */} ); }, }, }); - const handleDelete = async (currentOrgId) => { const apiObj = new DeleteOrganizationAPI(currentOrgId); dispatch(APITransport(apiObj)); @@ -114,17 +157,29 @@ const OrganizationList = () => { /> - {deleteDialogOpen && ( + {deleteDialogOpen && ( setDeleteDialogOpen(false)} - submit={() => handleDelete(currentOrgId)} - message={`Are you sure, you want to delete this Organization? All the associated videos, tasks, will be deleted.`} - loading={apiStatus.loading} + openDialog={deleteDialogOpen} + handleClose={() => setDeleteDialogOpen(false)} + submit={() => handleDelete(currentOrgId)} + message={`Are you sure, you want to delete this Organization? All the associated videos, tasks, will be deleted.`} + loading={apiStatus.loading} /> + )} ); }; export default OrganizationList; + + +{/* setDialogOpen(false)} + submit={handleArchiveUnarchive} + message={`Are you sure you want to ${isArchived ? "unarchive" : "archive"} this organization?`} + loading={apiStatus.loading} + confirmText={isArchived ? "Unarchive" : "Archive"} + closeText="Close" + /> */} \ No newline at end of file diff --git a/src/containers/Organization/MyOrganization.jsx b/src/containers/Organization/MyOrganization.jsx index 0984ef40..54b85cc3 100644 --- a/src/containers/Organization/MyOrganization.jsx +++ b/src/containers/Organization/MyOrganization.jsx @@ -71,6 +71,7 @@ const MyOrganization = () => { const [orgOwnerId, setOrgOwnerId] = useState(""); const [openUploadBulkVideoDialog, setOpenUploadBulkVideoDialog] = useState(false); + const [isUserOrgOwner, setIsUserOrgOwner] = useState(false); const organizationDetails = useSelector( (state) => state.getOrganizationDetails.data @@ -135,10 +136,19 @@ const MyOrganization = () => { if (userData && userData.id) { const { - organization: { organization_owner }, + organization: { organization_owners }, } = userData; - - setOrgOwnerId(organization_owner.id); + + if (organization_owners && organization_owners?.length > 0) { + const ownerIds = organization_owners.map(owner => owner.id); + setOrgOwnerId(ownerIds); + + if (ownerIds.includes(userData.id)) { + setIsUserOrgOwner(true); + } else { + setIsUserOrgOwner(false); + } + } } // eslint-disable-next-line }, [userData]); @@ -190,16 +200,16 @@ const MyOrganization = () => { > - {roles.filter((role) => role.value === userData?.role)[0] + { roles.filter((role) => role.value === userData?.role)[0] ?.canAddMembers && ( )} - {userData?.id === orgOwnerId && ( + {(isUserOrgOwner|| userData?.role==="ADMIN") &&( )} - {userData?.id === orgOwnerId && ( + {(isUserOrgOwner || userData?.role==="ADMIN")&&( { alignItems="center" > - {userData?.id === orgOwnerId && ( + {(isUserOrgOwner|| userData?.role==="ADMIN") && ( + */} @@ -323,7 +337,7 @@ const EditProject = () => { !( projectDetails?.managers?.some( (item) => item.id === userData.id - ) || userData?.id === orgOwnerId + ) ||isUserOrgOwner || userData?.role==="ADMIN" ) } /> @@ -344,7 +358,7 @@ const EditProject = () => { !( projectDetails?.managers?.some( (item) => item.id === userData.id - ) || userData?.id === orgOwnerId + ) || isUserOrgOwner || userData?.role==="ADMIN" ) } renderValue={(selected) => { @@ -392,7 +406,7 @@ const EditProject = () => { !( projectDetails?.managers?.some( (item) => item.id === userData.id - ) || userData?.id === orgOwnerId + ) || isUserOrgOwner || userData?.role==="ADMIN" ) } > @@ -423,7 +437,7 @@ const EditProject = () => { !( projectDetails?.managers?.some( (item) => item.id === userData.id - ) || userData?.id === orgOwnerId + ) ||isUserOrgOwner || userData?.role==="ADMIN" ) } > @@ -454,7 +468,7 @@ const EditProject = () => { !( projectDetails?.managers?.some( (item) => item.id === userData.id - ) || userData?.id === orgOwnerId + ) || isUserOrgOwner || userData?.role==="ADMIN" ) } > @@ -467,6 +481,23 @@ const EditProject = () => { + + + + Paraphrasing Stage + + + + + Default Workflow @@ -481,7 +512,7 @@ const EditProject = () => { !( projectDetails?.managers?.some( (item) => item.id === userData.id - ) || userData?.id === orgOwnerId + ) || isUserOrgOwner || userData?.role==="ADMIN" ) } MenuProps={MenuProps} @@ -568,7 +599,7 @@ const EditProject = () => { !( projectDetails?.managers?.some( (item) => item.id === userData.id - ) || userData?.id === orgOwnerId + ) ||isUserOrgOwner || userData?.role==="ADMIN" ) } renderInput={(params) => } @@ -593,7 +624,7 @@ const EditProject = () => { !( projectDetails?.managers?.some( (item) => item.id === userData.id - ) || userData?.id === orgOwnerId + ) || isUserOrgOwner || userData?.role==="ADMIN" ) } renderValue={(selected) => { @@ -618,7 +649,7 @@ const EditProject = () => { {(projectDetails?.managers?.some( (item) => item.id === userData.id ) || - userData?.id === orgOwnerId) && ( + isUserOrgOwner) && (