Merge pull request #435 from linagora/feat/migration-twake-ui
Feat/migration twake UI
This commit is contained in:
Vendored
+7
@@ -3,6 +3,7 @@ pipeline {
|
||||
|
||||
environment {
|
||||
DOCKER_HUB_CREDENTIAL = credentials('dockerHub')
|
||||
GITHUB_CREDENTIAL = credentials('github')
|
||||
}
|
||||
|
||||
tools {
|
||||
@@ -18,6 +19,12 @@ pipeline {
|
||||
stages {
|
||||
stage('Compile') {
|
||||
steps {
|
||||
sh '''
|
||||
cat > .npmrc << EOF
|
||||
@linagora:registry=https://npm.pkg.github.com/
|
||||
//npm.pkg.github.com/:_authToken=${GITHUB_CREDENTIAL_PSW}
|
||||
EOF
|
||||
'''
|
||||
sh 'npm install'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,11 +443,14 @@ describe("calendar Availability search", () => {
|
||||
screen.getByRole("button", { name: "event.createEvent" })
|
||||
);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByText("event.createEvent")).toHaveLength(2);
|
||||
expect(screen.getAllByText(/New User/i)).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getAllByText("event.createEvent")).toHaveLength(2);
|
||||
expect(screen.getAllByText(/New User/i)).toHaveLength(2);
|
||||
},
|
||||
{ timeout: 10000 }
|
||||
);
|
||||
}, 15000);
|
||||
|
||||
it("open window with attendees filled after temp search on enter in temp input", async () => {
|
||||
const spy = jest
|
||||
@@ -482,11 +485,14 @@ describe("calendar Availability search", () => {
|
||||
fireEvent.keyDown(input, { key: "Enter" });
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByText("event.createEvent")).toHaveLength(2);
|
||||
expect(screen.getAllByText(/New User/i)).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getAllByText("event.createEvent")).toHaveLength(2);
|
||||
expect(screen.getAllByText(/New User/i)).toHaveLength(2);
|
||||
},
|
||||
{ timeout: 10000 }
|
||||
);
|
||||
}, 15000);
|
||||
|
||||
it("BUGFIX: can untoggle all calendar.personal", async () => {
|
||||
await act(async () =>
|
||||
|
||||
@@ -69,10 +69,13 @@ describe("Event Error Handling", () => {
|
||||
renderWithProviders(<CalendarLayout />, erroredState)
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Test Event"));
|
||||
expect(screen.getByRole("alert")).toBeInTheDocument();
|
||||
});
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByText("Test Event"));
|
||||
expect(screen.getByRole("alert")).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 10000 }
|
||||
);
|
||||
const closeButton = screen.queryByRole("button", { name: "common.ok" });
|
||||
|
||||
if (closeButton) {
|
||||
@@ -82,9 +85,12 @@ describe("Event Error Handling", () => {
|
||||
fireEvent.click(closeButton);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByRole("alert")).not.toBeInTheDocument();
|
||||
});
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.queryByRole("alert")).not.toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 5000 }
|
||||
);
|
||||
|
||||
const afterCloseWarnCount = consoleWarnSpy.mock.calls.length;
|
||||
|
||||
|
||||
@@ -199,6 +199,8 @@ describe("RepeatEvent Component", () => {
|
||||
});
|
||||
|
||||
describe("Repeat Event Integration Tests", () => {
|
||||
// Increase timeout for all tests in this describe block
|
||||
jest.setTimeout(30000);
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import React from "react";
|
||||
import { ResponsiveDialog } from "../../src/components/Dialog";
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { Button, TextField } from "@linagora/twake-mui";
|
||||
import { TwakeMuiThemeProvider } from "@linagora/twake-mui";
|
||||
|
||||
describe("ResponsiveDialog", () => {
|
||||
const mockOnClose = jest.fn();
|
||||
const mockOnExpandToggle = jest.fn();
|
||||
|
||||
const renderWithTheme = (ui: React.ReactElement) => {
|
||||
return render(<TwakeMuiThemeProvider>{ui}</TwakeMuiThemeProvider>);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockOnClose.mockClear();
|
||||
mockOnExpandToggle.mockClear();
|
||||
});
|
||||
|
||||
it("renders in normal mode by default", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog open={true} onClose={mockOnClose} title="Test Dialog">
|
||||
<TextField label="Name" />
|
||||
</ResponsiveDialog>
|
||||
@@ -24,7 +29,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("renders title in normal mode", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -40,7 +45,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("renders back arrow in extended mode", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -57,7 +62,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("calls onExpandToggle when back arrow is clicked", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -76,7 +81,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("renders actions when provided", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -91,7 +96,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("does not render actions when not provided", () => {
|
||||
const { container } = render(
|
||||
const { container } = renderWithTheme(
|
||||
<ResponsiveDialog open={true} onClose={mockOnClose} title="Test">
|
||||
<div>Content</div>
|
||||
</ResponsiveDialog>
|
||||
@@ -102,7 +107,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("calls onClose when backdrop is clicked", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog open={true} onClose={mockOnClose} title="Test">
|
||||
<div>Content</div>
|
||||
</ResponsiveDialog>
|
||||
@@ -117,7 +122,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("applies custom normalMaxWidth", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -132,7 +137,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("wraps children in Stack component", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog open={true} onClose={mockOnClose} title="Test">
|
||||
<TextField label="Field 1" />
|
||||
<TextField label="Field 2" />
|
||||
@@ -144,7 +149,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("uses correct spacing in normal mode", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -160,7 +165,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("uses correct spacing in extended mode", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -176,7 +181,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("applies contentSx custom styles", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -191,7 +196,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("applies titleSx custom styles", () => {
|
||||
const { container } = render(
|
||||
const { container } = renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -207,7 +212,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("shows dividers when dividers prop is true", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -222,7 +227,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("does not show back arrow when onExpandToggle is not provided", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -238,7 +243,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("accepts custom headerHeight", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -254,7 +259,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("renders with custom expandedContentMaxWidth", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -270,7 +275,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("does not render dialog content when open is false", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog open={false} onClose={mockOnClose} title="Test">
|
||||
<div>Test Content</div>
|
||||
</ResponsiveDialog>
|
||||
@@ -280,7 +285,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("renders correctly in extended mode", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -297,7 +302,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("renders expand and close icons in normal mode when showHeaderActions is true", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -315,7 +320,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("does not render header icons when showHeaderActions is false", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -334,7 +339,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("calls onClose when close icon is clicked", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
@@ -353,7 +358,7 @@ describe("ResponsiveDialog", () => {
|
||||
});
|
||||
|
||||
it("calls onExpandToggle when expand icon is clicked", () => {
|
||||
render(
|
||||
renderWithTheme(
|
||||
<ResponsiveDialog
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
|
||||
@@ -662,7 +662,78 @@ describe("Event Preview Display", () => {
|
||||
preloadedState.calendars.list["667037022b752d0026472254/cal1"].events[
|
||||
"event1"
|
||||
];
|
||||
const expectedUrl = `test/mailto/?uri=mailto:john@test.com?subject=Test Event`;
|
||||
const expectedUrl = `test/mailto/?uri=mailto:john@test.com?subject=Test%20Event`;
|
||||
|
||||
expect(mockOpen).toHaveBeenCalledWith(expectedUrl);
|
||||
});
|
||||
|
||||
it("message button encodes special characters in event title correctly", () => {
|
||||
(window as any).MAIL_SPA_URL = "test";
|
||||
const mockOpen = jest.fn();
|
||||
window.open = mockOpen;
|
||||
|
||||
const specialCharState = {
|
||||
...preloadedState,
|
||||
calendars: {
|
||||
...preloadedState.calendars,
|
||||
list: {
|
||||
...preloadedState.calendars.list,
|
||||
"667037022b752d0026472254/cal1": {
|
||||
...preloadedState.calendars.list["667037022b752d0026472254/cal1"],
|
||||
events: {
|
||||
...preloadedState.calendars.list["667037022b752d0026472254/cal1"]
|
||||
.events,
|
||||
eventWithSpecialChars: {
|
||||
uid: "eventWithSpecialChars",
|
||||
title: "Meeting & Discussion? #Important",
|
||||
calId: "667037022b752d0026472254/cal1",
|
||||
start: day.toISOString(),
|
||||
end: day.toISOString(),
|
||||
organizer: { cn: "test", cal_address: "test@test.com" },
|
||||
attendee: [
|
||||
{
|
||||
cn: "test",
|
||||
cal_address: "test@test.com",
|
||||
partstat: "NEEDS-ACTION",
|
||||
rsvp: "TRUE",
|
||||
role: "REQ-PARTICIPANT",
|
||||
cutype: "INDIVIDUAL",
|
||||
},
|
||||
{
|
||||
cn: "John",
|
||||
cal_address: "john@test.com",
|
||||
partstat: "NEEDS-ACTION",
|
||||
rsvp: "TRUE",
|
||||
role: "REQ-PARTICIPANT",
|
||||
cutype: "INDIVIDUAL",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
renderWithProviders(
|
||||
<EventPreviewModal
|
||||
open={true}
|
||||
onClose={mockOnClose}
|
||||
calId={"667037022b752d0026472254/cal1"}
|
||||
eventId={"eventWithSpecialChars"}
|
||||
/>,
|
||||
specialCharState
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByTestId("MoreVertIcon"));
|
||||
const emailButton = screen.getByRole("menuitem", {
|
||||
name: "eventPreview.emailAttendees",
|
||||
});
|
||||
expect(emailButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(emailButton);
|
||||
|
||||
const expectedUrl = `test/mailto/?uri=mailto:john@test.com?subject=Meeting%20%26%20Discussion%3F%20%23Important`;
|
||||
|
||||
expect(mockOpen).toHaveBeenCalledWith(expectedUrl);
|
||||
});
|
||||
@@ -1957,7 +2028,8 @@ describe("Helper functions", () => {
|
||||
it("stringAvatar returns correct props", () => {
|
||||
const result = stringAvatar("Alice");
|
||||
expect(result.children).toBe("A");
|
||||
expect(result.style.backgroundColor).toMatch(/^#/);
|
||||
expect(result.color).toBeDefined();
|
||||
expect(typeof result.color).toBe("string");
|
||||
});
|
||||
|
||||
it("InfoRow renders text and link if url is valid", () => {
|
||||
|
||||
@@ -296,7 +296,7 @@ describe("EventPreviewModal - Recurring Event Interactions", () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText("editModeDialog.updateRecurrentEvent")
|
||||
screen.getByText("editModeDialog.deleteRecurrentEvent")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -381,7 +381,7 @@ describe("EventPreviewModal - Recurring Event Interactions", () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.queryByText("editModeDialog.updateRecurrentEvent")
|
||||
screen.queryByText("editModeDialog.deleteRecurrentEvent")
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -416,7 +416,7 @@ describe("Delete Recurring Event Instance", () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText("editModeDialog.updateRecurrentEvent")
|
||||
screen.getByText("editModeDialog.deleteRecurrentEvent")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -463,7 +463,7 @@ describe("Delete Recurring Event Instance", () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText("editModeDialog.updateRecurrentEvent")
|
||||
screen.getByText("editModeDialog.deleteRecurrentEvent")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import React, { PropsWithChildren } from "react";
|
||||
import { Provider } from "react-redux";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import { I18nContext } from "twake-i18n";
|
||||
import { TwakeMuiThemeProvider } from "@linagora/twake-mui";
|
||||
import type { AppStore, RootState } from "../../src/app/store";
|
||||
import { setupStore } from "../../src/app/store";
|
||||
interface ExtendedRenderOptions extends Omit<RenderOptions, "queries"> {
|
||||
@@ -21,28 +22,30 @@ export function renderWithProviders(
|
||||
|
||||
const Wrapper = ({ children }: PropsWithChildren) => {
|
||||
return (
|
||||
<I18nContext.Provider
|
||||
value={{
|
||||
t: (key: string, vars?: Record<string, string>) => {
|
||||
if (key === "locale") {
|
||||
return "en";
|
||||
}
|
||||
if (vars) {
|
||||
const params = Object.entries(vars)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join(",");
|
||||
return `${key}(${params})`;
|
||||
}
|
||||
return key;
|
||||
},
|
||||
f: (date: Date, formatStr: string) => date.toString(),
|
||||
lang: "en",
|
||||
}}
|
||||
>
|
||||
<MemoryRouter initialEntries={["/"]}>
|
||||
<Provider store={store}>{children}</Provider>
|
||||
</MemoryRouter>
|
||||
</I18nContext.Provider>
|
||||
<TwakeMuiThemeProvider>
|
||||
<I18nContext.Provider
|
||||
value={{
|
||||
t: (key: string, vars?: Record<string, string>) => {
|
||||
if (key === "locale") {
|
||||
return "en";
|
||||
}
|
||||
if (vars) {
|
||||
const params = Object.entries(vars)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join(",");
|
||||
return `${key}(${params})`;
|
||||
}
|
||||
return key;
|
||||
},
|
||||
f: (date: Date, formatStr: string) => date.toString(),
|
||||
lang: "en",
|
||||
}}
|
||||
>
|
||||
<MemoryRouter initialEntries={["/"]}>
|
||||
<Provider store={store}>{children}</Provider>
|
||||
</MemoryRouter>
|
||||
</I18nContext.Provider>
|
||||
</TwakeMuiThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+7
-1
@@ -23,6 +23,7 @@ const config: Config = {
|
||||
],
|
||||
testEnvironment: "jsdom",
|
||||
testMatch: ["**/*.test.tsx"],
|
||||
testTimeout: 15000,
|
||||
transform: {
|
||||
"^.+\\.tsx?$": ["ts-jest", { tsconfig: "tsconfig.json" }],
|
||||
"^.+\\.(js|jsx|mjs)$": "babel-jest",
|
||||
@@ -37,7 +38,11 @@ const config: Config = {
|
||||
"/node_modules/(?!(preact|@fullcalendar|react-calendar|get-user-locale|memoize|mimic-function|@wojtekmaj|ky|cozy-ui)/)",
|
||||
],
|
||||
|
||||
moduleNameMapper: { "^preact(/(.*)|$)": "preact$1" },
|
||||
moduleNameMapper: {
|
||||
"^preact(/(.*)|$)": "preact$1",
|
||||
"^react$": "<rootDir>/node_modules/react",
|
||||
"^react-dom$": "<rootDir>/node_modules/react-dom",
|
||||
},
|
||||
setupFilesAfterEnv: ["<rootDir>/src/setupTests.ts"],
|
||||
},
|
||||
{
|
||||
@@ -55,6 +60,7 @@ const config: Config = {
|
||||
],
|
||||
testEnvironment: "node",
|
||||
testMatch: ["**/*.test.ts"],
|
||||
testTimeout: 15000,
|
||||
transform: {
|
||||
"^.+\\.tsx?$": ["ts-jest", { tsconfig: "tsconfig.json" }],
|
||||
"^.+\\.(js|jsx|mjs)$": "babel-jest",
|
||||
|
||||
Generated
+404
-272
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@
|
||||
"@fullcalendar/moment-timezone": "^6.1.19",
|
||||
"@fullcalendar/react": "^6.1.17",
|
||||
"@fullcalendar/timegrid": "^6.1.17",
|
||||
"@linagora/twake-mui": "1.1.1",
|
||||
"@mui/icons-material": "^7.1.2",
|
||||
"@mui/material": "^7.1.2",
|
||||
"@mui/x-date-pickers": "^8.14.0",
|
||||
@@ -89,6 +90,7 @@
|
||||
"jest-preview": "^0.3.1",
|
||||
"prettier": "^3.6.2",
|
||||
"ts-jest": "^29.4.6",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,4 +23,10 @@ export default defineConfig({
|
||||
},
|
||||
minify: false,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
react: require.resolve("react"),
|
||||
"react-dom": require.resolve("react-dom"),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ import { Loading } from "./components/Loading/Loading";
|
||||
import HandleLogin from "./features/User/HandleLogin";
|
||||
import CalendarLayout from "./components/Calendar/CalendarLayout";
|
||||
import { Error } from "./components/Error/Error";
|
||||
import { CustomThemeProvider } from "./theme/ThemeProvider";
|
||||
import { TwakeMuiThemeProvider } from "@linagora/twake-mui";
|
||||
import { useAppDispatch, useAppSelector } from "./app/hooks";
|
||||
import { push } from "redux-first-history";
|
||||
import { ErrorSnackbar } from "./components/Error/ErrorSnackbar";
|
||||
@@ -61,7 +61,7 @@ function App() {
|
||||
}, [error, dispatch]);
|
||||
|
||||
return (
|
||||
<CustomThemeProvider>
|
||||
<TwakeMuiThemeProvider>
|
||||
<I18n
|
||||
dictRequire={(lang: keyof typeof locale) => locale[lang]}
|
||||
lang={lang}
|
||||
@@ -79,7 +79,7 @@ function App() {
|
||||
<ErrorSnackbar error={error} type="user" />
|
||||
</Suspense>
|
||||
</I18n>
|
||||
</CustomThemeProvider>
|
||||
</TwakeMuiThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import Autocomplete, {
|
||||
AutocompleteRenderInputParams,
|
||||
} from "@mui/material/Autocomplete";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import ListItemAvatar from "@mui/material/ListItemAvatar";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {
|
||||
Autocomplete,
|
||||
type AutocompleteRenderInputParams,
|
||||
Avatar,
|
||||
CircularProgress,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
TextField,
|
||||
} from "@linagora/twake-mui";
|
||||
import {
|
||||
type ReactNode,
|
||||
useCallback,
|
||||
@@ -16,12 +17,11 @@ import {
|
||||
} from "react";
|
||||
import { searchUsers } from "../../features/User/userAPI";
|
||||
import PeopleOutlineOutlinedIcon from "@mui/icons-material/PeopleOutlineOutlined";
|
||||
import Chip from "@mui/material/Chip";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { Chip, useTheme } from "@linagora/twake-mui";
|
||||
import { getAccessiblePair } from "../Calendar/utils/calendarColorsUtils";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { SnackbarAlert } from "../Loading/SnackBarAlert";
|
||||
import { PopperProps, PaperProps } from "@mui/material";
|
||||
import { PopperProps, PaperProps } from "@linagora/twake-mui";
|
||||
|
||||
export interface User {
|
||||
email: string;
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
InputAdornment,
|
||||
Backdrop,
|
||||
CircularProgress,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
exportCalendar,
|
||||
|
||||
@@ -20,8 +20,7 @@ import { push } from "redux-first-history";
|
||||
import EventPreviewModal from "../../features/Events/EventDisplayPreview";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import { TempCalendarsInput } from "./TempCalendarsInput";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Box } from "@mui/material";
|
||||
import { Button, Box, radius } from "@linagora/twake-mui";
|
||||
import {
|
||||
updateSlotLabelVisibility,
|
||||
eventToFullCalendarFormat,
|
||||
@@ -36,7 +35,7 @@ import momentTimezonePlugin from "@fullcalendar/moment-timezone";
|
||||
import { TimezoneSelector } from "./TimezoneSelector";
|
||||
import { MiniCalendar } from "./MiniCalendar";
|
||||
import { User } from "../Attendees/PeopleSearch";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useTheme } from "@linagora/twake-mui";
|
||||
import { updateDarkColor } from "./utils/calendarColorsUtils";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import frLocale from "@fullcalendar/core/locales/fr";
|
||||
@@ -619,6 +618,9 @@ export default function CalendarApp({
|
||||
onClick={() =>
|
||||
eventHandlers.handleDateSelect(null as unknown as DateSelectArg)
|
||||
}
|
||||
sx={{
|
||||
borderRadius: radius.lg,
|
||||
}}
|
||||
>
|
||||
<AddIcon /> <p>{t("event.createEvent")}</p>
|
||||
</Button>
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
TextField,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import { useState } from "react";
|
||||
import { HexColorPicker } from "react-colorful";
|
||||
import { useI18n } from "twake-i18n";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { MenuItem } from "@mui/material";
|
||||
import { MenuItem } from "@linagora/twake-mui";
|
||||
import { Calendar } from "../../features/Calendars/CalendarTypes";
|
||||
import { CalendarName } from "./CalendarName";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, DialogActions, Tab, Tabs } from "@mui/material";
|
||||
import { Button, Tab, Tabs } from "@linagora/twake-mui";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import {
|
||||
@@ -198,7 +198,7 @@ function CalendarPopover({
|
||||
</Tabs>
|
||||
}
|
||||
actions={
|
||||
<DialogActions>
|
||||
<>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={(e) => handleClose({}, "backdropClick")}
|
||||
@@ -216,7 +216,7 @@ function CalendarPopover({
|
||||
? t("actions.save")
|
||||
: t("actions.create")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{tab === "import" && (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Box, Typography } from "@linagora/twake-mui";
|
||||
import { Calendar } from "../../features/Calendars/CalendarTypes";
|
||||
import SquareRoundedIcon from "@mui/icons-material/SquareRounded";
|
||||
export function CalendarName({ calendar }: { calendar: Calendar }) {
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
IconButton,
|
||||
Typography,
|
||||
TextField,
|
||||
useTheme,
|
||||
} from "@linagora/twake-mui";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { useState } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import { getCalendars } from "../../features/Calendars/CalendarApi";
|
||||
import { addSharedCalendarAsync } from "../../features/Calendars/CalendarSlice";
|
||||
import { Calendar } from "../../features/Calendars/CalendarTypes";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { PeopleSearch, User } from "../Attendees/PeopleSearch";
|
||||
import { ResponsiveDialog } from "../Dialog";
|
||||
import { ColorPicker } from "./CalendarColorPicker";
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
AccordionSummary,
|
||||
Typography,
|
||||
IconButton,
|
||||
Checkbox,
|
||||
Divider,
|
||||
ListItem,
|
||||
Menu,
|
||||
MenuItem,
|
||||
} from "@linagora/twake-mui";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import { useState, useMemo, useEffect } from "react";
|
||||
import CalendarPopover from "./CalendarModal";
|
||||
import { Calendar } from "../../features/Calendars/CalendarTypes";
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import Checkbox from "@mui/material/Checkbox";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import CalendarSearch from "./CalendarSearch";
|
||||
import { Divider, ListItem, Menu, MenuItem } from "@mui/material";
|
||||
import { removeCalendarAsync } from "../../features/Calendars/CalendarSlice";
|
||||
import { DeleteCalendarDialog } from "./DeleteCalendarDialog";
|
||||
import { trimLongTextWithoutSpace } from "../../utils/textUtils";
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import Dialog from "@mui/material/Dialog";
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogActions,
|
||||
Button,
|
||||
} from "@linagora/twake-mui";
|
||||
import { Calendar } from "../../features/Calendars/CalendarTypes";
|
||||
import DialogTitle from "@mui/material/DialogTitle";
|
||||
import DialogContent from "@mui/material/DialogContent";
|
||||
import DialogContentText from "@mui/material/DialogContentText";
|
||||
import DialogActions from "@mui/material/DialogActions";
|
||||
import Button from "@mui/material/Button";
|
||||
import { useI18n } from "twake-i18n";
|
||||
|
||||
export function DeleteCalendarDialog({
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
ToggleButton,
|
||||
ToggleButtonGroup,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAppSelector } from "../../app/hooks";
|
||||
import { CalendarItemList } from "./CalendarItemList";
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
ToggleButton,
|
||||
ToggleButtonGroup,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useAppSelector } from "../../app/hooks";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useTheme } from "@linagora/twake-mui";
|
||||
import { useRef } from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "../../features/Calendars/CalendarSlice";
|
||||
import { Calendar } from "../../features/Calendars/CalendarTypes";
|
||||
import { setView } from "../../features/Settings/SettingsSlice";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { TextField } from "@linagora/twake-mui";
|
||||
import { User, PeopleSearch } from "../Attendees/PeopleSearch";
|
||||
import { getAccessiblePair } from "./utils/calendarColorsUtils";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Popover } from "@mui/material";
|
||||
import { Button, Popover } from "@linagora/twake-mui";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import moment from "moment";
|
||||
import { MouseEvent, useMemo, useState } from "react";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { darken, getContrastRatio, lighten, Theme } from "@mui/material";
|
||||
import { darken, getContrastRatio, lighten, Theme } from "@linagora/twake-mui";
|
||||
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||
import { updateCalColor } from "../../../features/Calendars/CalendarSlice";
|
||||
import { Calendar } from "../../../features/Calendars/CalendarTypes";
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
SxProps,
|
||||
Theme,
|
||||
Box,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import OpenInFullIcon from "@mui/icons-material/OpenInFull";
|
||||
@@ -132,7 +132,7 @@ function ResponsiveDialog({
|
||||
"& .MuiDialogActions-root .MuiBox-root": {
|
||||
maxWidth: isExpanded ? expandedContentMaxWidth : undefined,
|
||||
margin: isExpanded ? "0 auto" : undefined,
|
||||
padding: isExpanded ? "0 12px" : undefined,
|
||||
padding: "0",
|
||||
width: isExpanded ? "100%" : undefined,
|
||||
justifyContent: isExpanded ? "flex-end" : undefined,
|
||||
},
|
||||
@@ -140,7 +140,6 @@ function ResponsiveDialog({
|
||||
|
||||
const baseContentSx: SxProps<Theme> = {
|
||||
width: "100%",
|
||||
padding: isExpanded ? "16px" : undefined,
|
||||
};
|
||||
|
||||
const contentWrapperSx: SxProps<Theme> = {
|
||||
@@ -239,8 +238,6 @@ function ResponsiveDialog({
|
||||
? (theme) => `1px solid ${theme.palette.divider}`
|
||||
: undefined,
|
||||
justifyContent: actionsJustifyContent,
|
||||
paddingTop: "18px",
|
||||
paddingBottom: "18px",
|
||||
}}
|
||||
>
|
||||
{actions}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
|
||||
import ReplayIcon from "@mui/icons-material/Replay";
|
||||
import { Box, Button, Fade, Paper, Stack, Typography } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Fade,
|
||||
Paper,
|
||||
Stack,
|
||||
Typography,
|
||||
} from "@linagora/twake-mui";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { push } from "redux-first-history";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import Snackbar from "@mui/material/Snackbar";
|
||||
import Alert from "@mui/material/Alert";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Snackbar, Alert, Button } from "@linagora/twake-mui";
|
||||
import { useAppDispatch } from "../../app/hooks";
|
||||
import { clearError as calendarClearError } from "../../features/Calendars/CalendarSlice";
|
||||
import { clearError as userClearError } from "../../features/User/userSlice";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Button, TextField } from "@mui/material";
|
||||
import { Box, Button, TextField } from "@linagora/twake-mui";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { FieldWithLabel } from "./components/FieldWithLabel";
|
||||
import { Description as DescriptionIcon } from "@mui/icons-material";
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import { CalendarEvent } from "../../features/Events/EventsTypes";
|
||||
import { useState } from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
@@ -40,6 +40,7 @@ export function EditModeDialog({
|
||||
<Dialog open={Boolean(type)} onClose={handleClose}>
|
||||
<DialogTitle>
|
||||
{type === "edit" && t("editModeDialog.updateRecurrentEvent")}
|
||||
{type === "delete" && t("editModeDialog.deleteRecurrentEvent")}
|
||||
{type === "attendance" && t("editModeDialog.updateParticipationStatus")}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Card, Typography } from "@mui/material";
|
||||
import { Card, Typography } from "@linagora/twake-mui";
|
||||
import { useRef, useEffect } from "react";
|
||||
import { EventErrorHandler } from "../../Error/EventErrorHandler";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
CardContent,
|
||||
CardHeader,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { stringAvatar } from "../utils/eventUtils";
|
||||
import { ErrorEventChip } from "./ErrorEventChip";
|
||||
@@ -110,7 +110,7 @@ export function EventChip({
|
||||
event._def.extendedProps.organizer?.cn ??
|
||||
event._def.extendedProps.organizer?.cal_address
|
||||
)
|
||||
: { style: {}, children: null };
|
||||
: { color: undefined, children: null };
|
||||
|
||||
return (
|
||||
<Card
|
||||
@@ -261,10 +261,9 @@ export function EventChip({
|
||||
(window as any).displayOrgAvatar && (
|
||||
<Avatar
|
||||
children={OrganizerAvatar.children}
|
||||
style={{
|
||||
...OrganizerAvatar.style,
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
color={OrganizerAvatar.color}
|
||||
size="xs"
|
||||
sx={{
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
margin: "8px",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import CancelIcon from "@mui/icons-material/Cancel";
|
||||
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
|
||||
import LockOutlineIcon from "@mui/icons-material/LockOutline";
|
||||
import { Box, getContrastRatio } from "@mui/material";
|
||||
import { Box, getContrastRatio } from "@linagora/twake-mui";
|
||||
import moment from "moment";
|
||||
import React, { useLayoutEffect, useState } from "react";
|
||||
import { Calendar } from "../../../features/Calendars/CalendarTypes";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { Card, Typography } from "@mui/material";
|
||||
import { Card, Typography } from "@linagora/twake-mui";
|
||||
|
||||
export function SimpleEventChip({ title }: { title: string }) {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MenuItem } from "@mui/material";
|
||||
import { MenuItem } from "@linagora/twake-mui";
|
||||
import { CalendarEvent } from "../../features/Events/EventsTypes";
|
||||
import { useI18n } from "twake-i18n";
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
TextField,
|
||||
ToggleButtonGroup,
|
||||
ToggleButton,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import {
|
||||
Description as DescriptionIcon,
|
||||
Public as PublicIcon,
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
FormGroup,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import { useEffect, useState } from "react";
|
||||
import { RepetitionObject } from "../../features/Events/EventsTypes";
|
||||
import { useI18n } from "twake-i18n";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { Box, Typography, Link } from "@mui/material";
|
||||
import { Box, Typography, Link } from "@linagora/twake-mui";
|
||||
|
||||
type InfoRowProps = {
|
||||
icon: React.ReactNode;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { TextFieldProps } from "@mui/material/TextField";
|
||||
import { Box, Typography } from "@linagora/twake-mui";
|
||||
import { TextFieldProps } from "@linagora/twake-mui";
|
||||
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
|
||||
import { DatePickerFieldProps } from "@mui/x-date-pickers/DatePicker";
|
||||
import { TimePicker } from "@mui/x-date-pickers/TimePicker";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useRef, useEffect, useCallback } from "react";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { TextField } from "@linagora/twake-mui";
|
||||
import {
|
||||
PickerFieldAdapter,
|
||||
PickerValidationScope,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Box, Typography } from "@linagora/twake-mui";
|
||||
|
||||
/**
|
||||
* Helper component for field with label
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { TextField } from "@linagora/twake-mui";
|
||||
import {
|
||||
PickerFieldAdapter,
|
||||
PickerValidationScope,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import CancelIcon from "@mui/icons-material/Cancel";
|
||||
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Badge from "@mui/material/Badge";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Avatar, Badge, Box, Typography } from "@linagora/twake-mui";
|
||||
import { stringToGradient } from "../../../utils/avatarUtils";
|
||||
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||
import {
|
||||
emptyEventsCal,
|
||||
@@ -104,7 +102,7 @@ export function stringToColor(string: string) {
|
||||
|
||||
export function stringAvatar(name: string) {
|
||||
return {
|
||||
style: { backgroundColor: stringToColor(name) },
|
||||
color: stringToGradient(name),
|
||||
children: name[0],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Alert, { AlertColor } from "@mui/material/Alert";
|
||||
import Snackbar from "@mui/material/Snackbar";
|
||||
import { Alert, Snackbar } from "@linagora/twake-mui";
|
||||
import type { AlertColor } from "@linagora/twake-mui";
|
||||
|
||||
export function SnackbarAlert({
|
||||
open,
|
||||
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
Stack,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { type AutocompleteRenderInputParams } from "@mui/material/Autocomplete";
|
||||
} from "@linagora/twake-mui";
|
||||
import { type AutocompleteRenderInputParams } from "@linagora/twake-mui";
|
||||
import { useRef, useState, useEffect } from "react";
|
||||
import HighlightOffIcon from "@mui/icons-material/HighlightOff";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
|
||||
@@ -8,7 +8,7 @@ import SettingsIcon from "@mui/icons-material/Settings";
|
||||
import LogoutIcon from "@mui/icons-material/Logout";
|
||||
import "./Menubar.styl";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import { stringToColor } from "../Event/utils/eventUtils";
|
||||
import { stringToGradient } from "../../utils/avatarUtils";
|
||||
import {
|
||||
Avatar,
|
||||
IconButton,
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
Typography,
|
||||
Box,
|
||||
Divider,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import { push } from "redux-first-history";
|
||||
import { CalendarApi } from "@fullcalendar/core";
|
||||
import { useI18n } from "twake-i18n";
|
||||
@@ -194,7 +194,7 @@ export function Menubar({
|
||||
</div>
|
||||
<div className="menu-items">
|
||||
<div className="current-date-time">
|
||||
<Typography variant="h6" component="div">
|
||||
<Typography variant="h3" component="div">
|
||||
{dateLabel}
|
||||
</Typography>
|
||||
</div>
|
||||
@@ -255,16 +255,14 @@ export function Menubar({
|
||||
<div className="menu-items">
|
||||
<IconButton onClick={handleUserMenuClick}>
|
||||
<Avatar
|
||||
style={{
|
||||
backgroundColor: stringToColor(
|
||||
user && user.family_name
|
||||
? user.family_name
|
||||
: user && user.email
|
||||
? user.email
|
||||
: ""
|
||||
),
|
||||
}}
|
||||
sizes="large"
|
||||
color={stringToGradient(
|
||||
user && user.family_name
|
||||
? user.family_name
|
||||
: user && user.email
|
||||
? user.email
|
||||
: ""
|
||||
)}
|
||||
size="m"
|
||||
aria-label={t("menubar.userProfile")}
|
||||
>
|
||||
{user?.name && user?.family_name
|
||||
@@ -333,17 +331,15 @@ export function Menubar({
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
style={{
|
||||
backgroundColor: stringToColor(
|
||||
user && user.family_name
|
||||
? user.family_name
|
||||
: user && user.email
|
||||
? user.email
|
||||
: ""
|
||||
),
|
||||
marginBottom: "8px",
|
||||
}}
|
||||
sizes="large"
|
||||
color={stringToGradient(
|
||||
user && user.family_name
|
||||
? user.family_name
|
||||
: user && user.email
|
||||
? user.email
|
||||
: ""
|
||||
)}
|
||||
size="m"
|
||||
sx={{ marginBottom: "8px" }}
|
||||
>
|
||||
{user?.name && user?.family_name
|
||||
? `${user.name[0]}${user.family_name[0]}`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Autocomplete, TextField } from "@mui/material";
|
||||
import { Autocomplete, TextField } from "@linagora/twake-mui";
|
||||
import { PublicOutlined as TimezoneIcon } from "@mui/icons-material";
|
||||
import { useMemo } from "react";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Box, Typography } from "@linagora/twake-mui";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { Calendar } from "../../Calendars/CalendarTypes";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button } from "@mui/material";
|
||||
import { Button } from "@linagora/twake-mui";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { useAppDispatch } from "../../../app/hooks";
|
||||
|
||||
@@ -13,7 +13,7 @@ import PeopleAltOutlinedIcon from "@mui/icons-material/PeopleAltOutlined";
|
||||
import RepeatIcon from "@mui/icons-material/Repeat";
|
||||
import SubjectIcon from "@mui/icons-material/Subject";
|
||||
import VideocamIcon from "@mui/icons-material/Videocam";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Box, Typography } from "@linagora/twake-mui";
|
||||
import EventPopover from "./EventModal";
|
||||
import {
|
||||
Button,
|
||||
@@ -23,8 +23,8 @@ import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import AvatarGroup from "@mui/material/AvatarGroup";
|
||||
} from "@linagora/twake-mui";
|
||||
import { AvatarGroup } from "@linagora/twake-mui";
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import { CalendarName } from "../../components/Calendar/CalendarName";
|
||||
@@ -49,7 +49,6 @@ import { userAttendee } from "../User/models/attendee";
|
||||
import { browserDefaultTimeZone } from "../../utils/timezone";
|
||||
import { AttendanceValidation } from "./AttendanceValidation/AttendanceValidation";
|
||||
import { Calendar } from "../Calendars/CalendarTypes";
|
||||
import { userData } from "../User/userDataTypes";
|
||||
import { createEventContext } from "./createEventContext";
|
||||
|
||||
export default function EventPreviewModal({
|
||||
@@ -369,7 +368,9 @@ export default function EventPreviewModal({
|
||||
`${mailSpaUrl}/mailto/?uri=mailto:${event.attendee
|
||||
.map((a) => a.cal_address)
|
||||
.filter((mail) => mail !== user.email)
|
||||
.join(",")}?subject=${event.title}`
|
||||
.join(
|
||||
","
|
||||
)}?subject=${encodeURIComponent(event.title ?? "")}`
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -402,18 +403,28 @@ export default function EventPreviewModal({
|
||||
eventId
|
||||
)
|
||||
);
|
||||
setOpenEditModePopup("edit");
|
||||
setOpenEditModePopup("delete");
|
||||
} else {
|
||||
onClose({}, "backdropClick");
|
||||
await dispatch(
|
||||
deleteEventAsync({
|
||||
calId,
|
||||
eventId,
|
||||
eventURL: event.URL,
|
||||
})
|
||||
);
|
||||
try {
|
||||
const result = await dispatch(
|
||||
deleteEventAsync({
|
||||
calId,
|
||||
eventId,
|
||||
eventURL: event.URL,
|
||||
})
|
||||
);
|
||||
|
||||
// For compatibility with tests that may not mock unwrap
|
||||
if (result && typeof result.unwrap === "function") {
|
||||
await result.unwrap();
|
||||
}
|
||||
|
||||
updateTempList();
|
||||
} catch (error) {
|
||||
console.error("Failed to delete event:", error);
|
||||
}
|
||||
}
|
||||
updateTempList();
|
||||
}}
|
||||
>
|
||||
{t("eventPreview.deleteEvent")}
|
||||
@@ -616,7 +627,15 @@ export default function EventPreviewModal({
|
||||
}
|
||||
text={t("eventPreview.alarmText", {
|
||||
trigger: t(`event.form.notifications.${event.alarm.trigger}`),
|
||||
action: t(`event.form.notifications.${event.alarm.action}`),
|
||||
action: (() => {
|
||||
if (!event.alarm.action) return "";
|
||||
const translationKey = `event.form.notifications.${event.alarm.action}`;
|
||||
const translated = t(translationKey);
|
||||
// If translation returns the key itself, it means translation not found, use raw value
|
||||
return translated === translationKey
|
||||
? event.alarm.action
|
||||
: translated;
|
||||
})(),
|
||||
})}
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CalendarApi, DateSelectArg } from "@fullcalendar/core";
|
||||
import { Box, Button } from "@mui/material";
|
||||
import { Box, Button } from "@linagora/twake-mui";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import React, {
|
||||
useEffect,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Button } from "@mui/material";
|
||||
import { Box, Button } from "@linagora/twake-mui";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import { useEffect, useState, useMemo, useCallback, useRef } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
|
||||
@@ -2,8 +2,14 @@ import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||
import RepeatIcon from "@mui/icons-material/Repeat";
|
||||
import SquareRoundedIcon from "@mui/icons-material/SquareRounded";
|
||||
import VideocamIcon from "@mui/icons-material/Videocam";
|
||||
import { Box, Button, IconButton, Stack, Typography } from "@mui/material";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
IconButton,
|
||||
Stack,
|
||||
Typography,
|
||||
CircularProgress,
|
||||
} from "@linagora/twake-mui";
|
||||
import { useI18n } from "twake-i18n";
|
||||
import { useState } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
Snackbar,
|
||||
Switch,
|
||||
FormControlLabel,
|
||||
} from "@mui/material";
|
||||
} from "@linagora/twake-mui";
|
||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||
import SettingsIcon from "@mui/icons-material/Settings";
|
||||
// import SyncIcon from "@mui/icons-material/Sync";
|
||||
@@ -418,11 +418,7 @@ export default function SettingsPage() {
|
||||
)}
|
||||
{activeSettingsSubTab === "notifications" && (
|
||||
<Box className="settings-tab-content">
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{ mb: 3 }}
|
||||
>
|
||||
<Typography variant="h6" sx={{ mb: 3 }}>
|
||||
{t("settings.notifications.deliveryMethod") ||
|
||||
"Delivery method"}
|
||||
</Typography>
|
||||
|
||||
+4
-1
@@ -152,7 +152,9 @@
|
||||
"-PT1D": "1 day before",
|
||||
"-PT2D": "2 days before",
|
||||
"-PT1W": "1 week before",
|
||||
"EMAIL": "email"
|
||||
"EMAIL": "email",
|
||||
"DISPLAY": "display",
|
||||
"AUDIO": "audio"
|
||||
},
|
||||
"showMeAs": "Show me as",
|
||||
"free": "Free",
|
||||
@@ -188,6 +190,7 @@
|
||||
"editModeDialog": {
|
||||
"updateRecurrentEvent": "Update the recurrent event",
|
||||
"updateParticipationStatus": "Update the participation status",
|
||||
"deleteRecurrentEvent": "Delete the recurrent event",
|
||||
"thisEvent": "This event",
|
||||
"allEvents": "All the events"
|
||||
},
|
||||
|
||||
+3
-1
@@ -154,7 +154,9 @@
|
||||
"-PT1D": "1 jour avant",
|
||||
"-PT2D": "2 jours avant",
|
||||
"-PT1W": "1 semaine avant",
|
||||
"EMAIL": "e-mail"
|
||||
"EMAIL": "e-mail",
|
||||
"DISPLAY": "affichage",
|
||||
"AUDIO": "audio"
|
||||
},
|
||||
"showMeAs": "M'afficher comme",
|
||||
"free": "Libre",
|
||||
|
||||
+3
-1
@@ -154,7 +154,9 @@
|
||||
"-PT1D": "За 1 день",
|
||||
"-PT2D": "За 2 дня",
|
||||
"-PT1W": "За 1 неделю",
|
||||
"EMAIL": "Email"
|
||||
"EMAIL": "Email",
|
||||
"DISPLAY": "Отображение",
|
||||
"AUDIO": "Звук"
|
||||
},
|
||||
"showMeAs": "Показать как",
|
||||
"free": "Свободен",
|
||||
|
||||
+3
-1
@@ -152,7 +152,9 @@
|
||||
"-PT1D": "1 ngày trước",
|
||||
"-PT2D": "2 ngày trước",
|
||||
"-PT1W": "1 tuần trước",
|
||||
"EMAIL": "email"
|
||||
"EMAIL": "email",
|
||||
"DISPLAY": "hiển thị",
|
||||
"AUDIO": "âm thanh"
|
||||
},
|
||||
"showMeAs": "Hiển thị tôi là",
|
||||
"free": "Rảnh",
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import React from "react";
|
||||
import { ThemeProvider } from "@mui/material/styles";
|
||||
import { CssBaseline } from "@mui/material";
|
||||
import { customTheme } from "./theme";
|
||||
|
||||
interface CustomThemeProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function CustomThemeProvider({ children }: CustomThemeProviderProps) {
|
||||
return (
|
||||
<ThemeProvider theme={customTheme}>
|
||||
<CssBaseline />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export { customTheme };
|
||||
@@ -1,38 +0,0 @@
|
||||
import { createTheme } from "@mui/material/styles";
|
||||
|
||||
// Custom theme for Twake Calendar
|
||||
export const customTheme = createTheme({
|
||||
palette: {
|
||||
text: {
|
||||
primary: "#000000",
|
||||
secondary: "#717D96",
|
||||
secondaryContainer: "#243B55",
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
caption: {
|
||||
fontSize: "0.75rem",
|
||||
fontWeight: 400,
|
||||
lineHeight: 1.4,
|
||||
color: "#8C9CAF", // Custom secondary text color
|
||||
},
|
||||
},
|
||||
components: {
|
||||
// Custom Typography component
|
||||
MuiTypography: {
|
||||
styleOverrides: {
|
||||
// Custom variant for event info text
|
||||
caption: {
|
||||
fontSize: "13px",
|
||||
color: "#717D96",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Custom Button component
|
||||
// Custom Dialog component
|
||||
// Custom DialogActions component
|
||||
},
|
||||
});
|
||||
|
||||
// Export theme type for TypeScript
|
||||
export type CustomTheme = typeof customTheme;
|
||||
@@ -0,0 +1,11 @@
|
||||
import { nameToColor } from "@linagora/twake-mui";
|
||||
|
||||
/**
|
||||
* Generate a gradient color from a string
|
||||
* @param str - String to generate color from
|
||||
* @returns Color name for gradient
|
||||
*/
|
||||
export function stringToGradient(str: string): string | undefined {
|
||||
if (!str) return undefined;
|
||||
return nameToColor(str);
|
||||
}
|
||||
Reference in New Issue
Block a user