update icon event preview modal

This commit is contained in:
lenhanphung
2026-02-04 15:31:12 +07:00
parent 201f9c722b
commit 309ac0d23b
6 changed files with 46 additions and 26 deletions
@@ -116,6 +116,7 @@ function ResponsiveDialog({
}: ResponsiveDialogProps) {
const baseSx: SxProps<Theme> = {
"& .MuiBackdrop-root": {
backgroundColor: "rgba(0, 0, 0, 0.1)",
opacity: isExpanded ? "0 !important" : undefined,
transition: isExpanded ? "none !important" : undefined,
pointerEvents: isExpanded ? "none" : undefined,
+3 -1
View File
@@ -8,6 +8,7 @@ type InfoRowProps = {
data?: string; // optional link target
content?: React.ReactNode; // if provided, overrides text rendering
style?: React.CSSProperties;
alignItems?: React.CSSProperties["alignItems"];
};
function detectUrls(text: string) {
@@ -62,12 +63,13 @@ export function InfoRow({
data,
content,
style,
alignItems = "center",
}: InfoRowProps) {
return (
<Box
style={{
display: "flex",
alignItems: "center",
alignItems,
gap: 1,
marginBottom: 1,
}}
+12 -9
View File
@@ -13,6 +13,13 @@ import { Avatar, Badge, Box, Typography } from "@linagora/twake-mui";
import CancelIcon from "@mui/icons-material/Cancel";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
const EMAIL_DISPLAY_MAX_LENGTH = 50;
function truncateDisplayText(text: string, maxLength: number): string {
if (text.length <= maxLength) return text;
return `${text.slice(0, maxLength)}...`;
}
export function renderAttendeeBadge(
a: userAttendee,
key: string,
@@ -65,15 +72,11 @@ export function renderAttendeeBadge(
<Avatar {...stringAvatar(a.cn || a.cal_address)} />
</Badge>
<Box style={{ display: "flex", flexDirection: "column", minWidth: 0 }}>
<Typography
noWrap
style={{
maxWidth: "180px",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{a.cn || a.cal_address}
<Typography noWrap>
{truncateDisplayText(
a.cn || a.cal_address,
EMAIL_DISPLAY_MAX_LENGTH
)}
</Typography>
{isOrganizer && (
<Typography variant="caption" color="text.secondary">
+23 -11
View File
@@ -20,7 +20,9 @@ import {
MenuItem,
Tooltip,
Typography,
useTheme,
} from "@linagora/twake-mui";
import { alpha } from "@mui/material/styles";
import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
import CircleIcon from "@mui/icons-material/Circle";
import CloseIcon from "@mui/icons-material/Close";
@@ -73,6 +75,9 @@ export default function EventPreviewModal({
: calendars.list[calId];
const event = calendar.events[eventId];
const user = useAppSelector((state) => state.user.userData);
const theme = useTheme();
const infoIconColor = alpha(theme.palette.grey[900], 0.9);
const infoIconSx = { minWidth: "25px", marginRight: 2, color: infoIconColor };
if (!user) return null;
const isRecurring = event?.uid?.includes("/");
@@ -451,10 +456,10 @@ export default function EventPreviewModal({
title={t("eventPreview.privateEvent.tooltipOwn")}
placement="top"
>
<LockOutlineIcon />
<LockOutlineIcon sx={{ color: infoIconColor }} />
</Tooltip>
) : (
<LockOutlineIcon />
<LockOutlineIcon sx={{ color: infoIconColor }} />
))}
<Typography
variant="h5"
@@ -488,8 +493,9 @@ export default function EventPreviewModal({
{/* Video */}
{event.x_openpass_videoconference && (
<InfoRow
alignItems="flex-start"
icon={
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
<Box sx={{ ...infoIconSx, mt: 1 }}>
<VideocamOutlinedIcon />
</Box>
}
@@ -511,8 +517,9 @@ export default function EventPreviewModal({
{attendees?.length > 0 && (
<>
<InfoRow
alignItems="flex-start"
icon={
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
<Box sx={{ ...infoIconSx, mt: 1 }}>
<PeopleAltOutlinedIcon />
</Box>
}
@@ -585,8 +592,9 @@ export default function EventPreviewModal({
{/* Location */}
{event.location && (
<InfoRow
alignItems="flex-start"
icon={
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
<Box sx={infoIconSx}>
<LocationOnOutlinedIcon />
</Box>
}
@@ -600,8 +608,9 @@ export default function EventPreviewModal({
{/* Description */}
{event.description && (
<InfoRow
alignItems="flex-start"
icon={
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
<Box sx={infoIconSx}>
<SubjectIcon />
</Box>
}
@@ -615,8 +624,9 @@ export default function EventPreviewModal({
{/* ALARM */}
{event.alarm && (
<InfoRow
alignItems="flex-start"
icon={
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
<Box sx={infoIconSx}>
<NotificationsNoneIcon />
</Box>
}
@@ -641,8 +651,9 @@ export default function EventPreviewModal({
{/* Repetition */}
{event.repetition && (
<InfoRow
alignItems="flex-start"
icon={
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
<Box sx={infoIconSx}>
<RepeatIcon />
</Box>
}
@@ -681,8 +692,9 @@ export default function EventPreviewModal({
{/* Error */}
{event.error && (
<InfoRow
alignItems="flex-start"
icon={
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
<Box sx={infoIconSx}>
<ErrorOutlineIcon color="error" />
</Box>
}
@@ -698,12 +710,12 @@ export default function EventPreviewModal({
<Box
sx={{
display: "flex",
alignItems: "center",
alignItems: "flex-start",
gap: 1,
mb: 2,
}}
>
<Box sx={{ minWidth: "25px", marginRight: 2 }}>
<Box sx={infoIconSx}>
<CalendarTodayIcon />
</Box>
<CalendarName calendar={calendar} />
@@ -45,11 +45,11 @@ describe("videoConferenceUtils", () => {
});
describe("addVideoConferenceToDescription", () => {
it("should add video conference footer to empty description", () => {
it("should add video conference on first line when description is empty", () => {
const description = "";
const meetingLink = "https://meet.linagora.com/abc-defg-hij";
const result = addVideoConferenceToDescription(description, meetingLink);
expect(result).toBe("\nVisio: https://meet.linagora.com/abc-defg-hij");
expect(result).toBe("Visio: https://meet.linagora.com/abc-defg-hij");
});
it("should add video conference footer to existing description", () => {
+5 -3
View File
@@ -33,7 +33,8 @@ export function generateMeetingLink(baseUrl?: string): string {
}
/**
* Add video conference footer to event description
* Add video conference footer to event description.
* If description is empty, adds on first line; otherwise adds on the line below existing content.
* @param {string} description - Original description
* @param {string} meetingLink - Generated meeting link
* @returns {string} Description with video conference footer
@@ -42,8 +43,9 @@ export function addVideoConferenceToDescription(
description: string,
meetingLink: string
): string {
const footer = `\nVisio: ${meetingLink}`;
return description + footer;
const line = `Visio: ${meetingLink}`;
const trimmed = description.trimEnd();
return trimmed ? `${trimmed}\n${line}` : line;
}
/**