Skip to content

Commit 38a7192

Browse files
committed
Refactor code structure for improved readability and maintainability
Signed-off-by: Andre Bossard <anbossar@microsoft.com>
1 parent ab34b71 commit 38a7192

5 files changed

Lines changed: 81 additions & 54 deletions

File tree

debug-screenshot.png

154 KB
Loading

frontend/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"@fluentui/react-components": "^9.47.0",
1515
"@fluentui/react-icons": "^2.0.239",
1616
"react": "^18.2.0",
17-
"react-dom": "^18.2.0"
17+
"react-dom": "^18.2.0",
18+
"react-router-dom": "^7.9.6"
1819
},
1920
"devDependencies": {
2021
"@playwright/test": "^1.42.1",
@@ -23,4 +24,4 @@
2324
"@vitejs/plugin-react": "^4.2.1",
2425
"vite": "^5.1.0"
2526
}
26-
}
27+
}

frontend/src/App.jsx

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,23 @@
77
* - Clear interfaces: Props and state flow is explicit
88
*/
99

10-
import { useState } from 'react'
1110
import {
1211
makeStyles,
13-
tokens,
14-
TabList,
12+
Subtitle1,
1513
Tab,
14+
TabList,
1615
Text,
17-
Subtitle1,
16+
tokens,
1817
} from '@fluentui/react-components'
1918
import {
2019
Home24Regular,
21-
TaskListLtr24Regular,
2220
Info24Regular,
21+
TaskListLtr24Regular,
2322
} from '@fluentui/react-icons'
23+
import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'
24+
import About from './components/About'
2425
import Dashboard from './features/dashboard/Dashboard'
2526
import TaskList from './features/tasks/TaskList'
26-
import About from './components/About'
2727

2828
const useStyles = makeStyles({
2929
app: {
@@ -57,21 +57,14 @@ const useStyles = makeStyles({
5757

5858
export default function App() {
5959
const styles = useStyles()
60-
const [selectedTab, setSelectedTab] = useState('dashboard')
61-
62-
// Render content based on selected tab (CALCULATION)
63-
const renderContent = () => {
64-
switch (selectedTab) {
65-
case 'dashboard':
66-
return <Dashboard />
67-
case 'tasks':
68-
return <TaskList />
69-
case 'about':
70-
return <About />
71-
default:
72-
return <Dashboard />
73-
}
74-
}
60+
const location = useLocation()
61+
const navigate = useNavigate()
62+
const tabs = [
63+
{ value: 'dashboard', label: 'Dashboard', icon: <Home24Regular />, path: '/dashboard', testId: 'tab-dashboard' },
64+
{ value: 'tasks', label: 'Tasks', icon: <TaskListLtr24Regular />, path: '/tasks', testId: 'tab-tasks' },
65+
{ value: 'about', label: 'About', icon: <Info24Regular />, path: '/about', testId: 'tab-about' },
66+
]
67+
const activeTab = tabs.find((tab) => location.pathname.startsWith(tab.path))?.value ?? 'dashboard'
7568

7669
return (
7770
<div className={styles.app}>
@@ -84,23 +77,32 @@ export default function App() {
8477

8578
<nav className={styles.nav}>
8679
<TabList
87-
selectedValue={selectedTab}
88-
onTabSelect={(_, data) => setSelectedTab(data.value)}
80+
selectedValue={activeTab}
81+
onTabSelect={(_, data) => {
82+
const selected = tabs.find((tab) => tab.value === data.value)
83+
if (selected) {
84+
navigate(selected.path)
85+
}
86+
}}
8987
size="large"
9088
>
91-
<Tab value="dashboard" icon={<Home24Regular />} data-testid="tab-dashboard">
92-
Dashboard
93-
</Tab>
94-
<Tab value="tasks" icon={<TaskListLtr24Regular />} data-testid="tab-tasks">
95-
Tasks
96-
</Tab>
97-
<Tab value="about" icon={<Info24Regular />} data-testid="tab-about">
98-
About
99-
</Tab>
89+
{tabs.map((tab) => (
90+
<Tab key={tab.value} value={tab.value} icon={tab.icon} data-testid={tab.testId}>
91+
{tab.label}
92+
</Tab>
93+
))}
10094
</TabList>
10195
</nav>
10296

103-
<main className={styles.content}>{renderContent()}</main>
97+
<main className={styles.content}>
98+
<Routes>
99+
<Route path="/" element={<Navigate to="/dashboard" replace />} />
100+
<Route path="/dashboard" element={<Dashboard />} />
101+
<Route path="/tasks" element={<TaskList />} />
102+
<Route path="/about" element={<About />} />
103+
<Route path="*" element={<Navigate to="/dashboard" replace />} />
104+
</Routes>
105+
</main>
104106
</div>
105107
)
106108
}

frontend/src/main.jsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
import { FluentProvider, webLightTheme } from '@fluentui/react-components'
12
import React from 'react'
23
import ReactDOM from 'react-dom/client'
3-
import { FluentProvider, webLightTheme } from '@fluentui/react-components'
4+
import { BrowserRouter } from 'react-router-dom'
45
import App from './App'
56
import './index.css'
67

78
ReactDOM.createRoot(document.getElementById('root')).render(
89
<React.StrictMode>
9-
<FluentProvider theme={webLightTheme}>
10-
<App />
11-
</FluentProvider>
10+
<BrowserRouter>
11+
<FluentProvider theme={webLightTheme}>
12+
<App />
13+
</FluentProvider>
14+
</BrowserRouter>
1215
</React.StrictMode>,
1316
)

tests/e2e/app.spec.js

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ function uniqueTitle(prefix) {
1414
return `${prefix} ${suffix}`;
1515
}
1616

17+
const APP_URL = process.env.E2E_APP_URL || "http://localhost:3001";
18+
19+
async function visit(page, path = "/") {
20+
const url = path === "/" ? APP_URL : `${APP_URL}${path}`;
21+
await page.goto(url, { waitUntil: "load" });
22+
await waitForAppToLoad(page);
23+
}
24+
1725
// Helper function to wait for React app to load
1826
async function waitForAppToLoad(page) {
1927
// Listen for console errors
@@ -35,8 +43,7 @@ async function waitForAppToLoad(page) {
3543

3644
test.describe("Dashboard - Time is on our side", () => {
3745
test("shows the live server time ticking away", async ({ page }) => {
38-
await page.goto("http://localhost:3001", { waitUntil: "load" });
39-
await waitForAppToLoad(page);
46+
await visit(page);
4047

4148
// Check that we're on the dashboard
4249
await expect(page.getByTestId("tab-dashboard")).toHaveAttribute(
@@ -54,8 +61,7 @@ test.describe("Dashboard - Time is on our side", () => {
5461
});
5562

5663
test("displays server date from API", async ({ page }) => {
57-
await page.goto("http://localhost:3001", { waitUntil: "load" });
58-
await waitForAppToLoad(page);
64+
await visit(page);
5965

6066
// The server knows what day it is!
6167
const dateElement = page.getByTestId("server-date");
@@ -77,10 +83,7 @@ test.describe("Dashboard - Time is on our side", () => {
7783

7884
test.describe("Task Management - Getting stuff done", () => {
7985
test.beforeEach(async ({ page }) => {
80-
await page.goto("http://localhost:3001", { waitUntil: "load" });
81-
await waitForAppToLoad(page);
82-
// Navigate to Tasks tab
83-
await page.getByTestId("tab-tasks").click();
86+
await visit(page, "/tasks");
8487
await expect(page.getByTestId("tab-tasks")).toHaveAttribute(
8588
"aria-selected",
8689
"true"
@@ -252,8 +255,7 @@ test.describe("Task Management - Getting stuff done", () => {
252255

253256
test.describe("Navigation - Exploring the app", () => {
254257
test("navigates between tabs smoothly", async ({ page }) => {
255-
await page.goto("http://localhost:3001", { waitUntil: "load" });
256-
await waitForAppToLoad(page);
258+
await visit(page);
257259

258260
// Start on Dashboard
259261
await expect(page.getByTestId("tab-dashboard")).toHaveAttribute(
@@ -286,14 +288,35 @@ test.describe("Navigation - Exploring the app", () => {
286288
});
287289

288290
test("shows the awesome project title", async ({ page }) => {
289-
await page.goto("http://localhost:3001", { waitUntil: "load" });
290-
await waitForAppToLoad(page);
291+
await visit(page);
291292

292293
// Our glorious header should be visible
293294
await expect(
294295
page.getByText("Quart + React Demo Application")
295296
).toBeVisible();
296297
});
298+
299+
test("supports direct URL navigation for each tab", async ({ page }) => {
300+
await visit(page, "/tasks");
301+
await expect(page.getByTestId("tab-tasks")).toHaveAttribute(
302+
"aria-selected",
303+
"true"
304+
);
305+
await expect(page.getByText("Task Management")).toBeVisible();
306+
307+
await visit(page, "/about");
308+
await expect(page.getByTestId("tab-about")).toHaveAttribute(
309+
"aria-selected",
310+
"true"
311+
);
312+
await expect(page.getByText("About This Project")).toBeVisible();
313+
314+
await visit(page, "/dashboard");
315+
await expect(page.getByTestId("tab-dashboard")).toHaveAttribute(
316+
"aria-selected",
317+
"true"
318+
);
319+
});
297320
});
298321

299322
// ============================================================================
@@ -302,9 +325,7 @@ test.describe("Navigation - Exploring the app", () => {
302325

303326
test.describe("About Page - All the good info", () => {
304327
test.beforeEach(async ({ page }) => {
305-
await page.goto("http://localhost:3001", { waitUntil: "load" });
306-
await waitForAppToLoad(page);
307-
await page.getByTestId("tab-about").click();
328+
await visit(page, "/about");
308329
});
309330

310331
test("displays project information", async ({ page }) => {

0 commit comments

Comments
 (0)