diff --git a/src/App.js b/src/App.js
index 9d0d5fc..ad0526e 100644
--- a/src/App.js
+++ b/src/App.js
@@ -101,6 +101,7 @@ function App() {
const [notificationMessage, setNotificationMessage] = useState('');
const [notificationError, setNotificationError] = useState('');
const [notificationPanelOpen, setNotificationPanelOpen] = useState(false);
+ const [copyFeedback, setCopyFeedback] = useState('');
const minSelectableDate = useMemo(() => startOfDay(new Date()), []);
const weekdays = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
@@ -990,6 +991,36 @@ function App() {
}
}, [activeRangePicker, activeRangeEntry]);
+ const ntfyPreviewUrl = useMemo(() => {
+ if (
+ !notificationCapabilities.ntfy.enabled ||
+ !notificationCapabilities.ntfy.serverUrl ||
+ !notificationSettings.ntfy.topic
+ ) {
+ return null;
+ }
+ const server = notificationCapabilities.ntfy.serverUrl.replace(/\/+$/, '');
+ if (!server) {
+ return null;
+ }
+ const sanitizedTopic = notificationSettings.ntfy.topic.trim().replace(/^-+|-+$/g, '');
+ if (!sanitizedTopic) {
+ return null;
+ }
+ const prefix = (notificationCapabilities.ntfy.topicPrefix || '').replace(/^-+|-+$/g, '');
+ const separator = prefix && sanitizedTopic ? '-' : '';
+ const slug = `${prefix}${separator}${sanitizedTopic}` || sanitizedTopic || prefix;
+ if (!slug) {
+ return null;
+ }
+ return `${server}/${slug}`;
+ }, [
+ notificationCapabilities.ntfy.enabled,
+ notificationCapabilities.ntfy.serverUrl,
+ notificationCapabilities.ntfy.topicPrefix,
+ notificationSettings.ntfy.topic
+ ]);
+
const handleStoreSelection = async (store) => {
const storeId = String(store.id);
const existing = configMap.get(storeId);
@@ -1115,6 +1146,33 @@ function App() {
}
};
+ const copyToClipboard = async (text) => {
+ if (!text) {
+ return;
+ }
+ setCopyFeedback('');
+ try {
+ if (navigator?.clipboard?.writeText) {
+ await navigator.clipboard.writeText(text);
+ } else {
+ const tempInput = document.createElement('textarea');
+ tempInput.value = text;
+ tempInput.style.position = 'fixed';
+ tempInput.style.top = '-9999px';
+ document.body.appendChild(tempInput);
+ tempInput.focus();
+ tempInput.select();
+ document.execCommand('copy');
+ document.body.removeChild(tempInput);
+ }
+ setCopyFeedback('Link kopiert!');
+ setTimeout(() => setCopyFeedback(''), 2000);
+ } catch (err) {
+ setCopyFeedback(`Kopieren fehlgeschlagen: ${err.message}`);
+ setTimeout(() => setCopyFeedback(''), 3000);
+ }
+ };
+
const handleAdminSettingChange = (field, value, isNumber = false) => {
setAdminSettings((prev) => {
if (!prev) {
@@ -1390,70 +1448,6 @@ function App() {
-
-
- {!availableCollapsed && (
-
- {stores.length === 0 && (
-
Noch keine Betriebe geladen. Aktualisiere nach dem Login.
- )}
- {stores.map((store) => {
- const storeId = String(store.id);
- const entry = configMap.get(storeId);
- const isVisible = entry && !entry.hidden;
- const needsRestore = entry && entry.hidden;
- const blockedByNoPickups = store.hasPickupSlots === false;
- let statusLabel = 'Hinzufügen';
- let statusClass = 'text-blue-600';
- if (isVisible) {
- statusLabel = 'Bereits in Konfiguration';
- statusClass = 'text-gray-500';
- } else if (needsRestore) {
- statusLabel = 'Ausgeblendet – erneut hinzufügen';
- statusClass = 'text-amber-600';
- }
- if (blockedByNoPickups) {
- statusLabel = 'Keine Pickups – automatisch verborgen';
- statusClass = 'text-red-600';
- }
- return (
-
- );
- })}
-
- )}
-
-
{notificationPanelOpen && (
{notificationError && (
@@ -1513,6 +1507,29 @@ function App() {
Präfix: {notificationCapabilities.ntfy.topicPrefix} (Bindestrich wird automatisch ergänzt)
)}
+ {ntfyPreviewUrl && (
+
+
+ {ntfyPreviewUrl}
+
+
+
+ )}
+ {copyFeedback && (
+
{copyFeedback}
+ )}
)}
+
+
+ {!availableCollapsed && (
+
+ {stores.length === 0 && (
+
Noch keine Betriebe geladen. Aktualisiere nach dem Login.
+ )}
+ {stores.map((store) => {
+ const storeId = String(store.id);
+ const entry = configMap.get(storeId);
+ const isVisible = entry && !entry.hidden;
+ const needsRestore = entry && entry.hidden;
+ const blockedByNoPickups = store.hasPickupSlots === false;
+ let statusLabel = 'Hinzufügen';
+ let statusClass = 'text-blue-600';
+ if (isVisible) {
+ statusLabel = 'Bereits in Konfiguration';
+ statusClass = 'text-gray-500';
+ } else if (needsRestore) {
+ statusLabel = 'Ausgeblendet – erneut hinzufügen';
+ statusClass = 'text-amber-600';
+ }
+ if (blockedByNoPickups) {
+ statusLabel = 'Keine Pickups – automatisch verborgen';
+ statusClass = 'text-red-600';
+ }
+ return (
+
+ );
+ })}
+
+ )}
+
+ )}
+