I have a PR-issue linker program. In the links screen, where I show a table of PRs, when clicking on a PR, a dialog appears with a list of issues, for that specific PR. In that dialog, I have an Add another issue button to add another issue to the issues list.
The problem is, when a new issue is added, it doesn’t appear on the issues list, until I close the dialog and reopen. What should I do to update the list of issues when I add another issue to the list. Currently, I need to close and reopen the dialog, which is not a good UX.
Due to the poor design in the early stages, I am dealing with 5 JS files. Here are them:
The screen (1st JS file):
function PossibleLinks() {
const location = useLocation();
const id = location.state.id;
const projectId = location.state.projectId;
const [repos, setRepos] = useState([]);
const [selectedRepo, setSelectedRepo] = useState(null);
const [jiraRepoId, setJiraRepoId] = useState(0);
const [rowCount, setRowCount] = useState(10);
useEffect(() => {
getRepos();
}, []);
useEffect(() => {
getJiraRepoId();
}, 0);
const getRepos = async () => {
const res = await getRepositories(projectId);
setRepos(res.filter((item) => item.platform !== "jira"));
setSelectedRepo(res[0].id);
};
const getJiraRepoId = async () => {
const res = await getRepositories(projectId);
for (let i = 0; i < res.length; i++) {
if (res[i].platform === "jira") {
setJiraRepoId(res[i].id);
break;
}
}
};
return (
<div className="project">
<Sidebar2 id={id} projectId={projectId}></Sidebar2>
<div className="projectContainer">
<h2 className="title" align="left">
Possible Links
</h2>
>
{selectedRepo !== null && (
<PossibleLinksData
projectId={projectId}
jrId={jiraRepoId}
rId={selectedRepo}
rowCount={rowCount}
>
</PossibleLinksData>
)}
</div>
</div>
);
}
export default PossibleLinks;
The data (2nd JS file):
function PossibleLinksData({ jrId, rId, rowCount }) {
const location = useLocation();
const projectId = location.state.projectId;
const [data, setData] = useState(null);
const [currentPageNo, setCurrentPageNo] = useState(1);
const [lastPageNo, setLastPageNo] = useState();
useEffect(() => {
getPossLinks();
setCurrentPageNo(1)
}, [rId, rowCount]);
const getPossLinks = async () => {
const res = await getPossibleLinks(projectId, rId, rowCount);
setLastPageNo(Math.ceil(res.count / rowCount));
setData(res);
};
const getPossLinksByPage = async (pageNo = currentPageNo) => {
console.log("1 getPossLinksByPage --- ");
const res = await getPossibleLinksByPage(projectId, rId, pageNo, rowCount);
setData(res);
};
const handleChange = (event, value) => {
setCurrentPageNo(value);
getPossLinksByPage(value);
};
return (
<div sx={{ minWidth: 700 }}>
{data !== null ? (
<PossibleLinksTable
data={data.results}
rId={rId}
jrId={jrId}
getPossLinksByPage={getPossLinksByPage}
></PossibleLinksTable>
) : null}
{data !== null ? (
<Pagination
count={lastPageNo}
page={currentPageNo}
onChange={handleChange}
/>
) : null}
</div>
);
}
export default PossibleLinksData;
The Table of PRs (3rd JS file):
function PossibleLinksTable({ data, rId, jrId, getPossLinksByPage }) {
const location = useLocation();
const projectId = location.state.projectId;
const [formattedData, setFormattedData] = useState([]);
const [filteredData, setFilteredData] = useState([]); // filtered data
const [openDialog, setOpenDialog] = useState(false);
const [selected, setSelected] = useState(null);
useEffect(() => {
// formatting the data here
setFormattedData(data);
}, [data]);
useEffect(() => {
if (selected !== null) setOpenDialog(true);
}, [selected]);
return (
<div sx={{ minWidth: 700 }}>
<Box sx={{ minWidth: 700 }}>
<TableContainer sx={{ minWidth: 700 }}>
<Table size="small" sx={{ minWidth: 700 }}>
<TableHead sx={{ minWidth: 700 }}>
// some table heads here
</TableHead>
{formattedData.length !== 0 ? (
<TableBody>
{formattedData.map((item, index) => (
<TableRow>
// some table cells here
<TableCell align="center">
<IconButton
sx={{ color: "white" }}
onClick={() => setSelected(item)}
>
<AddLinkIcon></AddLinkIcon>
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
) : (
<TableBody></TableBody>
)}
</Table>
</TableContainer>
{selected && (
<PossibleLinksCards
item={selected}
open={openDialog}
close={handleCloseDialog}
rId={rId}
jrId={jrId}
getPossLinksByPage={getPossLinksByPage}
></PossibleLinksCards>
)}
</Box>
</div>
);
}
export default PossibleLinksTable;
The dialog (4th JS file):
function PossibleLinksCards({
item,
open,
close,
rId,
jrId,
getPossLinksByPage,
}) {
const [selectedIssues, setSelectedIssues] = useState([]);
const [selectedRanks, setSelectedRanks] = useState([]);
const location = useLocation();
const [hasAccess, setHasAccess] = useState(false);
const [alertOpen, setAlertOpen] = useState(false);
const [mes, setMes] = useState("");
const [isFailed, setIsFailed] = useState(false);
const projectId = location.state.projectId;
const [selected, setSelected] = useState(null);
const [openDialog, setOpenDialog] = useState(false);
useEffect(() => {
getCurrentProject();
}, []);
const getCurrentProject = async () => {
const res = await getProject(projectId);
setHasAccess(res.user_role === "PM");
};
useEffect(() => {
// formatting issues
}, [item]);
const handleSelected = (index) => {
// handling the selected issues array
};
useEffect(() => {
console.log(selectedIssues);
console.log(selectedRanks);
}, [selectedIssues, selectedRanks]);
useEffect(() => {
if (selected !== null) setOpenDialog(true);
}, [selected]);
const handleCloseDialog = () => {
setOpenDialog(false);
setSelected(null);
};
return (
<Dialog open={open} onClose={close}>
<DialogContent>
<DialogContentText>
<TableContainer>
<Table sx={{ minWidth: 650 }} size="small">
<TableHead>
// some table heads
</TableHead>
<TableBody>
{item.possible_links.map((link, index) => (
<TableRow>
//some table cells
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</DialogContentText>
</DialogContent>
<DialogActions
>
<Button
disabled={!hasAccess}
onClick={() => setSelected(item)}
>
Add Another Issue
</Button>
{selected && (
<AddAnotherIssueCard
item={selected}
open={openDialog}
close={handleCloseDialog}
rId={rId}
jrId={jrId}
getPossLinksByPage={getPossLinksByPage}
></AddAnotherIssueCard>
)}
</DialogActions>
</Dialog>
);
}
export default PossibleLinksCards;
The Add Another Issue Dialog (5th JS file):
function AddAnotherIssueCard({
item,
open,
close,
rId,
jrId,
getPossLinksByPage,
}) {
const location = useLocation();
const [hasAccess, setHasAccess] = useState(false);
const projectId = location.state.projectId;
const [selected, setSelected] = useState(null);
const [text, setText] = useState("");
const [openDialog, setOpenDialog] = useState(false);
const [issues, setIssues] = useState([null]);
useEffect(() => {
getCurrentProject();
}, []);
const getCurrentProject = async () => {
const res = await getProject(projectId);
setHasAccess(res.user_role === "PM");
};
useEffect(() => {
if (selected !== null) setOpenDialog(true);
}, [selected]);
const getIssues = async () => {
const res = await getIssuesById(projectId, jrId, text);
if (res.length !== 0) {
setIssues(res);
} else {
setIssues([null]);
}
};
const handleRelinkClick = async () => {
if (issues[0] === null) {
console.log("Please select an issue");
} else {
const body = {
pull_request: item.id,
issue: issues[0].id,
};
const res = await addAnotherIssue(projectId, rId, body);
setTimeout(close, 500);
await getPossLinksByPage();
}
};
return (
<div>
<Dialog open={open} onClose={close}>
<DialogContent>
// Here I GET the issue object.
</DialogContent>
<DialogActions>
<Button
disabled={!hasAccess}
variant="contained"
color="success"
onClick={handleRelinkClick}
>
ADD
</Button>
</DialogActions>
</Dialog>
</div>
);
}
export default AddAnotherIssueCard;