From aeb8670895dd3e5d97a742f8f0a744e698897da0 Mon Sep 17 00:00:00 2001
From: lenhanphung <44486647+lenhanphung@users.noreply.github.com>
Date: Tue, 20 Jan 2026 15:14:03 +0700
Subject: [PATCH] UI/update global UI (#459)
* Update loading screen to use Lottie animation
- Replace simple logo with Lottie animation from loadercalendar.lottie
- Center animation on screen with full viewport coverage
- Set animation width to 175px
- Install @lottiefiles/dotlottie-react package
* update spacing event modal
* add twake workplace logo to loading screen
* update spacing create calendar modal
* fix evenchip description color
* using variant instead of sx
---
__test__/features/user/HandleLogin.test.tsx | 4 +-
jest.config.ts | 2 +-
package-lock.json | 60 +++------
package.json | 1 +
public/loadercalendar.lottie | Bin 0 -> 3197 bytes
src/components/Calendar/AccessTab.tsx | 6 +-
src/components/Calendar/CustomCalendar.styl | 4 +
src/components/Calendar/ImportTab.tsx | 114 +++++++++++-------
src/components/Calendar/SettingsTab.tsx | 111 +++++++++--------
src/components/Dialog/README.md | 8 +-
src/components/Dialog/ResponsiveDialog.tsx | 4 +-
src/components/Event/AddDescButton.tsx | 2 +-
src/components/Event/EventChip/EventChip.tsx | 1 +
src/components/Event/EventFormFields.tsx | 9 +-
src/components/Event/EventRepeat.tsx | 22 +++-
.../Event/components/DateTimeFields.tsx | 3 +
.../Event/components/FieldWithLabel.tsx | 81 ++++++++++---
src/components/Loading/Loading.tsx | 39 +++++-
src/setupTests.ts | 8 ++
src/static/loadercalendar.lottie | Bin 0 -> 3197 bytes
src/static/twake-workplace.svg | 12 ++
21 files changed, 326 insertions(+), 165 deletions(-)
create mode 100644 public/loadercalendar.lottie
create mode 100644 src/static/loadercalendar.lottie
create mode 100644 src/static/twake-workplace.svg
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 0000000000000000000000000000000000000000..d4feeb83b0633d93ef1727ee915fb65a6609f6f4
GIT binary patch
literal 3197
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
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..d4feeb83b0633d93ef1727ee915fb65a6609f6f4
GIT binary patch
literal 3197
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
literal 0
HcmV?d00001
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 @@
+