Bump local twake-mui lockfile to 1.1.8.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Generated
+2490
-65
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ A highly reusable dialog component that supports both normal and expanded (fulls
|
||||
## Features
|
||||
|
||||
- ✅ **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
|
||||
- ✅ **Instant Transition**: No animation when expanding for immediate feedback
|
||||
- ✅ **Back Navigation**: Expanded mode shows back arrow icon in header for easy collapse
|
||||
|
||||
@@ -5,6 +5,7 @@ import iconCamera from "@/static/images/icon-camera.svg";
|
||||
import {
|
||||
addVideoConferenceToDescription,
|
||||
generateMeetingLink,
|
||||
removeVideoConferenceFromDescription,
|
||||
} from "@/utils/videoConferenceUtils";
|
||||
import {
|
||||
Box,
|
||||
@@ -186,10 +187,6 @@ export default function EventFormFields({
|
||||
const [hasClickedCalendarSection, setHasClickedCalendarSection] =
|
||||
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
|
||||
React.useEffect(() => {
|
||||
if (!isOpen) {
|
||||
@@ -197,7 +194,6 @@ export default function EventFormFields({
|
||||
setHasClickedDateTimeSection(false);
|
||||
setHasClickedLocationSection(false);
|
||||
setHasClickedCalendarSection(false);
|
||||
setHasClickedVideoMeetingSection(false);
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
@@ -428,9 +424,6 @@ export default function EventFormFields({
|
||||
if (showMore) {
|
||||
setShowDescription(true);
|
||||
}
|
||||
if (!showMore) {
|
||||
setHasClickedVideoMeetingSection(true);
|
||||
}
|
||||
};
|
||||
|
||||
const [openToast, setOpenToast] = React.useState(false);
|
||||
@@ -447,11 +440,7 @@ export default function EventFormFields({
|
||||
};
|
||||
|
||||
const handleDeleteVideoConference = () => {
|
||||
const updatedDescription = description.replace(
|
||||
/\nVisio: https?:\/\/[^\s]+/,
|
||||
""
|
||||
);
|
||||
setDescription(updatedDescription);
|
||||
setDescription(removeVideoConferenceFromDescription(description));
|
||||
setHasVideoConference(false);
|
||||
setMeetingLink(null);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ interface ClickableFieldProps {
|
||||
onClick: () => void;
|
||||
iconColor?: string;
|
||||
children?: React.ReactNode;
|
||||
ariaLabel?: string;
|
||||
}
|
||||
|
||||
export const ClickableField: React.FC<ClickableFieldProps> = ({
|
||||
@@ -16,12 +17,22 @@ export const ClickableField: React.FC<ClickableFieldProps> = ({
|
||||
onClick,
|
||||
iconColor,
|
||||
children,
|
||||
ariaLabel,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Box
|
||||
onClick={onClick}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={ariaLabel ?? text}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
onClick();
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: children ? "flex-start" : "center",
|
||||
@@ -31,6 +42,10 @@ export const ClickableField: React.FC<ClickableFieldProps> = ({
|
||||
"&:hover": {
|
||||
backgroundColor: "action.hover",
|
||||
},
|
||||
"&:focus-visible": {
|
||||
outline: `2px solid ${theme.palette.primary.main}`,
|
||||
outlineOffset: "2px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
|
||||
@@ -65,9 +65,7 @@ export function renderAttendeeBadge(
|
||||
<Avatar {...stringAvatar(a.cn || a.cal_address)} />
|
||||
</Badge>
|
||||
<Box style={{ display: "flex", flexDirection: "column", minWidth: 0 }}>
|
||||
<Typography noWrap>
|
||||
{a.cn || a.cal_address}
|
||||
</Typography>
|
||||
<Typography noWrap>{a.cn || a.cal_address}</Typography>
|
||||
{isOrganizer && (
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{t("event.organizer")}
|
||||
|
||||
@@ -197,9 +197,7 @@ export function Menubar({
|
||||
</div>
|
||||
<div className="menu-items">
|
||||
<div className="current-date-time">
|
||||
<p>
|
||||
{dateLabel}
|
||||
</p>
|
||||
<p>{dateLabel}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -232,7 +230,7 @@ export function Menubar({
|
||||
sx={{
|
||||
borderRadius: "12px",
|
||||
marginLeft: 1,
|
||||
"& fieldset": { borderRadius: "12px" }
|
||||
"& fieldset": { borderRadius: "12px" },
|
||||
}}
|
||||
>
|
||||
<MenuItem value="dayGridMonth">
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
extractVideoConferenceFromDescription,
|
||||
generateMeetingId,
|
||||
generateMeetingLink,
|
||||
removeVideoConferenceFromDescription,
|
||||
} from "../videoConferenceUtils";
|
||||
|
||||
// Mock window object for Node.js environment
|
||||
@@ -82,4 +83,39 @@ describe("videoConferenceUtils", () => {
|
||||
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");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,3 +59,19 @@ export function extractVideoConferenceFromDescription(
|
||||
const match = description.match(/Visio:\s*(https?:\/\/[^\s]+)/);
|
||||
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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user