Bump local twake-mui lockfile to 1.1.8.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
lenhanphung
2026-02-04 15:58:12 +07:00
parent 41c839f38b
commit af53ad158a
8 changed files with 2563 additions and 86 deletions
+2490 -65
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -5,7 +5,7 @@ A highly reusable dialog component that supports both normal and expanded (fulls
## Features ## Features
-**Two Modes**: Normal popup (570px) and expanded fullscreen mode -**Two Modes**: Normal popup (570px) and expanded fullscreen mode
-**Preserves Header**: Expanded mode doesn't cover app header (90px default) -**Preserves Header**: Expanded mode doesn't cover app header (70px default)
-**Clean Expanded View**: No backdrop/shadow in expanded mode for seamless integration -**Clean Expanded View**: No backdrop/shadow in expanded mode for seamless integration
-**Instant Transition**: No animation when expanding for immediate feedback -**Instant Transition**: No animation when expanding for immediate feedback
-**Back Navigation**: Expanded mode shows back arrow icon in header for easy collapse -**Back Navigation**: Expanded mode shows back arrow icon in header for easy collapse
+2 -13
View File
@@ -5,6 +5,7 @@ import iconCamera from "@/static/images/icon-camera.svg";
import { import {
addVideoConferenceToDescription, addVideoConferenceToDescription,
generateMeetingLink, generateMeetingLink,
removeVideoConferenceFromDescription,
} from "@/utils/videoConferenceUtils"; } from "@/utils/videoConferenceUtils";
import { import {
Box, Box,
@@ -186,10 +187,6 @@ export default function EventFormFields({
const [hasClickedCalendarSection, setHasClickedCalendarSection] = const [hasClickedCalendarSection, setHasClickedCalendarSection] =
React.useState(false); React.useState(false);
// Track if user has clicked on video meeting section in normal mode
const [hasClickedVideoMeetingSection, setHasClickedVideoMeetingSection] =
React.useState(false);
// Reset hasEndDateChanged and hasClickedDateTimeSection when modal closes // Reset hasEndDateChanged and hasClickedDateTimeSection when modal closes
React.useEffect(() => { React.useEffect(() => {
if (!isOpen) { if (!isOpen) {
@@ -197,7 +194,6 @@ export default function EventFormFields({
setHasClickedDateTimeSection(false); setHasClickedDateTimeSection(false);
setHasClickedLocationSection(false); setHasClickedLocationSection(false);
setHasClickedCalendarSection(false); setHasClickedCalendarSection(false);
setHasClickedVideoMeetingSection(false);
} }
}, [isOpen]); }, [isOpen]);
@@ -428,9 +424,6 @@ export default function EventFormFields({
if (showMore) { if (showMore) {
setShowDescription(true); setShowDescription(true);
} }
if (!showMore) {
setHasClickedVideoMeetingSection(true);
}
}; };
const [openToast, setOpenToast] = React.useState(false); const [openToast, setOpenToast] = React.useState(false);
@@ -447,11 +440,7 @@ export default function EventFormFields({
}; };
const handleDeleteVideoConference = () => { const handleDeleteVideoConference = () => {
const updatedDescription = description.replace( setDescription(removeVideoConferenceFromDescription(description));
/\nVisio: https?:\/\/[^\s]+/,
""
);
setDescription(updatedDescription);
setHasVideoConference(false); setHasVideoConference(false);
setMeetingLink(null); setMeetingLink(null);
}; };
@@ -8,6 +8,7 @@ interface ClickableFieldProps {
onClick: () => void; onClick: () => void;
iconColor?: string; iconColor?: string;
children?: React.ReactNode; children?: React.ReactNode;
ariaLabel?: string;
} }
export const ClickableField: React.FC<ClickableFieldProps> = ({ export const ClickableField: React.FC<ClickableFieldProps> = ({
@@ -16,12 +17,22 @@ export const ClickableField: React.FC<ClickableFieldProps> = ({
onClick, onClick,
iconColor, iconColor,
children, children,
ariaLabel,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
return ( return (
<Box <Box
onClick={onClick} onClick={onClick}
role="button"
tabIndex={0}
aria-label={ariaLabel ?? text}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onClick();
}
}}
sx={{ sx={{
display: "flex", display: "flex",
alignItems: children ? "flex-start" : "center", alignItems: children ? "flex-start" : "center",
@@ -31,6 +42,10 @@ export const ClickableField: React.FC<ClickableFieldProps> = ({
"&:hover": { "&:hover": {
backgroundColor: "action.hover", backgroundColor: "action.hover",
}, },
"&:focus-visible": {
outline: `2px solid ${theme.palette.primary.main}`,
outlineOffset: "2px",
},
}} }}
> >
<Box <Box
+1 -3
View File
@@ -65,9 +65,7 @@ export function renderAttendeeBadge(
<Avatar {...stringAvatar(a.cn || a.cal_address)} /> <Avatar {...stringAvatar(a.cn || a.cal_address)} />
</Badge> </Badge>
<Box style={{ display: "flex", flexDirection: "column", minWidth: 0 }}> <Box style={{ display: "flex", flexDirection: "column", minWidth: 0 }}>
<Typography noWrap> <Typography noWrap>{a.cn || a.cal_address}</Typography>
{a.cn || a.cal_address}
</Typography>
{isOrganizer && ( {isOrganizer && (
<Typography variant="caption" color="text.secondary"> <Typography variant="caption" color="text.secondary">
{t("event.organizer")} {t("event.organizer")}
+2 -4
View File
@@ -197,9 +197,7 @@ export function Menubar({
</div> </div>
<div className="menu-items"> <div className="menu-items">
<div className="current-date-time"> <div className="current-date-time">
<p> <p>{dateLabel}</p>
{dateLabel}
</p>
</div> </div>
</div> </div>
</div> </div>
@@ -232,7 +230,7 @@ export function Menubar({
sx={{ sx={{
borderRadius: "12px", borderRadius: "12px",
marginLeft: 1, marginLeft: 1,
"& fieldset": { borderRadius: "12px" } "& fieldset": { borderRadius: "12px" },
}} }}
> >
<MenuItem value="dayGridMonth"> <MenuItem value="dayGridMonth">
@@ -3,6 +3,7 @@ import {
extractVideoConferenceFromDescription, extractVideoConferenceFromDescription,
generateMeetingId, generateMeetingId,
generateMeetingLink, generateMeetingLink,
removeVideoConferenceFromDescription,
} from "../videoConferenceUtils"; } from "../videoConferenceUtils";
// Mock window object for Node.js environment // Mock window object for Node.js environment
@@ -82,4 +83,39 @@ describe("videoConferenceUtils", () => {
expect(result).toBeNull(); expect(result).toBeNull();
}); });
}); });
describe("removeVideoConferenceFromDescription", () => {
it("should return empty string when description is only the Visio line", () => {
const description = "Visio: https://meet.linagora.com/abc-defg-hij";
const result = removeVideoConferenceFromDescription(description);
expect(result).toBe("");
});
it("should remove Visio line when at end of description", () => {
const description =
"This is a meeting description.\nVisio: https://meet.linagora.com/abc-defg-hij";
const result = removeVideoConferenceFromDescription(description);
expect(result).toBe("This is a meeting description.");
});
it("should remove Visio line when in middle of description", () => {
const description =
"Line one\nVisio: https://meet.linagora.com/abc-defg-hij\nLine two";
const result = removeVideoConferenceFromDescription(description);
expect(result).toBe("Line one\nLine two");
});
it("should leave description unchanged when no Visio line present", () => {
const description = "Just a regular meeting description.";
const result = removeVideoConferenceFromDescription(description);
expect(result).toBe(description);
});
it("should remove Visio line when at start of description", () => {
const description =
"Visio: https://meet.linagora.com/abc-defg-hij\nRest of the text";
const result = removeVideoConferenceFromDescription(description);
expect(result).toBe("Rest of the text");
});
});
}); });
+16
View File
@@ -59,3 +59,19 @@ export function extractVideoConferenceFromDescription(
const match = description.match(/Visio:\s*(https?:\/\/[^\s]+)/); const match = description.match(/Visio:\s*(https?:\/\/[^\s]+)/);
return match ? match[1] : null; return match ? match[1] : null;
} }
const VISIO_LINE_REGEX = /^Visio:\s*https?:\/\/\S+$/;
/**
* Remove the Visio video conference line from description.
* Finds and removes the line matching "Visio: <url>" regardless of position (start, middle, end).
* @param {string} description - Event description
* @returns {string} Description with the Visio line removed
*/
export function removeVideoConferenceFromDescription(
description: string
): string {
const lines = description.split("\n");
const filtered = lines.filter((line) => !VISIO_LINE_REGEX.test(line.trim()));
return filtered.join("\n").trimEnd();
}