diff --git a/frontend/dist/index.html b/frontend/dist/index.html
index a5475d6..8ab2616 100644
--- a/frontend/dist/index.html
+++ b/frontend/dist/index.html
@@ -11,8 +11,8 @@
Schichtplaner — Veranstaltungsschichtpläne
-
-
+
+
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 0d47f67..b40ce55 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -180,16 +180,38 @@ export default function App() {
} catch (e) {}
};
+ const updateUrlParam = (id) => {
+ if (!id) return;
+ try {
+ const url = new URL(window.location.href);
+ url.searchParams.set('event', id);
+ window.history.replaceState(null, '', url.pathname + url.search);
+ } catch (e) {}
+ };
+
const refreshEvents = async () => {
try {
const data = await apiFetch('/events/');
const list = data.results || data;
setEvents(list);
- if (list.length > 0 && !selectedEventId) {
+
+ // Check URL query parameters for deep linking (?event=12)
+ const urlParams = new URLSearchParams(window.location.search);
+ const urlEventParam = urlParams.get('event') || urlParams.get('event_id');
+ const targetIdFromUrl = urlEventParam ? parseInt(urlEventParam, 10) : null;
+
+ if (targetIdFromUrl && list.some(e => e.id === targetIdFromUrl)) {
+ setSelectedEventId(targetIdFromUrl);
+ fetchEventMatrix(targetIdFromUrl);
+ setActiveTab('schedule');
+ updateUrlParam(targetIdFromUrl);
+ } else if (list.length > 0 && !selectedEventId) {
setSelectedEventId(list[0].id);
fetchEventMatrix(list[0].id);
+ updateUrlParam(list[0].id);
} else if (selectedEventId) {
fetchEventMatrix(selectedEventId);
+ updateUrlParam(selectedEventId);
}
} catch (e) {}
};
@@ -205,6 +227,34 @@ export default function App() {
setSelectedEventId(id);
fetchEventMatrix(id);
setActiveTab('schedule');
+ updateUrlParam(id);
+ };
+
+ const fallbackCopyText = (text) => {
+ const el = document.createElement('textarea');
+ el.value = text;
+ document.body.appendChild(el);
+ el.select();
+ document.execCommand('copy');
+ document.body.removeChild(el);
+ showNotification('Direktlink zum Schichtplan in Zwischenablage kopiert! 🔗');
+ };
+
+ const handleShareEvent = (targetEventOrId) => {
+ const targetId = typeof targetEventOrId === 'object' ? targetEventOrId.id : (targetEventOrId || selectedEventId);
+ if (!targetId) return;
+
+ const shareUrl = `${window.location.origin}${window.location.pathname}?event=${targetId}`;
+
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(shareUrl).then(() => {
+ showNotification('Direktlink zum Schichtplan in Zwischenablage kopiert! 🔗');
+ }).catch(() => {
+ fallbackCopyText(shareUrl);
+ });
+ } else {
+ fallbackCopyText(shareUrl);
+ }
};
const handleLogout = () => {
@@ -464,6 +514,7 @@ export default function App() {
alert(err.message || 'Aktion fehlgeschlagen.');
}
}}
+ onShareEvent={handleShareEvent}
onEditEvent={(evt) => {
setEventToEdit(evt);
setActiveTab('event-editor');
@@ -572,6 +623,7 @@ export default function App() {
onGenerateClaimLink={handleGenerateClaimLink}
onExportPdf={handleExportPdf}
onPrintView={handlePrintView}
+ onShareLink={() => handleShareEvent(selectedEventId)}
/>
)}
diff --git a/frontend/src/components/ShiftMatrixTable.jsx b/frontend/src/components/ShiftMatrixTable.jsx
index 1a8a199..2229de3 100644
--- a/frontend/src/components/ShiftMatrixTable.jsx
+++ b/frontend/src/components/ShiftMatrixTable.jsx
@@ -1,7 +1,7 @@
/* Hallmark · pre-emit critique: P5 H5 E5 S5 R5 V5 */
/* Hallmark · component: shift-matrix-table · genre: editorial · theme: Atelier (Dark & Light) · studied-DNA: https://inihaus.de */
import React from 'react';
-import { Clock, UserCheck, Shield, Printer, Download, Award, CheckCircle2, UserX, UserPlus, MapPin, Edit3, Trash2 } from 'lucide-react';
+import { Clock, UserCheck, Shield, Printer, Download, Award, CheckCircle2, UserX, UserPlus, MapPin, Edit3, Trash2, Share2 } from 'lucide-react';
export default function ShiftMatrixTable({
event,
@@ -12,6 +12,7 @@ export default function ShiftMatrixTable({
onGenerateClaimLink,
onExportPdf,
onPrintView,
+ onShareLink,
onEditEvent,
onDeleteEvent
}) {
@@ -92,6 +93,15 @@ export default function ShiftMatrixTable({
LÖSCHEN
)}
+ {onShareLink && (
+
+ )}
+ {onShareEvent && (
+
+ )}
+
{canManage && onEditEvent && (