update icon event preview modal
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
}}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user