diff --git a/__test__/features/user/HandleLogin.test.tsx b/__test__/features/user/HandleLogin.test.tsx
index c5799fa..6cc1717 100644
--- a/__test__/features/user/HandleLogin.test.tsx
+++ b/__test__/features/user/HandleLogin.test.tsx
@@ -56,7 +56,7 @@ describe("HandleLogin", () => {
};
renderWithProviders(, preloadedState);
- expect(screen.getByAltText(/loading/i)).toBeInTheDocument();
+ expect(screen.getByTestId("loading")).toBeInTheDocument();
});
test("shows Loading when userData exists and calendars pending is false", () => {
const preloadedState = {
@@ -71,7 +71,7 @@ describe("HandleLogin", () => {
};
renderWithProviders(, preloadedState);
- expect(screen.getByAltText("loading")).toBeInTheDocument();
+ expect(screen.getByTestId("loading")).toBeInTheDocument();
});
test("goes to error page when there is error in user data", () => {
const dispatch = appHooks.useAppDispatch();
diff --git a/jest.config.ts b/jest.config.ts
index 62e3e5d..a02a470 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -35,7 +35,7 @@ const config: Config = {
"/fileTransformer.ts",
},
transformIgnorePatterns: [
- "/node_modules/(?!(preact|@fullcalendar|react-calendar|get-user-locale|memoize|mimic-function|@wojtekmaj|ky|cozy-ui|p-map|@linagora/twake-mui)/)",
+ "/node_modules/(?!(preact|@fullcalendar|react-calendar|get-user-locale|memoize|mimic-function|@wojtekmaj|ky|cozy-ui|p-map|@linagora/twake-mui|@lottiefiles)/)",
],
moduleNameMapper: {
diff --git a/package-lock.json b/package-lock.json
index 8b2aaeb..080aefc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"@fullcalendar/react": "^6.1.17",
"@fullcalendar/timegrid": "^6.1.17",
"@linagora/twake-mui": "^1.1.3",
+ "@lottiefiles/dotlottie-react": "^0.17.13",
"@mui/icons-material": "^7.1.2",
"@mui/material": "^7.1.2",
"@mui/x-date-pickers": "^8.14.0",
@@ -138,7 +139,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -2071,7 +2071,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=18"
},
@@ -2095,7 +2094,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -2198,7 +2196,6 @@
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -2242,7 +2239,6 @@
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -2515,7 +2511,6 @@
"resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.20.tgz",
"integrity": "sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"preact": "~10.12.1"
}
@@ -3158,6 +3153,22 @@
"react-dom": "^18.2.0"
}
},
+ "node_modules/@lottiefiles/dotlottie-react": {
+ "version": "0.17.13",
+ "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-react/-/dotlottie-react-0.17.13.tgz",
+ "integrity": "sha512-Ui8bqFlxqxLqB3G4bE9nsSw05lUn7eiZ24dSi/NVHFjTMAlb/JxdS8xWt1cdF2W1yJPNCeQuze6kkqNC5OMbJg==",
+ "dependencies": {
+ "@lottiefiles/dotlottie-web": "0.61.0"
+ },
+ "peerDependencies": {
+ "react": "^17 || ^18 || ^19"
+ }
+ },
+ "node_modules/@lottiefiles/dotlottie-web": {
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-web/-/dotlottie-web-0.61.0.tgz",
+ "integrity": "sha512-1QwcDchh/TXTvP9zXUHA5oJOdhEdUrn6U7gAiQ1AXEUrcK6PTU6v5D3byP76BK56fQjoY2WQ2A4pYDCCvoVRqw=="
+ },
"node_modules/@module-federation/error-codes": {
"version": "0.21.6",
"resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.21.6.tgz",
@@ -3258,7 +3269,6 @@
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.6.tgz",
"integrity": "sha512-R4DaYF3dgCQCUAkr4wW1w26GHXcf5rCmBRHVBuuvJvaGLmZdD8EjatP80Nz5JCw0KxORAzwftnHzXVnjR8HnFw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4",
"@mui/core-downloads-tracker": "^7.3.6",
@@ -3369,7 +3379,6 @@
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.6.tgz",
"integrity": "sha512-8fehAazkHNP1imMrdD2m2hbA9sl7Ur6jfuNweh5o4l9YPty4iaZzRXqYvBCWQNwFaSHmMEj2KPbyXGp7Bt73Rg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4",
"@mui/private-theming": "^7.3.6",
@@ -3728,7 +3737,6 @@
"integrity": "sha512-LvoOF53PL6zXgdzEhgnnP51S4FseDFH1bHrobK4EK6zZX/tN8qgf5tdlmN7h4OkMv/Qs1oUfvj0QcLWSstnnvA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@rspack/core": "1.6.8",
"@rspack/lite-tapable": "~1.1.0",
@@ -3956,7 +3964,6 @@
"integrity": "sha512-FolcIAH5FW4J2FET+qwjd1kNeFbCkd0VLuIHO0thyolEjaPSxw5qxG67DA7BZGm6PVcoiSgPLks1DL6eZ8c+fA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@module-federation/runtime-tools": "0.21.6",
"@rspack/binding": "1.6.8",
@@ -4216,7 +4223,6 @@
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0",
@@ -4301,7 +4307,6 @@
"integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"tslib": "^2.8.0"
}
@@ -4312,7 +4317,6 @@
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -4608,7 +4612,6 @@
"integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -4630,7 +4633,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.2.2"
@@ -4642,7 +4644,6 @@
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"peerDependencies": {
"@types/react": "^18.0.0"
}
@@ -4699,7 +4700,6 @@
"integrity": "sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.51.0",
@@ -4729,7 +4729,6 @@
"integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.51.0",
"@typescript-eslint/types": "8.51.0",
@@ -5236,7 +5235,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5996,7 +5994,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -6708,7 +6705,6 @@
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.21.0"
},
@@ -6724,8 +6720,7 @@
"version": "1.11.19",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
@@ -7324,7 +7319,6 @@
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -8679,7 +8673,6 @@
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.7.6"
}
@@ -9654,7 +9647,6 @@
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@jest/core": "30.2.0",
"@jest/types": "30.2.0",
@@ -10418,7 +10410,6 @@
"integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/core": "^7.19.6",
"@svgr/babel-preset": "^6.5.1",
@@ -10877,7 +10868,6 @@
"integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"cssstyle": "^4.2.1",
"data-urls": "^5.0.0",
@@ -11314,7 +11304,6 @@
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"license": "MIT",
- "peer": true,
"engines": {
"node": "*"
}
@@ -11324,7 +11313,6 @@
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz",
"integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"moment": "^2.29.4"
},
@@ -11360,6 +11348,7 @@
}
],
"license": "MIT",
+ "peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -12308,7 +12297,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -12331,7 +12319,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -12351,7 +12338,6 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@@ -12376,7 +12362,6 @@
"integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -12477,8 +12462,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/redux-first-history": {
"version": "5.2.0",
@@ -13705,7 +13689,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -13886,7 +13869,6 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
- "peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -14103,7 +14085,6 @@
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -14912,7 +14893,6 @@
"integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==",
"dev": true,
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
diff --git a/package.json b/package.json
index fd87918..9b24b6f 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@fullcalendar/react": "^6.1.17",
"@fullcalendar/timegrid": "^6.1.17",
"@linagora/twake-mui": "^1.1.3",
+ "@lottiefiles/dotlottie-react": "^0.17.13",
"@mui/icons-material": "^7.1.2",
"@mui/material": "^7.1.2",
"@mui/x-date-pickers": "^8.14.0",
diff --git a/public/loadercalendar.lottie b/public/loadercalendar.lottie
new file mode 100644
index 0000000..d4feeb8
Binary files /dev/null and b/public/loadercalendar.lottie differ
diff --git a/src/components/Calendar/AccessTab.tsx b/src/components/Calendar/AccessTab.tsx
index e753cf6..03f4764 100644
--- a/src/components/Calendar/AccessTab.tsx
+++ b/src/components/Calendar/AccessTab.tsx
@@ -88,7 +88,8 @@ export function AccessTab({ calendar }: { calendar: Calendar }) {
tr.fc-scrollgrid-section:first-of-type .fc-scroller
position absolute
width 1px
whiteSpace nowrap
+.date-time-group .MuiFormControl-root
+ margin: 0
+.date-time-group.show-full-field > .MuiBox-root:first-of-type
+ margin-bottom: 8px
diff --git a/src/components/Calendar/ImportTab.tsx b/src/components/Calendar/ImportTab.tsx
index f8f30b2..2988fd9 100644
--- a/src/components/Calendar/ImportTab.tsx
+++ b/src/components/Calendar/ImportTab.tsx
@@ -53,27 +53,30 @@ export function ImportTab({
}, [importFile, importUrl, importMode]);
return (
-
+ <>
+ {/* Form group 1: Select file button - first group, margin top 0 */}
{importMode === "file" && (
- <>
-
-
-
+
+
{importFile && (
-
+
{importFile.name}
)}
@@ -81,38 +84,67 @@ export function ImportTab({
variant="caption"
color="text.secondary"
display="block"
- mb={2}
+ sx={{ marginTop: "6px" }}
>
{t("calendar.import_file_description")}
- >
+
)}
+ {/* Form group 2: URL field */}
{importMode === "url" && (
-
+ setImportUrl(e.target.value)}
+ size="small"
+ margin="dense"
+ sx={{
+ "&.MuiFormControl-root.MuiFormControl-marginDense": {
+ marginTop: "6px",
+ marginBottom: 0,
+ },
+ }}
+ />
+
+ )}
+
+ {/* Form group 3: Import to */}
+
+ setImportUrl(e.target.value)}
size="small"
margin="dense"
- />
- )}
-
-
- {t("calendar.import_to")}
-
-
+
+ {t("calendar.import_to")}
+
+
+
+
- {importTarget === "new" && }
-
+ {/* Form group 4: SettingsTab (when importing to new calendar) */}
+ {importTarget === "new" && (
+
+
+
+ )}
+ >
);
}
diff --git a/src/components/Calendar/SettingsTab.tsx b/src/components/Calendar/SettingsTab.tsx
index a979a99..d0f1528 100644
--- a/src/components/Calendar/SettingsTab.tsx
+++ b/src/components/Calendar/SettingsTab.tsx
@@ -49,62 +49,79 @@ export function SettingsTab({
}, [description]);
return (
-
- setName(e.target.value)}
- size="small"
- margin="dense"
- />
-
-
-
-
-
- {t("calendar.color")}
-
- setColor(color)}
- selectedColor={color}
+ <>
+ {/* Form group 1: Name field - first group, margin top 0 */}
+
+ setName(e.target.value)}
+ size="small"
+ sx={{
+ "&.MuiFormControl-root": {
+ marginTop: 0,
+ marginBottom: 0,
+ },
+ }}
/>
+ {/* Form group 2: Description */}
+
+
+
+
+ {/* Form group 3: Color */}
+
+
+ {t("calendar.color")}
+
+
+ setColor(color)}
+ selectedColor={color}
+ />
+
+
+
+ {/* Form group 4: New events visibility */}
{isOwn && (
-
+
{t("calendar.newEventsVisibility")}
- val && setVisibility(val)}
- size="medium"
- sx={{ borderRadius: "12px" }}
- >
-
-
- {t("common.all")}
-
+
+ val && setVisibility(val)}
+ size="medium"
+ sx={{ borderRadius: "12px" }}
+ >
+
+
+ {t("common.all")}
+
-
-
- {t("common.you")}
-
-
+
+
+ {t("common.you")}
+
+
+
)}
-
+ >
);
}
diff --git a/src/components/Dialog/README.md b/src/components/Dialog/README.md
index df79a66..da65225 100644
--- a/src/components/Dialog/README.md
+++ b/src/components/Dialog/README.md
@@ -9,7 +9,7 @@ A highly reusable dialog component that supports both normal and expanded (fulls
- ✅ **Clean Expanded View**: No backdrop/shadow in expanded mode for seamless integration
- ✅ **Instant Transition**: No animation when expanding for immediate feedback
- ✅ **Back Navigation**: Expanded mode shows back arrow icon in header for easy collapse
-- ✅ **MUI Stack Spacing**: Uses MUI Stack component with configurable spacing prop (2=16px normal, 3=24px expanded)
+- ✅ **MUI Stack Spacing**: Uses MUI Stack component with configurable spacing prop (2=16px for both normal and expanded modes)
- ✅ **Fully Customizable**: Override styles with `sx`, `contentSx`, `titleSx` props
- ✅ **Container Support**: Content container with configurable max-width
- ✅ **Type Safe**: Full TypeScript support
@@ -45,7 +45,7 @@ function MyComponent() {
>
- {/* Wrapped in Stack with spacing={2} (normal) or spacing={3} (expanded) */}
+ {/* Wrapped in Stack with spacing={2} for both normal and expanded modes */}
);
}
@@ -66,7 +66,7 @@ function MyComponent() {
| `expandedContentMaxWidth` | `string` | `"990px"` | Content container max-width in expanded mode |
| `headerHeight` | `string` | `"90px"` | App header height to preserve |
| `normalSpacing` | `number` | `2` | Stack spacing in normal mode (MUI spacing units: 1 = 8px) |
-| `expandedSpacing` | `number` | `3` | Stack spacing in expanded mode (MUI spacing units: 1 = 8px) |
+| `expandedSpacing` | `number` | `2` | Stack spacing in expanded mode (MUI spacing units: 1 = 8px) |
| `contentSx` | `SxProps` | - | Custom styles for DialogContent |
| `titleSx` | `SxProps` | - | Custom styles for DialogTitle |
| `dialogContentProps` | `DialogContentProps` | - | Additional DialogContent props |
@@ -175,7 +175,7 @@ For apps with different header heights:
- Shadow: removed (no elevation in expanded mode)
- Transition: disabled (instant expand/collapse for better UX)
- Title: replaced by back arrow IconButton (calls `onExpandToggle`)
-- Children spacing: `expandedSpacing={3}` (24px via MUI Stack component)
+- Children spacing: `expandedSpacing={2}` (16px via MUI Stack component)
- Actions (MuiBox): max-width = `expandedContentMaxWidth` (990px), centered container with buttons right-aligned
- padding: 0 12px
- width: 100%
diff --git a/src/components/Dialog/ResponsiveDialog.tsx b/src/components/Dialog/ResponsiveDialog.tsx
index 56e3315..19b47c6 100644
--- a/src/components/Dialog/ResponsiveDialog.tsx
+++ b/src/components/Dialog/ResponsiveDialog.tsx
@@ -66,7 +66,7 @@ interface ResponsiveDialogProps extends Omit<
headerHeight?: string;
/** Spacing between children in normal mode (default: 2 = 16px) */
normalSpacing?: number;
- /** Spacing between children in expanded mode (default: 3 = 24px) */
+ /** Spacing between children in expanded mode (default: 2 = 16px) */
expandedSpacing?: number;
/** Custom styles for DialogContent - merged with base styles */
contentSx?: SxProps;
@@ -102,7 +102,7 @@ function ResponsiveDialog({
expandedContentMaxWidth = "990px",
headerHeight = "90px",
normalSpacing = 2,
- expandedSpacing = 3,
+ expandedSpacing = 2,
contentSx,
titleSx,
dialogContentProps,
diff --git a/src/components/Event/AddDescButton.tsx b/src/components/Event/AddDescButton.tsx
index a5f7d6f..9c44c9f 100644
--- a/src/components/Event/AddDescButton.tsx
+++ b/src/components/Event/AddDescButton.tsx
@@ -32,7 +32,7 @@ export function AddDescButton({
<>
{!showDescription && (
-
+
}
onClick={() => setShowDescription(true)}
diff --git a/src/components/Event/EventChip/EventChip.tsx b/src/components/Event/EventChip/EventChip.tsx
index 2d44a73..485e198 100644
--- a/src/components/Event/EventChip/EventChip.tsx
+++ b/src/components/Event/EventChip/EventChip.tsx
@@ -245,6 +245,7 @@ export function EventChip({
whiteSpace: "normal",
flex: 1,
maxWidth: "75%",
+ color: titleStyle.color,
}}
>
{event._def.extendedProps.description}
diff --git a/src/components/Event/EventFormFields.tsx b/src/components/Event/EventFormFields.tsx
index ce3a6b9..8a4357d 100644
--- a/src/components/Event/EventFormFields.tsx
+++ b/src/components/Event/EventFormFields.tsx
@@ -13,6 +13,7 @@ import {
TextField,
ToggleButtonGroup,
ToggleButton,
+ Typography,
} from "@linagora/twake-mui";
import {
Description as DescriptionIcon,
@@ -481,7 +482,9 @@ export default function EventFormFields({
control={
}
- label={t("event.form.allDay")}
+ label={
+ {t("event.form.allDay")}
+ }
/>
}
- label={t("event.form.repeat")}
+ label={
+ {t("event.form.repeat")}
+ }
/>
{/* Interval */}
- {t("event.repeat.repeatEvery")}
+ {t("event.repeat.repeatEvery")}
-
+
{t("event.repeat.end.label")}
}
- label={t("event.repeat.end.never")}
+ label={
+
+ {t("event.repeat.end.never")}
+
+ }
/>
}
label={
- {t("event.repeat.end.after")}
+
+ {t("event.repeat.end.after")}
+
- {t("event.repeat.end.occurrences")}
+
+ {t("event.repeat.end.occurrences")}
+
}
/>
@@ -229,7 +237,9 @@ export default function RepeatEvent({
control={}
label={
- {t("event.repeat.end.on")}
+
+ {t("event.repeat.end.on")}
+
= ({
{isExpanded || shouldShowFullFieldsInNormal ? (
diff --git a/src/components/Event/components/FieldWithLabel.tsx b/src/components/Event/components/FieldWithLabel.tsx
index af6f0e0..5a86268 100644
--- a/src/components/Event/components/FieldWithLabel.tsx
+++ b/src/components/Event/components/FieldWithLabel.tsx
@@ -19,19 +19,52 @@ export const FieldWithLabel = React.memo(
}) => {
if (!isExpanded) {
// Normal mode: label on top
+ const isEmptyLabel =
+ label === null ||
+ label === undefined ||
+ (typeof label === "string" && label.trim() === "");
+
return (
-
-
- {label}
-
+ *:not(:first-of-type)": {
+ marginTop: isEmptyLabel ? 0 : "6px",
+ },
+ // Only apply margin to direct child MuiTextField-root
+ "& > .MuiFormControl-root": {
+ marginTop: "6px",
+ marginBottom: 0,
+ },
+ "& > .MuiTextField-root": {
+ marginTop: "6px",
+ marginBottom: 0,
+ },
+ // Reset margin for nested MuiTextField-root
+ "& .MuiFormControl-root .MuiTextField-root": {
+ marginTop: 0,
+ marginBottom: 0,
+ },
+ "& .MuiTextField-root .MuiTextField-root": {
+ marginTop: 0,
+ marginBottom: 0,
+ },
+ // Reset margin for nested Box children (DateTimeFields structure)
+ "& > .MuiBox-root > .MuiBox-root": {
+ marginTop: 0,
+ },
+ "& > .MuiBox-root > .MuiBox-root > .MuiBox-root": {
+ marginTop: 0,
+ },
+ },
+ ...(Array.isArray(sx) ? sx : sx ? [sx] : []),
+ ]}
+ >
+ {!isEmptyLabel && (
+
+ {label}
+
+ )}
{children}
);
@@ -42,17 +75,35 @@ export const FieldWithLabel = React.memo(
{label}
- {children}
+ .MuiBox-root > .MuiBox-root:nth-of-type(2)": {
+ marginTop: "8px",
+ },
+ // Remove margin from MuiFormControl-root MuiFormControl-marginDense in extended mode
+ "& .MuiFormControl-root.MuiFormControl-marginDense": {
+ marginTop: 0,
+ marginBottom: 0,
+ },
+ "& .MuiTextField-root.MuiFormControl-marginDense": {
+ marginTop: 0,
+ marginBottom: 0,
+ },
+ }}
+ >
+ {children}
+
);
}
diff --git a/src/components/Loading/Loading.tsx b/src/components/Loading/Loading.tsx
index 02bf97e..bec86cd 100644
--- a/src/components/Loading/Loading.tsx
+++ b/src/components/Loading/Loading.tsx
@@ -1,6 +1,41 @@
import React from "react";
-import logo from "../../static/images/calendar.svg";
+import { DotLottieReact } from "@lottiefiles/dotlottie-react";
+import { Box } from "@linagora/twake-mui";
+import twakeLogo from "../../static/twake-workplace.svg";
export function Loading() {
- return
;
+ return (
+
+
+
+
+ );
}
diff --git a/src/setupTests.ts b/src/setupTests.ts
index 5a47074..0db69b8 100644
--- a/src/setupTests.ts
+++ b/src/setupTests.ts
@@ -51,6 +51,14 @@ class ResizeObserverMock {
(global as any).ResizeObserver = ResizeObserverMock;
+class IntersectionObserverMock {
+ observe() {}
+ unobserve() {}
+ disconnect() {}
+}
+
+(global as any).IntersectionObserver = IntersectionObserverMock;
+
beforeAll(() => {
console.warn = (...args: unknown[]) => {
if (
diff --git a/src/static/loadercalendar.lottie b/src/static/loadercalendar.lottie
new file mode 100644
index 0000000..d4feeb8
Binary files /dev/null and b/src/static/loadercalendar.lottie differ
diff --git a/src/static/twake-workplace.svg b/src/static/twake-workplace.svg
new file mode 100644
index 0000000..dab29ba
--- /dev/null
+++ b/src/static/twake-workplace.svg
@@ -0,0 +1,12 @@
+