diff --git a/jest.config.ts b/jest.config.ts index 945e1fb..1d3dfb3 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)/)", + "/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: ["/src/setupTests.ts"], }, ], diff --git a/package-lock.json b/package-lock.json index 78266ed..7c6a50b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" } diff --git a/package.json b/package.json index 8d88137..fd87918 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/Calendar/AccessTab.tsx b/src/components/Calendar/AccessTab.tsx index a5289af..e753cf6 100644 --- a/src/components/Calendar/AccessTab.tsx +++ b/src/components/Calendar/AccessTab.tsx @@ -90,6 +90,7 @@ export function AccessTab({ calendar }: { calendar: Calendar }) { fullWidth label={t("calendar.caldav_access")} value={calDAVLink} + size="small" InputProps={{ endAdornment: ( @@ -110,6 +111,7 @@ export function AccessTab({ calendar }: { calendar: Calendar }) { fullWidth label={t("calendar.secretUrl")} value={secretLink} + size="small" InputProps={{ endAdornment: ( @@ -120,7 +122,12 @@ export function AccessTab({ calendar }: { calendar: Calendar }) { ), }} /> - @@ -142,9 +149,11 @@ export function AccessTab({ calendar }: { calendar: Calendar }) { + + + {importFile && ( {importFile.name} diff --git a/src/components/Calendar/SettingsTab.tsx b/src/components/Calendar/SettingsTab.tsx index f8455f8..07748ff 100644 --- a/src/components/Calendar/SettingsTab.tsx +++ b/src/components/Calendar/SettingsTab.tsx @@ -67,6 +67,8 @@ export function SettingsTab({ showMore={false} description={description} setDescription={setDescription} + buttonVariant="contained" + buttonColor="secondary" /> @@ -88,7 +90,8 @@ export function SettingsTab({ value={visibility} exclusive onChange={(e, val) => val && setVisibility(val)} - size="small" + size="medium" + sx={{ borderRadius: "12px" }} > diff --git a/src/components/Event/AddDescButton.tsx b/src/components/Event/AddDescButton.tsx index df45847..a5f7d6f 100644 --- a/src/components/Event/AddDescButton.tsx +++ b/src/components/Event/AddDescButton.tsx @@ -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({ @@ -40,6 +49,7 @@ export function AddDescButton({ )} - {DisplayedIcons(IconDisplayed)} + {DisplayedIcons(IconDisplayed, titleStyle.color)} {event.title} diff --git a/src/components/Event/EventChip/EventChipUtils.tsx b/src/components/Event/EventChip/EventChipUtils.tsx index 3325831..7187b73 100644 --- a/src/components/Event/EventChip/EventChipUtils.tsx +++ b/src/components/Event/EventChip/EventChipUtils.tsx @@ -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 ( - - {IconDisplayed.needAction && ( - - )} - {IconDisplayed.declined && } - {IconDisplayed.tentative && ( - - )} - {IconDisplayed.private && ( - - )} - + {IconDisplayed.needAction && } + {IconDisplayed.declined && } + {IconDisplayed.tentative && } + {IconDisplayed.private && } + ); } diff --git a/src/components/Event/EventFormFields.tsx b/src/components/Event/EventFormFields.tsx index 9170be3..0f0a9fe 100644 --- a/src/components/Event/EventFormFields.tsx +++ b/src/components/Event/EventFormFields.tsx @@ -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" /> @@ -555,12 +558,15 @@ export default function EventFormFields({ > - diff --git a/src/features/Events/AttendanceValidation/RSVPButton.tsx b/src/features/Events/AttendanceValidation/RSVPButton.tsx index 8c308d4..d3aab14 100644 --- a/src/features/Events/AttendanceValidation/RSVPButton.tsx +++ b/src/features/Events/AttendanceValidation/RSVPButton.tsx @@ -47,7 +47,7 @@ export function RSVPButton({ ? rsvpColor[rsvpValue] : "primary" } - size="large" + size="medium" sx={{ borderRadius: "50px" }} onClick={() => handleRSVPClick( diff --git a/src/features/Events/EventDisplayPreview.tsx b/src/features/Events/EventDisplayPreview.tsx index c2dc159..4fa14ec 100644 --- a/src/features/Events/EventDisplayPreview.tsx +++ b/src/features/Events/EventDisplayPreview.tsx @@ -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={ - <> - - - {(window as any).DEBUG && ( - { - const icsContent = await dlEvent(event); - const blob = new Blob([icsContent], { - type: "text/calendar", - }); - const url = URL.createObjectURL(blob); + + {(window as any).DEBUG && ( + { + 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); - }} - > - - - )} - {isOrganizer && isOwn && ( - { - if (isRecurring) { - setAfterChoiceFunc(() => () => { - setHidePreview(true); - setOpenUpdateModal(true); - }); - setOpenEditModePopup("edit"); - } else { - setHidePreview(true); - setOpenUpdateModal(true); - } - }} - > - - - )} - {((event.class !== "PRIVATE" && !isOwn) || isOwn) && ( - setToggleActionMenu(e.currentTarget)} - > - - - )} - setToggleActionMenu(null)} - anchorEl={toggleActionMenu} - > - {mailSpaUrl && attendees.length > 0 && ( - - 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")} - - )} - setToggleActionMenu(null)} - onOpenDuplicate={() => { - setToggleActionMenu(null); - setHidePreview(true); - setOpenDuplicateModal(true); - }} - /> - {isOrganizer && ( - { - 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")} - - )} - - onClose({}, "backdropClick")} - > - - - - - - {event.class === "PRIVATE" && - (isOwn ? ( - - - - ) : ( - - ))} - - {formatEventChipTitle(event, t)} - - {event.transp === "TRANSPARENT" && ( - - } - label={t("eventPreview.free.label")} - /> - + + + )} + {isOrganizer && isOwn && ( + { + if (isRecurring) { + setAfterChoiceFunc(() => () => { + setHidePreview(true); + setOpenUpdateModal(true); + }); + setOpenEditModePopup("edit"); + } else { + setHidePreview(true); + setOpenUpdateModal(true); + } + }} + > + + + )} + {((event.class !== "PRIVATE" && !isOwn) || isOwn) && ( + setToggleActionMenu(e.currentTarget)} + > + + + )} + setToggleActionMenu(null)} + anchorEl={toggleActionMenu} + > + {mailSpaUrl && attendees.length > 0 && ( + + 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")} + )} - - - {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)) : ""}`} - - + setToggleActionMenu(null)} + onOpenDuplicate={() => { + setToggleActionMenu(null); + setHidePreview(true); + setOpenDuplicateModal(true); + }} + /> + {isOrganizer && ( + { + 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")} + + )} + + onClose({}, "backdropClick")} + > + + + } actions={ } > + + + {event.class === "PRIVATE" && + (isOwn ? ( + + + + ) : ( + + ))} + + {formatEventChipTitle(event, t)} + + {event.transp === "TRANSPARENT" && ( + + } + label={t("eventPreview.free.label")} + /> + + )} + + + {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)) : ""}`} + + {((event.class !== "PRIVATE" && !isOwn) || isOwn) && ( <> {/* Video */} @@ -503,9 +518,11 @@ export default function EventPreviewModal({ content={ @@ -701,11 +718,11 @@ export default function EventPreviewModal({ )} {/* Calendar color dot */} @@ -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} /> diff --git a/src/static/images/icon-camera.svg b/src/static/images/icon-camera.svg new file mode 100644 index 0000000..cd5c2ce --- /dev/null +++ b/src/static/images/icon-camera.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + +