feat: add virtual location input #121

This commit is contained in:
Linus Rath
2026-03-30 15:19:47 +02:00
parent 0fb8b81acd
commit c859230862
10 changed files with 44 additions and 1 deletions
+35 -1
View File
@@ -188,6 +188,9 @@ export function EventModal({
const [location, setLocation] = useState( const [location, setLocation] = useState(
event?.locations ? Object.values(event.locations)[0]?.name || "" : "" event?.locations ? Object.values(event.locations)[0]?.name || "" : ""
); );
const [virtualLocation, setVirtualLocation] = useState(
event?.virtualLocations ? Object.values(event.virtualLocations)[0]?.uri || "" : ""
);
const [startDate, setStartDate] = useState(formatDateInput(getInitialStart())); const [startDate, setStartDate] = useState(formatDateInput(getInitialStart()));
const [startTime, setStartTime] = useState(formatTimeInput(getInitialStart())); const [startTime, setStartTime] = useState(formatTimeInput(getInitialStart()));
const [endDate, setEndDate] = useState(formatDateInput(getInitialEnd())); const [endDate, setEndDate] = useState(formatDateInput(getInitialEnd()));
@@ -313,6 +316,20 @@ export function EventModal({
data.locations = null; data.locations = null;
} }
if (virtualLocation.trim()) {
data.virtualLocations = {
vl1: {
"@type": "VirtualLocation",
name: null,
description: null,
uri: virtualLocation.trim(),
features: null,
},
};
} else if (event && event.virtualLocations && Object.keys(event.virtualLocations).length > 0) {
data.virtualLocations = null;
}
if (recurrence !== "none") { if (recurrence !== "none") {
data.recurrenceRules = [{ data.recurrenceRules = [{
"@type": "RecurrenceRule", "@type": "RecurrenceRule",
@@ -372,7 +389,7 @@ export function EventModal({
} finally { } finally {
setIsSaving(false); setIsSaving(false);
} }
}, [title, description, location, startDate, startTime, endDate, endTime, allDay, calendarId, recurrence, alert, attendees, sendInvitations, currentUserEmails, existingParticipants, event, onSave, isSaving]); }, [title, description, location, virtualLocation, startDate, startTime, endDate, endTime, allDay, calendarId, recurrence, alert, attendees, sendInvitations, currentUserEmails, existingParticipants, event, onSave, isSaving]);
const handleRsvp = useCallback((status: CalendarParticipant['participationStatus']) => { const handleRsvp = useCallback((status: CalendarParticipant['participationStatus']) => {
if (!event || !userParticipantId || !onRsvp) return; if (!event || !userParticipantId || !onRsvp) return;
@@ -401,6 +418,7 @@ export function EventModal({
privacy: event.privacy, privacy: event.privacy,
}; };
if (event.locations) data.locations = structuredClone(event.locations); if (event.locations) data.locations = structuredClone(event.locations);
if (event.virtualLocations) data.virtualLocations = structuredClone(event.virtualLocations);
if (event.recurrenceRules) data.recurrenceRules = structuredClone(event.recurrenceRules); if (event.recurrenceRules) data.recurrenceRules = structuredClone(event.recurrenceRules);
if (event.alerts) data.alerts = structuredClone(event.alerts); if (event.alerts) data.alerts = structuredClone(event.alerts);
if (event.participants) data.participants = structuredClone(event.participants); if (event.participants) data.participants = structuredClone(event.participants);
@@ -778,6 +796,22 @@ export function EventModal({
/> />
</div> </div>
<div>
<label className="text-sm font-medium mb-1 block">
<span className="flex items-center gap-1.5">
<Video className="w-4 h-4" />
{t("form.meeting_link")}
</span>
</label>
<Input
type="url"
value={virtualLocation}
onChange={(e) => setVirtualLocation(e.target.value)}
placeholder="https://meet.example.com/..."
maxLength={2000}
/>
</div>
<div> <div>
<label className="text-sm font-medium mb-1 block"> <label className="text-sm font-medium mb-1 block">
<span className="flex items-center gap-1.5"> <span className="flex items-center gap-1.5">
+1
View File
@@ -1894,6 +1894,7 @@
"title": "Titel", "title": "Titel",
"description": "Beschreibung", "description": "Beschreibung",
"location": "Ort", "location": "Ort",
"meeting_link": "Meeting-Link",
"start_date": "Startdatum", "start_date": "Startdatum",
"end_date": "Enddatum", "end_date": "Enddatum",
"start_time": "Startzeit", "start_time": "Startzeit",
+1
View File
@@ -1894,6 +1894,7 @@
"title": "Title", "title": "Title",
"description": "Description", "description": "Description",
"location": "Location", "location": "Location",
"meeting_link": "Meeting link",
"start_date": "Start date", "start_date": "Start date",
"end_date": "End date", "end_date": "End date",
"start_time": "Start time", "start_time": "Start time",
+1
View File
@@ -1894,6 +1894,7 @@
"title": "Título", "title": "Título",
"description": "Descripción", "description": "Descripción",
"location": "Ubicación", "location": "Ubicación",
"meeting_link": "Enlace de reunión",
"start_date": "Fecha de inicio", "start_date": "Fecha de inicio",
"end_date": "Fecha de fin", "end_date": "Fecha de fin",
"start_time": "Hora de inicio", "start_time": "Hora de inicio",
+1
View File
@@ -1894,6 +1894,7 @@
"title": "Titre", "title": "Titre",
"description": "Description", "description": "Description",
"location": "Lieu", "location": "Lieu",
"meeting_link": "Lien de réunion",
"start_date": "Date de début", "start_date": "Date de début",
"end_date": "Date de fin", "end_date": "Date de fin",
"start_time": "Heure de début", "start_time": "Heure de début",
+1
View File
@@ -1894,6 +1894,7 @@
"title": "Titolo", "title": "Titolo",
"description": "Descrizione", "description": "Descrizione",
"location": "Luogo", "location": "Luogo",
"meeting_link": "Link riunione",
"start_date": "Data di inizio", "start_date": "Data di inizio",
"end_date": "Data di fine", "end_date": "Data di fine",
"start_time": "Ora di inizio", "start_time": "Ora di inizio",
+1
View File
@@ -1894,6 +1894,7 @@
"title": "タイトル", "title": "タイトル",
"description": "説明", "description": "説明",
"location": "場所", "location": "場所",
"meeting_link": "会議リンク",
"start_date": "開始日", "start_date": "開始日",
"end_date": "終了日", "end_date": "終了日",
"start_time": "開始時刻", "start_time": "開始時刻",
+1
View File
@@ -1894,6 +1894,7 @@
"title": "Titel", "title": "Titel",
"description": "Beschrijving", "description": "Beschrijving",
"location": "Locatie", "location": "Locatie",
"meeting_link": "Vergaderlink",
"start_date": "Startdatum", "start_date": "Startdatum",
"end_date": "Einddatum", "end_date": "Einddatum",
"start_time": "Starttijd", "start_time": "Starttijd",
+1
View File
@@ -1894,6 +1894,7 @@
"title": "Título", "title": "Título",
"description": "Descrição", "description": "Descrição",
"location": "Local", "location": "Local",
"meeting_link": "Link da reunião",
"start_date": "Data de início", "start_date": "Data de início",
"end_date": "Data de término", "end_date": "Data de término",
"start_time": "Hora de início", "start_time": "Hora de início",
+1
View File
@@ -1894,6 +1894,7 @@
"title": "Название", "title": "Название",
"description": "Описание", "description": "Описание",
"location": "Место", "location": "Место",
"meeting_link": "Ссылка на встречу",
"start_date": "Дата начала", "start_date": "Дата начала",
"end_date": "Дата окончания", "end_date": "Дата окончания",
"start_time": "Время начала", "start_time": "Время начала",