mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-21 12:49:06 +00:00
calendar refresh quick action icon
This commit is contained in:
@@ -201,21 +201,33 @@ export default function ICSSettings({
|
|||||||
bg="gray.100"
|
bg="gray.100"
|
||||||
_hover={{ bg: "gray.200" }}
|
_hover={{ bg: "gray.200" }}
|
||||||
_focus={{ bg: "gray.200" }}
|
_focus={{ bg: "gray.200" }}
|
||||||
pr="48px"
|
pr="90px"
|
||||||
width="100%"
|
width="100%"
|
||||||
/>
|
/>
|
||||||
|
<HStack position="absolute" right="4px" gap={1} zIndex={1}>
|
||||||
|
<IconButton
|
||||||
|
aria-label="Force sync calendar"
|
||||||
|
onClick={handleForceSync}
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
disabled={syncStatus === "syncing" || !icsUrl || !isEditing}
|
||||||
|
>
|
||||||
|
{syncStatus === "syncing" ? (
|
||||||
|
<Spinner size="sm" />
|
||||||
|
) : (
|
||||||
|
<LuRefreshCw />
|
||||||
|
)}
|
||||||
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="Copy room URL"
|
aria-label="Copy room URL"
|
||||||
onClick={handleCopyRoomUrl}
|
onClick={handleCopyRoomUrl}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
position="absolute"
|
|
||||||
right="4px"
|
|
||||||
size="sm"
|
size="sm"
|
||||||
zIndex={1}
|
|
||||||
>
|
>
|
||||||
{justCopied ? <LuCheck /> : <LuCopy />}
|
{justCopied ? <LuCheck /> : <LuCopy />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
</HStack>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Table,
|
Table,
|
||||||
@@ -9,12 +9,15 @@ import {
|
|||||||
Spinner,
|
Spinner,
|
||||||
Badge,
|
Badge,
|
||||||
VStack,
|
VStack,
|
||||||
|
Icon,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { LuLink } from "react-icons/lu";
|
import { LuLink, LuRefreshCw } from "react-icons/lu";
|
||||||
|
import { FaCalendarAlt } from "react-icons/fa";
|
||||||
import type { components } from "../../../reflector-api";
|
import type { components } from "../../../reflector-api";
|
||||||
import {
|
import {
|
||||||
useRoomActiveMeetings,
|
useRoomActiveMeetings,
|
||||||
useRoomUpcomingMeetings,
|
useRoomUpcomingMeetings,
|
||||||
|
useRoomIcsSync,
|
||||||
} from "../../../lib/apiHooks";
|
} from "../../../lib/apiHooks";
|
||||||
|
|
||||||
type Room = components["schemas"]["Room"];
|
type Room = components["schemas"]["Room"];
|
||||||
@@ -23,6 +26,34 @@ type CalendarEventResponse = components["schemas"]["CalendarEventResponse"];
|
|||||||
import { RoomActionsMenu } from "./RoomActionsMenu";
|
import { RoomActionsMenu } from "./RoomActionsMenu";
|
||||||
import { MEETING_DEFAULT_TIME_MINUTES } from "../../../[roomName]/[meetingId]/constants";
|
import { MEETING_DEFAULT_TIME_MINUTES } from "../../../[roomName]/[meetingId]/constants";
|
||||||
|
|
||||||
|
// Custom icon component that combines calendar and refresh icons
|
||||||
|
const CalendarSyncIcon = () => (
|
||||||
|
<Box position="relative" display="inline-block" w="20px" h="20px">
|
||||||
|
<Icon
|
||||||
|
as={FaCalendarAlt}
|
||||||
|
position="absolute"
|
||||||
|
top={0}
|
||||||
|
left={0}
|
||||||
|
boxSize="20px"
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
position="absolute"
|
||||||
|
bottom="-2px"
|
||||||
|
right="-2px"
|
||||||
|
bg="white"
|
||||||
|
borderRadius="full"
|
||||||
|
p="1px"
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
w="12px"
|
||||||
|
h="12px"
|
||||||
|
>
|
||||||
|
<Icon as={LuRefreshCw} boxSize="10px" color="gray.700" />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
interface RoomTableProps {
|
interface RoomTableProps {
|
||||||
rooms: Room[];
|
rooms: Room[];
|
||||||
linkCopied: string;
|
linkCopied: string;
|
||||||
@@ -148,6 +179,28 @@ export function RoomTable({
|
|||||||
onDelete,
|
onDelete,
|
||||||
loading,
|
loading,
|
||||||
}: RoomTableProps) {
|
}: RoomTableProps) {
|
||||||
|
const [syncingRooms, setSyncingRooms] = useState<Set<string>>(new Set());
|
||||||
|
const syncMutation = useRoomIcsSync();
|
||||||
|
|
||||||
|
const handleForceSync = async (roomName: string) => {
|
||||||
|
setSyncingRooms((prev) => new Set(prev).add(roomName));
|
||||||
|
try {
|
||||||
|
await syncMutation.mutateAsync({
|
||||||
|
params: {
|
||||||
|
path: { room_name: roomName },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to sync calendar:", err);
|
||||||
|
} finally {
|
||||||
|
setSyncingRooms((prev) => {
|
||||||
|
const next = new Set(prev);
|
||||||
|
next.delete(roomName);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box display={{ base: "none", lg: "block" }} position="relative">
|
<Box display={{ base: "none", lg: "block" }} position="relative">
|
||||||
{loading && (
|
{loading && (
|
||||||
@@ -217,6 +270,21 @@ export function RoomTable({
|
|||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
<Flex alignItems="center" gap={2}>
|
<Flex alignItems="center" gap={2}>
|
||||||
|
{room.ics_enabled && (
|
||||||
|
<IconButton
|
||||||
|
aria-label="Force sync calendar"
|
||||||
|
onClick={() => handleForceSync(room.name)}
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
disabled={syncingRooms.has(room.name)}
|
||||||
|
>
|
||||||
|
{syncingRooms.has(room.name) ? (
|
||||||
|
<Spinner size="sm" />
|
||||||
|
) : (
|
||||||
|
<CalendarSyncIcon />
|
||||||
|
)}
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
{linkCopied === room.name ? (
|
{linkCopied === room.name ? (
|
||||||
<Text color="green.500" fontSize="sm">
|
<Text color="green.500" fontSize="sm">
|
||||||
Copied!
|
Copied!
|
||||||
|
|||||||
Reference in New Issue
Block a user