Merge pull request #65 from mcataford/refactor/filelist-view
refactor: refactor filedetails + filelist into filelistview wrapper
This commit is contained in:
commit
4528266f3b
4 changed files with 139 additions and 15 deletions
|
@ -6,14 +6,14 @@ import {
|
|||
} from "@tanstack/react-query"
|
||||
|
||||
import NavigationBar from "./components/NavigationBar"
|
||||
import FileList from "./components/FileList"
|
||||
import FileDetails from "./components/FileDetails"
|
||||
import AsyncTaskContext from "./contexts/AsyncTaskContext"
|
||||
import LocationContext, { useLocationContext } from "./contexts/LocationContext"
|
||||
import { useOwnFileList } from "./hooks/files"
|
||||
|
||||
import { Router, Route } from "./router"
|
||||
|
||||
import FileListView from "./components/FileListView"
|
||||
|
||||
const routeLabels = {
|
||||
ITEM_DETAILS: "item-details",
|
||||
}
|
||||
|
@ -34,20 +34,10 @@ const App = () => {
|
|||
<Box component="main" sx={{ display: "flex", paddingTop: "10px" }}>
|
||||
<Router>
|
||||
<Route path="/">
|
||||
<Box component="div" sx={{ flexGrow: 1 }}>
|
||||
<FileList data={data} />
|
||||
</Box>
|
||||
<FileListView />
|
||||
</Route>
|
||||
<Route path="/item/:itemId">
|
||||
<>
|
||||
<Box component="div" sx={{ flexGrow: 1 }}>
|
||||
<FileList data={data} />
|
||||
</Box>
|
||||
|
||||
<Box component="div" sx={{ flexGrow: 1 }}>
|
||||
<FileDetails itemId={location.params.itemId} />
|
||||
</Box>
|
||||
</>
|
||||
<FileListView />
|
||||
</Route>
|
||||
</Router>
|
||||
</Box>
|
||||
|
|
|
@ -29,7 +29,10 @@ function FileDetails({ itemId }: FileDetailsProps) {
|
|||
const currentFileDetails = data
|
||||
|
||||
return (
|
||||
<MuiCard sx={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
||||
<MuiCard
|
||||
aria-label="file details"
|
||||
sx={{ height: "100%", display: "flex", flexDirection: "column" }}
|
||||
>
|
||||
<MuiBox
|
||||
component="div"
|
||||
sx={{ display: "flex", alignItems: "center", flexDirection: "column" }}
|
||||
|
|
91
frontend/src/components/FileListView/FileListView.test.tsx
Normal file
91
frontend/src/components/FileListView/FileListView.test.tsx
Normal file
|
@ -0,0 +1,91 @@
|
|||
import { render, screen, waitFor } from "@testing-library/react"
|
||||
import { QueryClientProvider, QueryClient } from "@tanstack/react-query"
|
||||
import AxiosMockAdapter from "axios-mock-adapter"
|
||||
|
||||
import axios from "../../axios"
|
||||
import { LocationContext } from "../../contexts/LocationContext"
|
||||
import FileListView from "."
|
||||
|
||||
const routes = {
|
||||
mock: "/item/:itemId",
|
||||
}
|
||||
function renderComponent() {
|
||||
render(
|
||||
<QueryClientProvider client={new QueryClient()}>
|
||||
<LocationContext routes={routes}>
|
||||
<FileListView />
|
||||
</LocationContext>
|
||||
</QueryClientProvider>,
|
||||
)
|
||||
}
|
||||
|
||||
describe("FileListView", () => {
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
|
||||
it("renders no sidebar if no item is in the path", async () => {
|
||||
jest.spyOn(globalThis, "location", "get").mockReturnValue({
|
||||
...globalThis.location,
|
||||
pathname: "/",
|
||||
})
|
||||
|
||||
const axiosMockAdapter = new AxiosMockAdapter(axios)
|
||||
|
||||
axiosMockAdapter.onGet("/files/").reply(200, [
|
||||
{
|
||||
title: "Item 1",
|
||||
filename: "item1.txt",
|
||||
size: 1,
|
||||
id: "b61bf93d-a9db-473e-822e-a65003b1b7e3",
|
||||
},
|
||||
])
|
||||
|
||||
renderComponent()
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByText(/loading/i)).not.toBeInTheDocument(),
|
||||
)
|
||||
|
||||
expect(
|
||||
screen.queryByLabelText("item details sidebar"),
|
||||
).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("renders a sidebar if an item is selected", async () => {
|
||||
const mockItemId = "b61bf93d-a9db-473e-822e-a65003b1b7e3"
|
||||
jest.spyOn(globalThis, "location", "get").mockReturnValue({
|
||||
...globalThis.location,
|
||||
pathname: `/item/${mockItemId}/`,
|
||||
})
|
||||
|
||||
const axiosMockAdapter = new AxiosMockAdapter(axios)
|
||||
|
||||
axiosMockAdapter.onGet("/files/").reply(200, [
|
||||
{
|
||||
title: "Item 1",
|
||||
filename: "item1.txt",
|
||||
size: 1,
|
||||
id: mockItemId,
|
||||
},
|
||||
])
|
||||
|
||||
axiosMockAdapter.onGet(`/files/${mockItemId}/`).reply(200, {
|
||||
title: "Item 1",
|
||||
filename: "item1.txt",
|
||||
size: 1,
|
||||
id: mockItemId,
|
||||
})
|
||||
|
||||
renderComponent()
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByText(/loading/i)).not.toBeInTheDocument(),
|
||||
)
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByLabelText(/file details/i)).toBeInTheDocument(),
|
||||
)
|
||||
|
||||
expect(screen.queryByLabelText("item details sidebar")).toBeInTheDocument()
|
||||
})
|
||||
})
|
40
frontend/src/components/FileListView/index.tsx
Normal file
40
frontend/src/components/FileListView/index.tsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
import React from "react"
|
||||
|
||||
import Box from "@mui/material/Box"
|
||||
|
||||
import FileList from "../FileList"
|
||||
import FileDetails from "../FileDetails"
|
||||
import { useOwnFileList } from "../../hooks/files"
|
||||
import { useLocationContext } from "../../contexts/LocationContext"
|
||||
|
||||
function FileListView() {
|
||||
const { isLoading, data } = useOwnFileList()
|
||||
const { location } = useLocationContext()
|
||||
|
||||
const sidebar = React.useMemo(() => {
|
||||
if (location.params.itemId)
|
||||
return (
|
||||
<Box
|
||||
aria-label="item details sidebar"
|
||||
component="div"
|
||||
sx={{ flexGrow: 1 }}
|
||||
>
|
||||
<FileDetails itemId={location.params.itemId} />
|
||||
</Box>
|
||||
)
|
||||
return null
|
||||
}, [location])
|
||||
|
||||
if (isLoading || !data) return "Loading"
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box component="div" sx={{ flexGrow: 1 }}>
|
||||
<FileList data={data} />
|
||||
</Box>
|
||||
{sidebar}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FileListView
|
Reference in a new issue