Fix button style, button type (#450)

This commit is contained in:
lenhanphung
2026-01-13 17:36:10 +07:00
committed by GitHub
parent aaaa2599ed
commit 2482e9f957
15 changed files with 336 additions and 276 deletions
+2 -2
View File
@@ -35,7 +35,7 @@ const config: Config = {
"<rootDir>/fileTransformer.ts",
},
transformIgnorePatterns: [
"/node_modules/(?!(preact|@fullcalendar|react-calendar|get-user-locale|memoize|mimic-function|@wojtekmaj|ky|cozy-ui|p-map)/)",
"/node_modules/(?!(preact|@fullcalendar|react-calendar|get-user-locale|memoize|mimic-function|@wojtekmaj|ky|cozy-ui|p-map|@linagora/twake-mui)/)",
],
moduleNameMapper: {
@@ -65,7 +65,7 @@ const config: Config = {
"^.+\\.tsx?$": ["ts-jest", { tsconfig: "tsconfig.json" }],
"^.+\\.(js|jsx|mjs)$": "babel-jest",
},
transformIgnorePatterns: ["/node_modules/(?!(ky)/)"],
transformIgnorePatterns: ["/node_modules/(?!(ky|@linagora/twake-mui)/)"],
setupFilesAfterEnv: ["<rootDir>/src/setupTests.ts"],
},
],
+7 -45
View File
@@ -17,7 +17,7 @@
"@fullcalendar/moment-timezone": "^6.1.19",
"@fullcalendar/react": "^6.1.17",
"@fullcalendar/timegrid": "^6.1.17",
"@linagora/twake-mui": "1.1.1",
"@linagora/twake-mui": "^1.1.3",
"@mui/icons-material": "^7.1.2",
"@mui/material": "^7.1.2",
"@mui/x-date-pickers": "^8.14.0",
@@ -138,7 +138,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 +2070,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
},
@@ -2095,7 +2093,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
}
@@ -2198,7 +2195,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 +2238,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 +2510,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"
}
@@ -3139,10 +3133,9 @@
}
},
"node_modules/@linagora/twake-mui": {
"version": "1.1.1",
"resolved": "https://npm.pkg.github.com/download/@linagora/twake-mui/1.1.1/16fcea760c76c020860b19640c010ddc4c1ba9f3",
"integrity": "sha512-3MCOnhiwUKUI4WH/Mrx6R9cyyCJZoIKbc6TUoTQew8s4PprhvXI+xElOOVgBsCdCkZ9DOpeOOrcvMzDbd9JYNg==",
"license": "MIT",
"version": "1.1.3",
"resolved": "https://npm.pkg.github.com/download/@linagora/twake-mui/1.1.3/c8ed9f2e04beaf55c1cfd1e014d2f43081c975ae",
"integrity": "sha512-lLylOmnMOpXRlkFCsKq2Jaf1bfaobQsHz1fvxRIR0MIs8EAy2gyKc/5D22Q/Mqo3aN2zEum9qrd1D030lm8NJg==",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
@@ -3258,7 +3251,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 +3361,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 +3719,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 +3946,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 +4205,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 +4289,6 @@
"integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"tslib": "^2.8.0"
}
@@ -4312,7 +4299,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 +4594,6 @@
"integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -4630,7 +4615,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 +4626,6 @@
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"dev": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^18.0.0"
}
@@ -4699,7 +4682,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 +4711,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 +5217,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5996,7 +5976,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -6708,7 +6687,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 +6702,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 +7301,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 +8655,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 +9629,6 @@
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/core": "30.2.0",
"@jest/types": "30.2.0",
@@ -10418,7 +10392,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 +10850,6 @@
"integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"cssstyle": "^4.2.1",
"data-urls": "^5.0.0",
@@ -11314,7 +11286,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 +11295,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 +11330,7 @@
}
],
"license": "MIT",
"peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -12308,7 +12279,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 +12301,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 +12320,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 +12344,6 @@
"integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -12477,8 +12444,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 +13671,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -13886,7 +13851,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 +14067,6 @@
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -14912,7 +14875,6 @@
"integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==",
"dev": true,
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
+1 -1
View File
@@ -12,7 +12,7 @@
"@fullcalendar/moment-timezone": "^6.1.19",
"@fullcalendar/react": "^6.1.17",
"@fullcalendar/timegrid": "^6.1.17",
"@linagora/twake-mui": "1.1.1",
"@linagora/twake-mui": "^1.1.3",
"@mui/icons-material": "^7.1.2",
"@mui/material": "^7.1.2",
"@mui/x-date-pickers": "^8.14.0",
+10 -1
View File
@@ -90,6 +90,7 @@ export function AccessTab({ calendar }: { calendar: Calendar }) {
fullWidth
label={t("calendar.caldav_access")}
value={calDAVLink}
size="small"
InputProps={{
endAdornment: (
<InputAdornment position="end">
@@ -110,6 +111,7 @@ export function AccessTab({ calendar }: { calendar: Calendar }) {
fullWidth
label={t("calendar.secretUrl")}
value={secretLink}
size="small"
InputProps={{
endAdornment: (
<InputAdornment position="end">
@@ -120,7 +122,12 @@ export function AccessTab({ calendar }: { calendar: Calendar }) {
),
}}
/>
<Button variant="contained" onClick={handleResetSecretLink}>
<Button
variant="contained"
color="secondary"
onClick={handleResetSecretLink}
sx={{ borderRadius: "4px" }}
>
{t("actions.reset")}
</Button>
</Box>
@@ -142,9 +149,11 @@ export function AccessTab({ calendar }: { calendar: Calendar }) {
<Button
variant="contained"
color="secondary"
onClick={handleExport}
startIcon={!exportLoading && <FileDownloadOutlinedIcon />}
disabled={exportLoading}
sx={{ borderRadius: "4px" }}
>
{exportLoading ? (
<Box display="flex" alignItems="center" gap={1}>
+16 -9
View File
@@ -56,15 +56,22 @@ export function ImportTab({
<Box mt={2}>
{importMode === "file" && (
<>
<Button variant="outlined" component="label" sx={{ mb: 1 }}>
{t("common.select_file")}
<input
type="file"
hidden
accept=".ics"
onChange={(e) => setImportFile(e.target.files?.[0] ?? null)}
/>
</Button>
<Box mb={1}>
<Button
variant="outlined"
component="label"
size="medium"
sx={{ borderRadius: "12px" }}
>
{t("common.select_file")}
<input
type="file"
hidden
accept=".ics"
onChange={(e) => setImportFile(e.target.files?.[0] ?? null)}
/>
</Button>
</Box>
{importFile && (
<Typography variant="body2" color="text.secondary">
{importFile.name}
+4 -1
View File
@@ -67,6 +67,8 @@ export function SettingsTab({
showMore={false}
description={description}
setDescription={setDescription}
buttonVariant="contained"
buttonColor="secondary"
/>
<Box mt={2}>
@@ -88,7 +90,8 @@ export function SettingsTab({
value={visibility}
exclusive
onChange={(e, val) => val && setVisibility(val)}
size="small"
size="medium"
sx={{ borderRadius: "12px" }}
>
<ToggleButton value="public" sx={{ width: "140px" }}>
<PublicIcon fontSize="small" sx={{ mr: 1 }} />
+16 -5
View File
@@ -9,12 +9,23 @@ export function AddDescButton({
showMore,
description,
setDescription,
buttonVariant,
buttonColor,
}: {
showDescription: boolean;
setShowDescription: (b: boolean) => void;
showMore: boolean;
description: string;
setDescription: (d: string) => void;
buttonVariant?: "text" | "outlined" | "contained";
buttonColor?:
| "inherit"
| "primary"
| "secondary"
| "success"
| "error"
| "info"
| "warning";
}) {
const { t } = useI18n();
return (
@@ -25,11 +36,9 @@ export function AddDescButton({
<Button
startIcon={<DescriptionIcon />}
onClick={() => setShowDescription(true)}
size="small"
sx={{
textTransform: "none",
color: "text.secondary",
}}
size="medium"
variant={buttonVariant}
color={buttonColor}
>
{t("event.form.addDescription")}
</Button>
@@ -40,6 +49,7 @@ export function AddDescButton({
<FieldWithLabel
label={t("event.form.description")}
isExpanded={showMore}
sx={{ padding: 0, margin: 0 }}
>
<TextField
fullWidth
@@ -57,6 +67,7 @@ export function AddDescButton({
"& .MuiInputBase-root": {
maxHeight: "33%",
overflowY: "auto",
padding: 0,
},
"& textarea": {
resize: "vertical",
+1 -1
View File
@@ -166,7 +166,7 @@ export function EventChip({
{startTime}
</Typography>
)}
{DisplayedIcons(IconDisplayed)}
{DisplayedIcons(IconDisplayed, titleStyle.color)}
<Typography variant="body2" noWrap style={titleStyle}>
{event.title}
</Typography>
@@ -156,28 +156,37 @@ export function getCardStyle(
}
}
export function DisplayedIcons(IconDisplayed: IconDisplayConfig) {
export function DisplayedIcons(
IconDisplayed: IconDisplayConfig,
iconColor?: string
) {
if (!Object.values(IconDisplayed).find((b) => b === true)) return;
const iconStyle: React.CSSProperties = {
fontSize: "15px",
color: iconColor || "inherit",
marginRight: 2,
};
return (
<Box
<span
className="event-chip-icons"
style={{
display: "flex",
display: "inline-flex",
flexDirection: "row",
gap: "1px",
color: iconColor || "inherit",
margin: 0,
marginRight: "4px",
fontFamily: "inherit",
fontWeight: "inherit",
lineHeight: "inherit",
letterSpacing: "inherit",
}}
>
{IconDisplayed.needAction && (
<HelpOutlineIcon style={{ fontSize: "15px" }} />
)}
{IconDisplayed.declined && <CancelIcon style={{ fontSize: "15px" }} />}
{IconDisplayed.tentative && (
<HelpOutlineIcon style={{ fontSize: "15px" }} />
)}
{IconDisplayed.private && (
<LockOutlineIcon style={{ fontSize: "15px" }} />
)}
</Box>
{IconDisplayed.needAction && <HelpOutlineIcon style={iconStyle} />}
{IconDisplayed.declined && <CancelIcon style={iconStyle} />}
{IconDisplayed.tentative && <HelpOutlineIcon style={iconStyle} />}
{IconDisplayed.private && <LockOutlineIcon style={iconStyle} />}
</span>
);
}
+19 -10
View File
@@ -22,6 +22,7 @@ import {
ContentCopy as CopyIcon,
Close as DeleteIcon,
} from "@mui/icons-material";
import iconCamera from "../../static/images/icon-camera.svg";
import AttendeeSelector from "../Attendees/AttendeeSearch";
import RepeatEvent from "./EventRepeat";
import { RepetitionObject } from "../../features/Events/EventsTypes";
@@ -446,6 +447,8 @@ export default function EventFormFields({
showMore={showMore}
description={description}
setDescription={setDescription}
buttonVariant="contained"
buttonColor="secondary"
/>
<FieldWithLabel label={t("event.form.dateTime")} isExpanded={showMore}>
@@ -555,12 +558,15 @@ export default function EventFormFields({
>
<Box display="flex" gap={1} alignItems="center">
<Button
startIcon={<VideocamIcon />}
startIcon={
<img src={iconCamera} alt="camera" width={24} height={24} />
}
onClick={handleAddVideoConference}
size="medium"
variant="contained"
color="secondary"
sx={{
textTransform: "none",
color: "text.secondary",
borderRadius: "4px",
display: hasVideoConference ? "none" : "flex",
}}
>
@@ -570,12 +576,15 @@ export default function EventFormFields({
{hasVideoConference && meetingLink && (
<>
<Button
startIcon={<VideocamIcon />}
startIcon={
<img src={iconCamera} alt="camera" width={24} height={24} />
}
onClick={() => window.open(meetingLink, "_blank")}
size="medium"
variant="contained"
color="primary"
sx={{
textTransform: "none",
borderRadius: "4px",
mr: 1,
}}
>
@@ -716,14 +725,14 @@ export default function EventFormFields({
setEventClass(newValue);
}
}}
size="small"
size="medium"
>
<ToggleButton value="PUBLIC" sx={{ width: "140px" }}>
<PublicIcon sx={{ mr: 1, fontSize: "16px" }} />
<ToggleButton value="PUBLIC" sx={{ minWidth: "160px" }}>
<PublicIcon sx={{ mr: 1 }} />
{t("event.form.visibleAll")}
</ToggleButton>
<ToggleButton value="PRIVATE" sx={{ width: "140px" }}>
<LockIcon sx={{ mr: 1, fontSize: "16px" }} />
<ToggleButton value="PRIVATE" sx={{ minWidth: "160px" }}>
<LockIcon sx={{ mr: 1 }} />
{t("event.form.visibleParticipants")}
</ToggleButton>
</ToggleButtonGroup>
@@ -1,5 +1,5 @@
import React from "react";
import { Box, Typography } from "@linagora/twake-mui";
import { Box, Typography, SxProps, Theme } from "@linagora/twake-mui";
/**
* Helper component for field with label
@@ -10,15 +10,17 @@ export const FieldWithLabel = React.memo(
label,
isExpanded,
children,
sx,
}: {
label: string | React.ReactNode;
isExpanded: boolean;
children: React.ReactNode;
sx?: SxProps<Theme>;
}) => {
if (!isExpanded) {
// Normal mode: label on top
return (
<Box>
<Box sx={sx}>
<Typography
component="div"
sx={{
@@ -37,7 +39,7 @@ export const FieldWithLabel = React.memo(
// Extended mode: label on left
return (
<Box display="flex" alignItems="center">
<Box display="flex" alignItems="center" sx={sx}>
<Typography
component="div"
sx={{
+16 -9
View File
@@ -171,23 +171,30 @@ export function Menubar({
<div className="navigation-controls">
<ButtonGroup
variant="outlined"
size="small"
size="medium"
sx={{
height: "43px",
"& .MuiButton-root": {
color: "#525256",
borderColor: "#AEAEC0",
"& button:first-of-type": {
borderRadius: "12px 0 0 12px",
},
"& button:last-of-type": {
borderRadius: "0 12px 12px 0",
},
}}
>
<Button onClick={() => handleNavigation("prev")}>
<ChevronLeftIcon />
<Button
sx={{ width: 20 }}
onClick={() => handleNavigation("prev")}
>
<ChevronLeftIcon sx={{ height: 20 }} />
</Button>
<Button onClick={() => handleNavigation("today")}>
{t("menubar.today")}
</Button>
<Button onClick={() => handleNavigation("next")}>
<ChevronRightIcon />
<Button
sx={{ width: 20 }}
onClick={() => handleNavigation("next")}
>
<ChevronRightIcon sx={{ height: 20 }} />
</Button>
</ButtonGroup>
</div>
@@ -47,7 +47,7 @@ export function RSVPButton({
? rsvpColor[rsvpValue]
: "primary"
}
size="large"
size="medium"
sx={{ borderRadius: "50px" }}
onClick={() =>
handleRSVPClick(
+191 -174
View File
@@ -18,7 +18,6 @@ import EventPopover from "./EventModal";
import {
Button,
Chip,
DialogActions,
IconButton,
Menu,
MenuItem,
@@ -305,180 +304,150 @@ export default function EventPreviewModal({
actionsJustifyContent="center"
style={{ overflow: "auto" }}
title={
<>
<DialogActions>
<Box>
{(window as any).DEBUG && (
<IconButton
onClick={async () => {
const icsContent = await dlEvent(event);
const blob = new Blob([icsContent], {
type: "text/calendar",
});
const url = URL.createObjectURL(blob);
<Box
display="flex"
justifyContent="flex-end"
alignItems="center"
gap={0.5}
width="100%"
>
{(window as any).DEBUG && (
<IconButton
size="small"
onClick={async () => {
let url: string | null = null;
try {
const icsContent = await dlEvent(event);
const blob = new Blob([icsContent], {
type: "text/calendar",
});
url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `${eventId}.ics`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}}
>
<FileDownloadOutlinedIcon />
</IconButton>
)}
{isOrganizer && isOwn && (
<IconButton
size="small"
onClick={() => {
if (isRecurring) {
setAfterChoiceFunc(() => () => {
setHidePreview(true);
setOpenUpdateModal(true);
});
setOpenEditModePopup("edit");
} else {
setHidePreview(true);
setOpenUpdateModal(true);
}
}}
>
<EditIcon />
</IconButton>
)}
{((event.class !== "PRIVATE" && !isOwn) || isOwn) && (
<IconButton
size="small"
onClick={(e) => setToggleActionMenu(e.currentTarget)}
>
<MoreVertIcon />
</IconButton>
)}
<Menu
open={Boolean(toggleActionMenu)}
onClose={() => setToggleActionMenu(null)}
anchorEl={toggleActionMenu}
>
{mailSpaUrl && attendees.length > 0 && (
<MenuItem
onClick={() =>
window.open(
`${mailSpaUrl}/mailto/?uri=mailto:${event.attendee
.map((a) => a.cal_address)
.filter((mail) => mail !== user.email)
.join(
","
)}?subject=${encodeURIComponent(event.title ?? "")}`
)
}
>
{t("eventPreview.emailAttendees")}
</MenuItem>
)}
<EventDuplication
event={event}
onClose={() => setToggleActionMenu(null)}
onOpenDuplicate={() => {
setToggleActionMenu(null);
setHidePreview(true);
setOpenDuplicateModal(true);
}}
/>
{isOrganizer && (
<MenuItem
onClick={async () => {
if (isRecurring) {
setAfterChoiceFunc(
() => (typeOfAction?: "solo" | "all" | undefined) =>
handleDelete(
isRecurring,
typeOfAction,
onClose,
dispatch,
calendar,
event,
calId,
eventId
)
);
setOpenEditModePopup("delete");
} else {
onClose({}, "backdropClick");
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);
}
}
}}
>
{t("eventPreview.deleteEvent")}
</MenuItem>
)}
</Menu>
<IconButton
size="small"
onClick={() => onClose({}, "backdropClick")}
>
<CloseIcon />
</IconButton>
</Box>
</DialogActions>
<Box display="flex" flexDirection="row">
{event.class === "PRIVATE" &&
(isOwn ? (
<Tooltip
title={t("eventPreview.privateEvent.tooltipOwn")}
placement="top"
>
<LockOutlineIcon />
</Tooltip>
) : (
<LockOutlineIcon />
))}
<Typography
variant="h5"
sx={{
fontSize: "24px",
fontWeight: 600,
wordBreak: "break-word",
fontFamily: "Inter, sans-serif",
const link = document.createElement("a");
link.href = url;
link.download = `${eventId}.ics`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (error) {
console.error("Failed to download ICS file:", error);
} finally {
if (url) URL.revokeObjectURL(url);
}
}}
gutterBottom
>
{formatEventChipTitle(event, t)}
</Typography>
{event.transp === "TRANSPARENT" && (
<Tooltip title={t("eventPreview.free.tooltip")} placement="top">
<Chip
icon={<CircleIcon color="success" fontSize="small" />}
label={t("eventPreview.free.label")}
/>
</Tooltip>
<FileDownloadOutlinedIcon />
</IconButton>
)}
{isOrganizer && isOwn && (
<IconButton
size="small"
onClick={() => {
if (isRecurring) {
setAfterChoiceFunc(() => () => {
setHidePreview(true);
setOpenUpdateModal(true);
});
setOpenEditModePopup("edit");
} else {
setHidePreview(true);
setOpenUpdateModal(true);
}
}}
>
<EditIcon />
</IconButton>
)}
{((event.class !== "PRIVATE" && !isOwn) || isOwn) && (
<IconButton
size="small"
onClick={(e) => setToggleActionMenu(e.currentTarget)}
>
<MoreVertIcon />
</IconButton>
)}
<Menu
open={Boolean(toggleActionMenu)}
onClose={() => setToggleActionMenu(null)}
anchorEl={toggleActionMenu}
>
{mailSpaUrl && attendees.length > 0 && (
<MenuItem
onClick={() =>
window.open(
`${mailSpaUrl}/mailto/?uri=mailto:${attendees
.map((a) => a.cal_address)
.filter((mail) => mail !== user.email)
.join(
","
)}?subject=${encodeURIComponent(event.title ?? "")}`
)
}
>
{t("eventPreview.emailAttendees")}
</MenuItem>
)}
</Box>
<Typography color="text.secondaryContainer" gutterBottom>
{formatDate(event.start, t, timezone, event.allday)}
{event.end &&
formatEnd(event.start, event.end, t, timezone, event.allday) &&
` ${formatEnd(event.start, event.end, t, timezone, event.allday)} ${!event.allday ? getTimezoneOffset(timezone, new Date(event.start)) : ""}`}
</Typography>
</>
<EventDuplication
event={event}
onClose={() => setToggleActionMenu(null)}
onOpenDuplicate={() => {
setToggleActionMenu(null);
setHidePreview(true);
setOpenDuplicateModal(true);
}}
/>
{isOrganizer && (
<MenuItem
onClick={async () => {
if (isRecurring) {
setAfterChoiceFunc(
() => (typeOfAction?: "solo" | "all" | undefined) =>
handleDelete(
isRecurring,
typeOfAction,
onClose,
dispatch,
calendar,
event,
calId,
eventId
)
);
setOpenEditModePopup("delete");
} else {
onClose({}, "backdropClick");
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();
}
await updateTempList();
} catch (error) {
console.error("Failed to delete event:", error);
}
}
}}
>
{t("eventPreview.deleteEvent")}
</MenuItem>
)}
</Menu>
<IconButton
size="small"
onClick={() => onClose({}, "backdropClick")}
>
<CloseIcon />
</IconButton>
</Box>
}
actions={
<AttendanceValidation
@@ -490,6 +459,52 @@ export default function EventPreviewModal({
/>
}
>
<Box mb={3}>
<Box
display="flex"
flexDirection="row"
alignItems="center"
gap={1}
mb={1}
>
{event.class === "PRIVATE" &&
(isOwn ? (
<Tooltip
title={t("eventPreview.privateEvent.tooltipOwn")}
placement="top"
>
<LockOutlineIcon />
</Tooltip>
) : (
<LockOutlineIcon />
))}
<Typography
variant="h5"
sx={{
fontSize: "24px",
fontWeight: 600,
wordBreak: "break-word",
fontFamily: "Inter, sans-serif",
}}
>
{formatEventChipTitle(event, t)}
</Typography>
{event.transp === "TRANSPARENT" && (
<Tooltip title={t("eventPreview.free.tooltip")} placement="top">
<Chip
icon={<CircleIcon color="success" fontSize="small" />}
label={t("eventPreview.free.label")}
/>
</Tooltip>
)}
</Box>
<Typography color="text.secondaryContainer">
{formatDate(event.start, t, timezone, event.allday)}
{event.end &&
formatEnd(event.start, event.end, t, timezone, event.allday) &&
` ${formatEnd(event.start, event.end, t, timezone, event.allday)} ${!event.allday ? getTimezoneOffset(timezone, new Date(event.start)) : ""}`}
</Typography>
</Box>
{((event.class !== "PRIVATE" && !isOwn) || isOwn) && (
<>
{/* Video */}
@@ -503,9 +518,11 @@ export default function EventPreviewModal({
content={
<Button
variant="contained"
size="medium"
onClick={() =>
window.open(event.x_openpass_videoconference)
}
sx={{ borderRadius: "4px" }}
>
{t("eventPreview.joinVideo")}
</Button>
@@ -701,11 +718,11 @@ export default function EventPreviewModal({
)}
{/* Calendar color dot */}
<Box
style={{
sx={{
display: "flex",
alignItems: "center",
gap: 1,
marginBottom: 2,
mb: 2,
}}
>
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
@@ -775,7 +792,7 @@ export default function EventPreviewModal({
calendarRef={{ current: null }}
onClose={() => {
setOpenDuplicateModal(false);
onClose({}, "backdropClick"); // Đóng cả preview modal
onClose({}, "backdropClick"); // Close preview modal as well
}}
event={event}
/>
+24
View File
@@ -0,0 +1,24 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" rx="10.1356" fill="white"/>
<rect width="24" height="24" rx="10.1356" fill="url(#paint0_linear_5774_3576)"/>
<g filter="url(#filter0_d_5774_3576)">
<path d="M6.2106 11.2587C6.2106 10.2286 6.2106 9.71348 6.40456 9.32001C6.57517 8.9739 6.8474 8.69251 7.18224 8.51616C7.5629 8.31567 8.06121 8.31567 9.05784 8.31567H11.3712C12.3678 8.31567 12.8662 8.31567 13.2468 8.51616C13.5817 8.69251 13.8539 8.9739 14.0245 9.32001C14.2184 9.71348 14.2184 10.2286 14.2184 11.2587V12.7303C14.2184 13.7604 14.2184 14.2755 14.0245 14.669C13.8539 15.0151 13.5817 15.2965 13.2468 15.4728C12.8662 15.6733 12.3678 15.6733 11.3712 15.6733H9.05784C8.06121 15.6733 7.5629 15.6733 7.18224 15.4728C6.8474 15.2965 6.57517 15.0151 6.40456 14.669C6.2106 14.2755 6.2106 13.7604 6.2106 12.7303V11.2587Z" fill="white"/>
<path d="M15.1082 10.8363C15.1082 10.7558 15.1082 10.7156 15.1199 10.6799C15.1302 10.6483 15.147 10.6194 15.1692 10.5952C15.1943 10.5678 15.2287 10.549 15.2974 10.5113L16.2875 9.96889C16.6323 9.77997 16.8048 9.6855 16.9454 9.70453C17.0682 9.72113 17.1788 9.78989 17.2505 9.89426C17.3326 10.0138 17.3326 10.2156 17.3326 10.619V13.37C17.3326 13.7734 17.3326 13.9751 17.2505 14.0947C17.1788 14.1991 17.0682 14.2679 16.9454 14.2845C16.8048 14.3035 16.6323 14.209 16.2875 14.0201L15.2974 13.4777C15.2287 13.44 15.1943 13.4212 15.1692 13.3938C15.147 13.3696 15.1302 13.3407 15.1199 13.3091C15.1082 13.2734 15.1082 13.2331 15.1082 13.1527V10.8363Z" fill="white"/>
</g>
<defs>
<filter id="filter0_d_5774_3576" x="4.89775" y="7.2654" width="13.7477" height="9.98336" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="0.26257"/>
<feGaussianBlur stdDeviation="0.656424"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5774_3576"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5774_3576" result="shape"/>
</filter>
<linearGradient id="paint0_linear_5774_3576" x1="2.81482" y1="21.7231" x2="27.4139" y2="-3.61031" gradientUnits="userSpaceOnUse">
<stop offset="0.23798" stop-color="#50C750"/>
<stop offset="1" stop-color="#EBFF00"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB