Skip to content

Commit 8c089e5

Browse files
authored
[WEB-20] Clicking on folder pill in breadcrumb path redirects user to that folder (#343)
* initial testing commit * implemented clicking on breadcrumb pill redirects you to desired page using ids on pathList, corrected display of files when navigating back to root directory after exiting file view * commented in types.ts and Directory.tsx the reasoning behind the following additions
1 parent b3d004f commit 8c089e5

File tree

5 files changed

+104
-57
lines changed

5 files changed

+104
-57
lines changed

frontend/src/packages/dashboard/Dashboard.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ import { Breadcrumbs, Link } from "@mui/material";
66
// local imports
77
import SideBar from "src/packages/dashboard/components/SideBar/SideBar";
88
import Renderer from "./components/FileRenderer/Renderer";
9-
import { initAction, traverseBackFolder } from "./state/folders/actions";
9+
import {
10+
initAction,
11+
traverseBackFolder,
12+
traverseIntoFolder,
13+
} from "./state/folders/actions";
1014
import ConfirmationWindow from "./components/ConfirmationModal/ConfirmationWindow";
1115
import Directory from "./components/Directory";
16+
import { getFolderState } from "./api/helpers";
1217

1318
const Container = styled.div`
1419
display: flex;
@@ -33,12 +38,12 @@ export default function Dashboard() {
3338
);
3439

3540
const [selectedFile, setSelectedFile] = useState<string | null>(null);
36-
// const parentFolder = getFolderState().parentFolder;
41+
const parentFolder = getFolderState().parentFolder;
3742
const dispatch = useDispatch();
38-
3943
useEffect(() => {
4044
// fetches all folders and files from backend and displays it
41-
dispatch(initAction());
45+
// dispatch(initAction());
46+
dispatch(traverseIntoFolder(parentFolder));
4247
}, []);
4348

4449
return (

frontend/src/packages/dashboard/components/Directory.tsx

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from "react";
1+
import React, { useEffect } from "react";
22
import { Breadcrumbs } from "@mui/material";
33
import Chip from "@mui/material/Chip";
44
import { emphasize, styled as customStyle } from "@mui/material/styles";
@@ -7,8 +7,12 @@ import { useDispatch } from "react-redux";
77
import IconButton from "@mui/material/IconButton";
88
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
99

10-
import { traverseBackFolder } from "../state/folders/actions";
10+
import {
11+
traverseBackFolder,
12+
traverseIntoFolder,
13+
} from "../state/folders/actions";
1114
import { getFolderState } from "../api/helpers";
15+
import { PathObject } from "../state/folders/types";
1216

1317
const DirectoryFlex = styled.div`
1418
display: flex;
@@ -22,9 +26,10 @@ const DirectoryFlex = styled.div`
2226

2327
const BreadcrumbItem = customStyle(Chip)(({ theme }) => {
2428
const backgroundColor =
25-
theme.palette.mode === 'light'
29+
theme.palette.mode === "light"
2630
? theme.palette.grey[200]
2731
: theme.palette.grey[800];
32+
2833
return {
2934
backgroundColor,
3035
height: theme.spacing(3),
@@ -40,25 +45,44 @@ const BreadcrumbItem = customStyle(Chip)(({ theme }) => {
4045
};
4146
});
4247

48+
// Wrapper used for breadcrumb to individualise onClick for each pill
49+
type BreadcrumbItemWrapperProps = {
50+
folderObject: PathObject;
51+
};
52+
53+
const BreadcrumbItemWrapper = ({
54+
folderObject,
55+
}: BreadcrumbItemWrapperProps) => {
56+
const dispatch = useDispatch();
57+
const handleClickBreadcrumbItem = () => {
58+
dispatch(traverseIntoFolder(folderObject.folderId));
59+
};
60+
return (
61+
<div>
62+
<BreadcrumbItem
63+
label={folderObject.folderName}
64+
onClick={handleClickBreadcrumbItem}
65+
/>
66+
</div>
67+
);
68+
};
69+
4370
export default function Directory() {
4471
const dispatch = useDispatch();
4572
const parentFolder = getFolderState().parentFolder;
4673

4774
const handleClick = () => {
4875
dispatch(traverseBackFolder(parentFolder));
4976
};
50-
5177
return (
5278
<DirectoryFlex>
5379
<IconButton aria-label="back" onClick={() => handleClick()}>
5480
<ArrowBackIcon fontSize="inherit" />
5581
</IconButton>
5682
<Breadcrumbs aria-label="breadcrumb">
57-
{getFolderState()
58-
.path.split("/")
59-
.map((folder, i) => {
60-
return <BreadcrumbItem key={i} label={folder} />;
61-
})}
83+
{getFolderState().path.map((folderObject, i) => {
84+
return <BreadcrumbItemWrapper folderObject={folderObject} key={i} />;
85+
})}
6286
</Breadcrumbs>
6387
</DirectoryFlex>
6488
);

frontend/src/packages/dashboard/state/folders/initial-state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ const ROOT_UUID = "00000000-0000-0000-0000-000000000000";
44

55
export const initialState: sliceState = {
66
parentFolder: ROOT_UUID,
7-
path: "root",
7+
path: [{ folderName: "root", folderId: ROOT_UUID }],
88
items: [],
99
};

frontend/src/packages/dashboard/state/folders/reducers.ts

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,90 @@
1-
import { PayloadAction } from '@reduxjs/toolkit';
2-
import { RenamePayloadType, SetDirPayloadType } from './actions';
3-
import {
4-
sliceState,
5-
FileEntity,
6-
Folder,
7-
File
8-
} from './types';
1+
import { PayloadAction } from "@reduxjs/toolkit";
2+
import { RenamePayloadType, SetDirPayloadType } from "./actions";
3+
import { sliceState, FileEntity, Folder, File, PathObject } from "./types";
94

105
/**
116
* payload takes in:
127
* array of type Folder || File
138
*/
14-
export function setItems(state: sliceState, action: PayloadAction<FileEntity[]>) {
15-
const newEntityList: FileEntity[] = action.payload;
9+
export function setItems(
10+
state: sliceState,
11+
action: PayloadAction<FileEntity[]>
12+
) {
13+
const newEntityList: FileEntity[] = [...action.payload];
1614
return {
1715
...state,
18-
items: newEntityList
19-
}
16+
items: newEntityList,
17+
};
2018
}
2119

22-
23-
export function addFolderItems(state: sliceState, action: PayloadAction<Folder>) {
20+
export function addFolderItems(
21+
state: sliceState,
22+
action: PayloadAction<Folder>
23+
) {
2424
const newFolder: Folder = action.payload;
2525
return {
2626
...state,
27-
items: [
28-
...state.items,
29-
newFolder,
30-
]
31-
}
27+
items: [...state.items, newFolder],
28+
};
3229
}
3330

3431
export function addFileItems(state: sliceState, action: PayloadAction<File>) {
3532
const newFile: File = action.payload;
3633
return {
37-
...state,
38-
items: [
39-
...state.items,
40-
newFile,
41-
]
42-
}
34+
...state,
35+
items: [...state.items, newFile],
36+
};
4337
}
4438

45-
export function renameFileEntity(state: sliceState, action: PayloadAction<RenamePayloadType>) {
39+
export function renameFileEntity(
40+
state: sliceState,
41+
action: PayloadAction<RenamePayloadType>
42+
) {
4643
const { id, newName } = action.payload;
4744
return {
4845
...state,
4946
items: state.items.map((item) => {
50-
if(item.id == id) {
51-
return ({
47+
if (item.id == id) {
48+
return {
5249
...item,
5350
name: newName,
54-
})
51+
};
5552
}
5653
// else
5754
return item;
58-
})
59-
}
55+
}),
56+
};
6057
}
6158

62-
export function setDirectory(state: sliceState, action: PayloadAction<SetDirPayloadType>) {
63-
let pathDir = state.path;
59+
export function setDirectory(
60+
state: sliceState,
61+
action: PayloadAction<SetDirPayloadType>
62+
) {
63+
// Helper function for setDirectory
64+
// checks if current folder already in breadcrumb path
65+
function folderInPathList(pathList: PathObject[], folderId: string): boolean {
66+
for (const pathObj of pathList) {
67+
if (pathObj.folderId === folderId) {
68+
return true;
69+
}
70+
}
71+
return false;
72+
}
6473

65-
// traverse back to the previous folder
66-
if (action.payload.folderName == '') {
67-
pathDir = (pathDir.split("/")).slice(0, -1).join("/");
68-
} else { // traverse into a folder
69-
pathDir = pathDir + '/' + action.payload.folderName;
74+
const pathList: PathObject[] = [...state.path];
75+
const destFolderName: string = action.payload.folderName;
76+
const destFolderId: string = action.payload.parentFolder;
77+
if (folderInPathList(pathList, destFolderId)) {
78+
while (pathList[pathList.length - 1].folderId !== destFolderId) {
79+
pathList.pop();
80+
}
81+
} else {
82+
pathList.push({ folderName: destFolderName, folderId: destFolderId });
7083
}
7184

7285
return {
7386
...state,
7487
parentFolder: action.payload.parentFolder,
75-
path: pathDir
76-
}
88+
path: pathList,
89+
};
7790
}
78-
79-

frontend/src/packages/dashboard/state/folders/types.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@ export type File = {
1414
// folders and files
1515
export type FileEntity = Folder | File;
1616

17+
// PathObject is the type which specifies the name AND id of the
18+
// folder we are currently in
19+
export type PathObject = {
20+
folderName: string;
21+
folderId: string;
22+
};
23+
1724
export type sliceState = {
1825
parentFolder: string;
19-
path: string;
26+
path: PathObject[];
2027
items: FileEntity[];
2128
};

0 commit comments

Comments
 (0)