Untitled
unknown
plain_text
2 years ago
16 kB
6
Indexable
import React, { useEffect, useState, useContext } from "react";
import Breadcrumbs, { BreadcrumbsItem } from "@atlaskit/breadcrumbs";
import { Dropdown, Menu, message, Space } from "antd";
import { DownOutlined, UserOutlined } from "@ant-design/icons";
import ArrowUpCircleIcon from "@atlaskit/icon/glyph/arrow-up-circle";
import HomeIcon from "@atlaskit/icon/glyph/home";
import Select from "../SelectBox";
import { Link, useLocation, useNavigate } from "react-router-dom";
import PropTypes from "prop-types";
import CreateJournalModal from "../Modals/CreateJournalModal";
import UpdateBadge from "@atlaskit/badge";
import { router } from "@forge/bridge";
import ReportsDrawer from "../Reports Drawer";
import SettingsDrawer from "../SettingsDrawer";
import ExportComponent from "../Export";
import Button from "@atlaskit/button/standard-button";
import UpArrowIcon from "../../assets/Images/arrow-up.svg";
import PlaceHolderImage from "../../assets/Images/homePagePlaceHolder.svg";
import AddIcon from "../../assets/Images/addIcon.svg";
import drawerIcon from "../../assets/Images/minimizeIcon.svg";
import exportIcon from "../../assets/Images/exportIcon.svg";
import refreshIcon from "../../assets/Images/refresh.svg";
import dots from "../../assets/Images/threeDotIcon.svg";
import Loading from "../PageLoader";
import { MyContext } from "../../context/useContext";
import {
getIssues,
getIssuesByPriority,
getCreatedVsResolvedIssues,
getUnReleasedVersions,
getAllSprints,
getStoryPointsKey,
getUpdatesOfLastViewedJorunals,
getStatuses,
getFields,
} from "../../components/persistence/utils/JiraUtils";
import { getJournals } from "../../components/persistence/utils/StorageUtils";
import Reports from "../Tabs/Reports";
import Updates from "../Tabs/Updates";
import { useDetails } from "../../hooks/useDetails";
import { useRequestJira } from "../../hooks/useRequestJira";
import {
GET_MYSELF_QUERY,
DEFAULT_CREATED_VS_RESOLVED_DAYS,
} from "../../constants";
import SettingsIcon from "@atlaskit/icon/glyph/settings";
import ExportIcon from "@atlaskit/icon/glyph/export";
import GraphBarIcon from "@atlaskit/icon/glyph/graph-bar";
import MediaServicesAddCommentIcon from "@atlaskit/icon/glyph/media-services/add-comment";
import {
UPDATES_TAB_TEXT,
REPORTS_TAB_TEXT,
SETTINGS_TAB_TEXT,
PROJECT_HUB,
PROJECT_HOME_PAGE,
SCROLL_TO_THE_TOP_LABEL,
REFRESH,
EXPORT,
ADD_REPORTS,
PLEASE_SELECT_A_HUB,
YOU_DONT_HAVE_ANY_HUBS,
NOTIFICATION_LABEL,
ERROR_LABEL,
YOU_HAVE_SUCCESSFULLY_CREATED_LABEL,
ERROR_CREATING_THE_REPORT_LABEL,
NEW_COPY_HUB,
NEW_HUB,
COPY_HUB,
DELETE_HUB,
} from "../../messages";
import { Flex, Text } from "../Basic";
import Tooltip from "../Tooltip";
import { getReportQuery } from "../persistence/utils/ReportQuery";
import Modal from "antd/es/modal/Modal";
import Notification from "antd/lib/notification";
import { successfulNotification, errorNotification } from "../Notification";
import DeleteModal from "../journalListDelete";
const DetailsPage = () => {
const [user, setUser] = useState(null);
const [selectedTab, setSelectedTab] = useState(0);
const { search } = useLocation();
const [loading, setLoading] = useState(false);
const [updateBadges, setUpdateBadges] = useState(null);
const [showExport, setShowExport] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [journal, setJournal] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [reportsDrawerOpen, setReportsDrawerOpen] = useState(false);
const [journalToBeDuplicated, setJournalToBeDuplicated] = useState(null);
const [settingsDrawerOpen, setSettingsDrawerOpen] = useState(false);
const [api, contextHolder] = Notification.useNotification();
const [dropDownOpen, setDropDownOpen] = useState(false);
const [deleteModal, setDeleteModal] = useState(false);
const {
addId,
addSprints,
setStoryPointsKey,
addFields,
addStatuses,
id,
currentJournal,
addCurrentJournal,
journals,
addUser,
addJournals,
minAllReports,
} = useContext(MyContext);
const { projectKey } = useDetails();
useEffect(() => {
if (projectKey) {
setIsLoading(true);
getJournals(projectKey)
.then((data) => {
addJournals(data);
})
.finally(() => {
setIsLoading(false);
});
}
}, [projectKey]);
useEffect(() => {
const savedId = localStorage.getItem("selectedJournalId");
if (savedId) {
addId(savedId);
addCurrentJournal(journals?.find((journal) => journal.id === savedId));
}
}, [journals]);
useEffect(() => {
if (journals.length > 0 && id) {
if (journals?.find((journal) => journal.id === id)) {
addCurrentJournal(journals?.find((journal) => journal.id === id));
}
}
}, [id]);
useEffect(() => {
localStorage.setItem("selectedJournalId", id);
}, [id]);
useEffect(() => {
useRequestJira(GET_MYSELF_QUERY).then((res) => addUser(res.accountId));
}, []);
const [showScrollButton, setShowScrollButton] = useState(false);
const scrollToTopButton = document.getElementById("scrollToTopButton");
window.onscroll = function () {
scrollFunction();
};
function scrollFunction() {
if (
document.body.scrollTop > 50 ||
document.documentElement.scrollTop > 50
) {
scrollToTopButton.style.display = "block";
} else {
scrollToTopButton.style.display = "none";
}
}
const handleScroll = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
setShowScrollButton(scrollTop > 0);
};
const handleScrollToTop = () => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
};
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
useEffect(() => {
setJournal(currentJournal);
}, [journals, currentJournal]);
useEffect(() => {
if (search.includes("settings")) {
journal?.settings?.updates ? setSelectedTab(3) : setSelectedTab(2);
} else if (search.includes("exports")) {
journal?.settings?.updates ? setSelectedTab(2) : setSelectedTab(1);
}
}, [search, journal?.settings]);
useEffect(() => {
useRequestJira(GET_MYSELF_QUERY).then((res) => setUser(res.accountId));
if (projectKey) {
fetchAllData(
addSprints,
setStoryPointsKey,
addFields,
addStatuses,
);
}
if (journals && user) {
getUpdatesOfLastViewedJorunals(journals, user).then((res) => {
setUpdateBadges(res);
});
}
}, [projectKey, id, user]);
const handleRefresh = () => {
router.reload();
};
const onClick = ({ key }) => {
switch (key) {
case "configure":
setSettingsDrawerOpen(true);
setDropDownOpen(false);
break;
case "copyHub":
setIsModalOpen(true);
setJournalToBeDuplicated(currentJournal);
setDropDownOpen(false);
break;
case "deleteHub":
setDeleteModal(true);
setDropDownOpen(false);
break;
default:
break;
}
};
const items = [
{
label: "Configure",
key: "configure",
},
{
label: "Copy hub",
key: "copyHub",
},
{
label: "Delete hub",
key: "deleteHub",
},
];
return (
<Flex
alignItems="flex-start"
flexDirection="column"
width="96vw"
height="fit-content"
>
{isModalOpen && (
<CreateJournalModal
isModalOpen={isModalOpen}
ModalCloseHandler={() => setIsModalOpen(!isModalOpen)}
journalToBeDuplicated={journalToBeDuplicated}
setJournalToBeDuplicated={setJournalToBeDuplicated}
/>
)}
{deleteModal && (
<DeleteModal
loading={loading}
setLoading={setLoading}
journal={currentJournal}
setDeleteModal={setDeleteModal}
/>
)}
{contextHolder}
<Flex justifyContent="space-between" gap="10px">
<Flex
flexDirection="column"
width="fit-content"
gap="10px"
alignItems="flex-start"
>
<Flex width="fit-content" gap="10px">
{journals.length > 0 && (
<Select
value={id}
loading={isLoading}
onChange={(value) => {
addId(value);
}}
options={journals?.map((journal) => {
return {
label: journal.name,
value: journal.id,
};
})}
defaultValue={journal?.id}
width="300px"
placeholder={PROJECT_HOME_PAGE}
/>
)}
<Button
style={{
background: " #FFAB00",
color: "#000",
}}
onClick={() => setIsModalOpen(true)}
>
<Flex gap="5px" style={{ color: "#172B4D" }}>
{NEW_HUB}
</Flex>
</Button>
</Flex>
<Text fontSize="25px" fontWeight="400">
{currentJournal &&
Object.keys(currentJournal).length > 0 &&
currentJournal?.name}
</Text>
</Flex>
<Flex width="fit-content" gap="10px"></Flex>
</Flex>
<br />
{id && (
<ReportsDrawer
open={reportsDrawerOpen}
onClose={() => setReportsDrawerOpen(false)}
journal={journal || currentJournal || {}}
api={api}
successfulNotification={successfulNotification}
errorNotification={errorNotification}
/>
)}
{id && (
<SettingsDrawer
open={settingsDrawerOpen}
onClose={() => setSettingsDrawerOpen(false)}
setSettingsDrawerOpen={setSettingsDrawerOpen}
journal={journal || currentJournal || {}}
/>
)}
{(settingsDrawerOpen || reportsDrawerOpen) && (
<div
onClick={() => {
setSettingsDrawerOpen(false);
setReportsDrawerOpen(false);
}}
style={{
inset: "0px",
position: "fixed",
height: "100vh",
width: "100vw",
zIndex: "100",
backgroundColor: "rgba(0,0,0,0.5)",
}}
></div>
)}
<div
style={{
position: "fixed",
top: "20px",
right: "20px",
gap: "20px",
zIndex: "100",
backgroundColor: "white",
display: "flex",
flexDirection: "column",
width: "fit-content",
}}
>
<div
style={{
background: dropDownOpen ? "#EBECF0" : "transparent",
borderRadius: "5px",
width: "32px",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.3s ease-in-out",
cursor: "pointer",
marginBottom: "40px",
}}
>
<Dropdown
onOpenChange={(open) => {
setDropDownOpen(open);
}}
trigger={["click"]}
menu={{ items, onClick }}
>
<img
src={dots}
alt="dots"
style={{
cursor: id ? "pointer" : "not-allowed",
filter: !id && "invert(0.6)",
transform: "rotate(90deg)",
}}
/>
</Dropdown>
</div>
<div onClick={() => setReportsDrawerOpen(true)}>
<img
src={AddIcon}
alt="drawerIcon"
style={{
cursor: id ? "pointer" : "not-allowed",
filter: !id && "invert(0.6)",
}}
/>
</div>
<div onClick={handleRefresh}>
<img
src={refreshIcon}
alt="refreshIcon"
style={{
cursor: id ? "pointer" : "not-allowed",
filter: !id && "invert(0.6)",
}}
/>
</div>
<div
onClick={() => {
setShowExport(true);
}}
>
<img
src={exportIcon}
alt="exportIcon"
style={{
cursor: id ? "pointer" : "not-allowed",
filter: !id && "invert(0.6)",
}}
/>
</div>
<div
onClick={() => {
minAllReports();
}}
>
<img
src={drawerIcon}
alt="dots"
style={{
cursor: id ? "pointer" : "not-allowed",
filter: !id && "invert(0.6)",
}}
/>
</div>
</div>
<div
id="scrollToTopButton"
onClick={handleScrollToTop}
style={{
position: "fixed",
bottom: "100px",
right: "20px",
zIndex: "100",
backgroundColor: "white",
display: "block",
width: "fit-content",
}}
>
<img
src={UpArrowIcon}
alt="UpArrowIcon"
style={{
cursor: id ? "pointer" : "not-allowed",
filter: !id && "invert(0.6)",
}}
/>
</div>
{id && !isLoading && (
<div
style={{
marginBottom: "100px",
}}
>
{journal && Object.keys(journal).length > 0 && (
<Reports isLoading={isLoading} journal={journal} />
)}
</div>
)}
<Modal
visible={showExport}
onCancel={() => setShowExport(false)}
footer={null}
width="fit-content"
style={{
top: "10px",
}}
>
<ExportComponent />
</Modal>
{isLoading ? (
<div style={{ position: "absolute", top: "40%", left: "50%" }}>
<Loading size="xlarge" appearance="inherit" />
</div>
) : (
!isLoading &&
!id && (
<Flex alignItems="center" justifyContent="center" height="80vh">
<Flex
flexDirection="column"
alignItems="center"
justifyContent="center"
gap="10px"
height="fit-content"
width="fit-content"
>
<img src={PlaceHolderImage} alt="Group-1" border="0" />
{journals.length == 0 || !journal ? (
<Text
style={{
textAlign: "center",
fontWeight: "bold",
}}
>{YOU_DONT_HAVE_ANY_HUBS}</Text>
) : (
<Text
style={{
textAlign: "center",
fontWeight:'bold'
}}
>{PLEASE_SELECT_A_HUB}</Text>
)}
</Flex>
</Flex>
)
)}
</Flex>
);
};
export default DetailsPage;
DetailsPage.propTypes = {
setPages: PropTypes.func,
pages: PropTypes.array,
name: PropTypes.string,
path: PropTypes.string,
element: PropTypes.element,
key: PropTypes.string,
match: PropTypes.object,
};
const fetchAllData = async (
addSprints,
setStoryPointsKey,
addFields,
addStatuses,
) => {
const promises = [];
promises.push(
getStoryPointsKey().then((data) => {
setStoryPointsKey(data);
})
);
promises.push(
getFields().then((data) => {
addFields(data);
})
);
promises.push(
getStatuses().then((data) => {
addStatuses(data);
})
);
promises.push(
getAllSprints().then((data) => {
addSprints(data);
})
);
try {
await Promise.all(promises);
} catch (error) {
console.error("An error occurred:", error);
}
};
Editor is loading...