update header bar

This commit is contained in:
lenhanphung
2026-02-04 12:49:42 +07:00
parent ec258f4d42
commit 41c839f38b
12 changed files with 114 additions and 23 deletions
+19 -6
View File
@@ -1,9 +1,14 @@
import { Menubar } from "@/components/Menubar/Menubar";
import * as oidcAuth from "@/features/User/oidcAuth";
import { redirectTo } from "@/utils/navigation";
import "@testing-library/jest-dom";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../utils/Renderwithproviders";
jest.mock("@/utils/navigation", () => ({
redirectTo: jest.fn(),
}));
describe("Calendar App Component Display Tests", () => {
const preloadedState = {
user: {
@@ -320,7 +325,7 @@ describe("Calendar App Component Display Tests", () => {
expect(avatar).toBeInTheDocument();
});
it("shows AppsIcon when applist is not empty", () => {
it("shows apps button when applist is not empty", () => {
(window as any).appList = [{ name: "test", icon: "test", link: "test" }];
const mockCalendarRef = { current: null };
const mockOnRefresh = jest.fn();
@@ -335,10 +340,10 @@ describe("Calendar App Component Display Tests", () => {
/>,
preloadedState
);
expect(screen.getByTestId("AppsIcon")).toBeInTheDocument();
expect(screen.getByLabelText("menubar.apps")).toBeInTheDocument();
});
it("opens popover when clicking AppsIcon", () => {
it("opens popover when clicking apps button", () => {
(window as any).appList = [
{ name: "Twake", icon: "twake.svg", link: "/twake" },
{ name: "Calendar", icon: "calendar.svg", link: "/calendar" },
@@ -356,7 +361,7 @@ describe("Calendar App Component Display Tests", () => {
/>,
preloadedState
);
const appsButton = screen.getByTestId("AppsIcon");
const appsButton = screen.getByLabelText("menubar.apps");
fireEvent.click(appsButton);
expect(screen.getByText("Twake")).toBeInTheDocument();
expect(screen.getByText("Calendar")).toBeInTheDocument();
@@ -377,7 +382,7 @@ describe("Calendar App Component Display Tests", () => {
/>,
preloadedState
);
const appsButton = screen.getByTestId("AppsIcon");
const appsButton = screen.getByLabelText("menubar.apps");
fireEvent.click(appsButton);
const testLink = screen.getByRole("link", { name: /test/i });
@@ -532,7 +537,7 @@ describe("Menubar interaction with expanded Dialog", () => {
preloadedState
);
const appsButton = screen.getByTestId("AppsIcon");
const appsButton = screen.getByLabelText("menubar.apps");
expect(appsButton).toBeVisible();
fireEvent.click(appsButton);
@@ -717,10 +722,17 @@ describe("Menubar interaction with expanded Dialog", () => {
});
describe("Menubar logout flow", () => {
const redirectToMock = redirectTo as jest.Mock;
beforeEach(() => {
localStorage.clear();
sessionStorage.clear();
jest.clearAllMocks();
redirectToMock.mockReset();
});
afterEach(() => {
redirectToMock.mockReset();
});
function renderMenubar(user = { name: "John", email: "test@example.com" }) {
@@ -756,6 +768,7 @@ describe("Menubar logout flow", () => {
fireEvent.click(screen.getByText("menubar.logout"));
});
expect(logoutSpy).toHaveBeenCalled();
expect(redirectToMock).toHaveBeenCalledWith("https://logout.url/");
expect(sessionStorage.length).toBe(0);
});
@@ -248,7 +248,7 @@ describe("ResponsiveDialog", () => {
onClose={mockOnClose}
title="Test"
isExpanded={true}
headerHeight="100px"
headerHeight="70px"
>
<div>Custom Header Content</div>
</ResponsiveDialog>
+45
View File
@@ -83,6 +83,51 @@
"node": "24.x"
}
},
"../twake-ui/packages/twake-mui": {
"name": "@linagora/twake-mui",
"version": "1.1.7",
"license": "MIT",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@babel/eslint-parser": "7.19.1",
"@types/react": "18.3.26",
"@types/react-dom": "18.3.7",
"@typescript-eslint/eslint-plugin": "6.21.0",
"@typescript-eslint/parser": "6.21.0",
"cozy-tsconfig": "1.8.1",
"eslint": "8.35.0",
"eslint-config-cozy-app": "6.7.1",
"eslint-config-prettier": "8.6.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-jest": "27.9.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-hooks": "4.6.0",
"prettier": "2.8.4"
},
"engines": {
"node": "24.x"
},
"peerDependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/material": "^7.1.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"peerDependenciesMeta": {
"react": {
"optional": false
},
"react-dom": {
"optional": false
}
}
},
"node_modules/@adobe/css-tools": {
"version": "4.4.4",
"dev": true,
+1 -1
View File
@@ -6,7 +6,7 @@
.main-layout
display flex
height calc(100vh - 90px)
height calc(100vh - 70px)
.main-layout.calendar-layout
background-color #fff
+1 -1
View File
@@ -244,7 +244,7 @@ tbody > tr.fc-scrollgrid-section:first-of-type .fc-scroller
overflow hidden !important
.navigation-controls
margin-right 40px
margin-right 16px
.fc .fc-timegrid-slot-minor
border-top-style: none
+2 -2
View File
@@ -64,7 +64,7 @@ function MyComponent() {
| `onExpandToggle` | `() => void` | - | Handler for back button click when expanded |
| `normalMaxWidth` | `string` | `"570px"` | Max width in normal mode |
| `expandedContentMaxWidth` | `string` | `"990px"` | Content container max-width in expanded mode |
| `headerHeight` | `string` | `"90px"` | App header height to preserve |
| `headerHeight` | `string` | `"70px"` | App header height to preserve |
| `normalSpacing` | `number` | `2` | Stack spacing in normal mode (MUI spacing units: 1 = 8px) |
| `expandedSpacing` | `number` | `2` | Stack spacing in expanded mode (MUI spacing units: 1 = 8px) |
| `contentSx` | `SxProps<Theme>` | - | Custom styles for DialogContent |
@@ -149,7 +149,7 @@ For apps with different header heights:
open={open}
onClose={handleClose}
title="Custom Header Height"
headerHeight="80px"
headerHeight="70px"
isExpanded={true}
>
<TextField label="Content" />
+1 -1
View File
@@ -100,7 +100,7 @@ function ResponsiveDialog({
onExpandToggle,
normalMaxWidth = "570px",
expandedContentMaxWidth = "990px",
headerHeight = "90px",
headerHeight = "70px",
normalSpacing = 2,
expandedSpacing = 2,
contentSx,
+1 -1
View File
@@ -214,7 +214,7 @@ export default function SearchBar() {
}}
>
{!extended && (
<IconButton onClick={() => setExtended(true)}>
<IconButton sx={{ mr: 1 }} onClick={() => setExtended(true)}>
<SearchIcon />
</IconButton>
)}
+13 -3
View File
@@ -38,20 +38,22 @@
padding 0.5rem
width 100%
z-index 1300
height 80px
height 60px
background-color #fff
.menubar-item
display flex
align-items center
width calc(330px - 0.5rem)
margin-right 65px
.tc-home
cursor pointer
.logo
padding 0.5rem 1rem
padding 0
font-size 1.5rem
max-width 230px
margin-left 1rem
.nav-month
padding-right 2px
@@ -91,6 +93,14 @@
justify-content flex-end
align-items center
.current-date-time
font-family Roboto
font-size 22px
font-style normal
font-weight 400
line-height 36px
color #243B55
body.fullscreen-view .navigation-controls,
body.fullscreen-view .current-date-time,
body.fullscreen-view .refresh-button,
+26 -6
View File
@@ -4,6 +4,7 @@ import { Logout } from "@/features/User/oidcAuth";
import logo from "@/static/header-logo.svg";
import { getInitials, stringToGradient } from "@/utils/avatarUtils";
import { getUserDisplayName } from "@/utils/userUtils";
import { redirectTo } from "@/utils/navigation";
import { CalendarApi } from "@fullcalendar/core";
import {
Avatar,
@@ -19,7 +20,8 @@ import {
Select,
Typography,
} from "@linagora/twake-mui";
import AppsIcon from "@mui/icons-material/Apps";
import WidgetsOutlinedIcon from "@mui/icons-material/WidgetsOutlined";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import LogoutIcon from "@mui/icons-material/Logout";
@@ -139,7 +141,7 @@ export function Menubar({
const handleLogoutClick = async () => {
const logoutUrl = await Logout();
sessionStorage.removeItem("tokenSet");
window.location.assign(logoutUrl.href);
redirectTo(logoutUrl.href);
handleUserMenuClose();
};
@@ -195,9 +197,9 @@ export function Menubar({
</div>
<div className="menu-items">
<div className="current-date-time">
<Typography variant="h3" component="div">
<p>
{dateLabel}
</Typography>
</p>
</div>
</div>
</div>
@@ -211,6 +213,7 @@ export function Menubar({
onClick={onRefresh}
aria-label={t("menubar.refresh")}
title={t("menubar.refresh")}
sx={{ mr: 1 }}
>
<RefreshIcon />
</IconButton>
@@ -226,7 +229,11 @@ export function Menubar({
onChange={(e) => handleViewChange(e.target.value)}
variant="outlined"
aria-label={t("menubar.viewSelector")}
sx={{ height: "43px" }}
sx={{
borderRadius: "12px",
marginLeft: 1,
"& fieldset": { borderRadius: "12px" }
}}
>
<MenuItem value="dayGridMonth">
{t("menubar.views.month")}
@@ -240,6 +247,19 @@ export function Menubar({
</Select>
</FormControl>
</div>
<div className="menu-items">
<IconButton
component="a"
href="https://twake.app/support/"
target="_blank"
rel="noopener noreferrer"
style={{ marginRight: 8 }}
aria-label={t("menubar.help")}
title={t("menubar.help")}
>
<HelpOutlineIcon />
</IconButton>
</div>
<div className="menu-items">
{applist.length > 0 && (
<IconButton
@@ -248,7 +268,7 @@ export function Menubar({
aria-label={t("menubar.apps")}
title={t("menubar.apps")}
>
<AppsIcon />
<WidgetsOutlinedIcon />
</IconButton>
)}
</div>
+1 -1
View File
@@ -1,7 +1,7 @@
.main-layout.settings-layout
display flex
flex-direction row
height calc(100vh - 90px)
height calc(100vh - 70px)
padding 0 10px 10px 0;
.settings-sidebar
+3
View File
@@ -0,0 +1,3 @@
export function redirectTo(url: string): void {
window.location.assign(url);
}