fix: enforce future-dated ranges with modal picker
This commit is contained in:
173
src/App.js
173
src/App.js
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
||||||
import { BrowserRouter as Router, Routes, Route, Navigate, Link, useLocation, useNavigate } from 'react-router-dom';
|
import { BrowserRouter as Router, Routes, Route, Navigate, Link, useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { DateRange } from 'react-date-range';
|
import { DateRange } from 'react-date-range';
|
||||||
import { format, parseISO, isValid } from 'date-fns';
|
import { format, parseISO, isValid, startOfDay } from 'date-fns';
|
||||||
import { de } from 'date-fns/locale';
|
import { de } from 'date-fns/locale';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import 'react-date-range/dist/styles.css';
|
import 'react-date-range/dist/styles.css';
|
||||||
@@ -40,9 +40,16 @@ const formatRangeLabel = (start, end) => {
|
|||||||
return 'Zeitraum auswählen';
|
return 'Zeitraum auswählen';
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildSelectionRange = (start, end) => {
|
const buildSelectionRange = (start, end, minDate) => {
|
||||||
const startDate = parseDateValue(start) || parseDateValue(end) || new Date();
|
const minimum = minDate || startOfDay(new Date());
|
||||||
const endDate = parseDateValue(end) || parseDateValue(start) || startDate;
|
let startDate = parseDateValue(start) || parseDateValue(end) || minimum;
|
||||||
|
let endDate = parseDateValue(end) || parseDateValue(start) || startDate;
|
||||||
|
if (startDate < minimum) {
|
||||||
|
startDate = minimum;
|
||||||
|
}
|
||||||
|
if (endDate < minimum) {
|
||||||
|
endDate = startDate;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
@@ -76,6 +83,7 @@ function App() {
|
|||||||
const [dirtyDialogSaving, setDirtyDialogSaving] = useState(false);
|
const [dirtyDialogSaving, setDirtyDialogSaving] = useState(false);
|
||||||
const [confirmDialog, setConfirmDialog] = useState({ open: false, resolve: null });
|
const [confirmDialog, setConfirmDialog] = useState({ open: false, resolve: null });
|
||||||
const [activeRangePicker, setActiveRangePicker] = useState(null);
|
const [activeRangePicker, setActiveRangePicker] = useState(null);
|
||||||
|
const minSelectableDate = useMemo(() => startOfDay(new Date()), []);
|
||||||
|
|
||||||
const weekdays = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
|
const weekdays = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
|
||||||
|
|
||||||
@@ -866,7 +874,7 @@ function App() {
|
|||||||
return updated;
|
return updated;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}, [setConfig, setIsDirty]);
|
}, [setConfig]);
|
||||||
|
|
||||||
const configMap = useMemo(() => {
|
const configMap = useMemo(() => {
|
||||||
const map = new Map();
|
const map = new Map();
|
||||||
@@ -880,15 +888,21 @@ function App() {
|
|||||||
|
|
||||||
const visibleConfig = useMemo(() => config.filter((item) => !item.hidden), [config]);
|
const visibleConfig = useMemo(() => config.filter((item) => !item.hidden), [config]);
|
||||||
|
|
||||||
|
const activeRangeEntry = useMemo(() => {
|
||||||
|
if (!activeRangePicker) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return config.find((item) => item.id === activeRangePicker) || null;
|
||||||
|
}, [activeRangePicker, config]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeRangePicker) {
|
if (!activeRangePicker) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const stillExists = config.some((item) => item.id === activeRangePicker);
|
if (!activeRangeEntry || activeRangeEntry.desiredWeekday) {
|
||||||
if (!stillExists) {
|
|
||||||
setActiveRangePicker(null);
|
setActiveRangePicker(null);
|
||||||
}
|
}
|
||||||
}, [activeRangePicker, config]);
|
}, [activeRangePicker, activeRangeEntry]);
|
||||||
|
|
||||||
const handleStoreSelection = async (store) => {
|
const handleStoreSelection = async (store) => {
|
||||||
const storeId = String(store.id);
|
const storeId = String(store.id);
|
||||||
@@ -1343,62 +1357,24 @@ function App() {
|
|||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-2 border-b">
|
<td className="px-4 py-2 border-b">
|
||||||
<div className="relative">
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
onClick={() => {
|
||||||
onClick={() => {
|
if (item.desiredWeekday) {
|
||||||
if (item.desiredWeekday) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
setActiveRangePicker(item.id);
|
||||||
setActiveRangePicker((prev) => (prev === item.id ? null : item.id));
|
}}
|
||||||
}}
|
disabled={Boolean(item.desiredWeekday)}
|
||||||
disabled={Boolean(item.desiredWeekday)}
|
className={`w-full border rounded p-2 text-left transition focus:outline-none focus:ring-2 focus:ring-blue-500 ${
|
||||||
className={`w-full border rounded p-2 text-left transition focus:outline-none focus:ring-2 focus:ring-blue-500 ${
|
item.desiredWeekday
|
||||||
item.desiredWeekday
|
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||||
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
: 'bg-white hover:border-blue-400'
|
||||||
: 'bg-white hover:border-blue-400'
|
}`}
|
||||||
}`}
|
>
|
||||||
>
|
<span className="block text-sm text-gray-700">{formatRangeLabel(rangeStart, rangeEnd)}</span>
|
||||||
<span className="block text-sm text-gray-700">{formatRangeLabel(rangeStart, rangeEnd)}</span>
|
<span className="block text-xs text-gray-500">Klicke zum Auswählen</span>
|
||||||
<span className="block text-xs text-gray-500">Klicke zum Auswählen</span>
|
</button>
|
||||||
</button>
|
|
||||||
{activeRangePicker === item.id && !item.desiredWeekday && (
|
|
||||||
<div className="absolute z-20 mt-2 bg-white border border-gray-200 rounded-lg shadow-2xl">
|
|
||||||
<DateRange
|
|
||||||
onChange={(ranges) => {
|
|
||||||
const { startDate, endDate } = ranges.selection;
|
|
||||||
handleDateRangeSelection(item.id, startDate, endDate);
|
|
||||||
}}
|
|
||||||
moveRangeOnFirstSelection={false}
|
|
||||||
ranges={[buildSelectionRange(rangeStart, rangeEnd)]}
|
|
||||||
rangeColors={['#2563EB']}
|
|
||||||
months={1}
|
|
||||||
direction="horizontal"
|
|
||||||
showDateDisplay={false}
|
|
||||||
locale={de}
|
|
||||||
/>
|
|
||||||
<div className="flex items-center justify-between px-4 py-2 border-t text-sm bg-gray-50 rounded-b-lg">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="text-gray-600 hover:text-gray-900"
|
|
||||||
onClick={() => {
|
|
||||||
handleDateRangeSelection(item.id, null, null);
|
|
||||||
setActiveRangePicker(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Zurücksetzen
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="text-blue-600 font-semibold hover:text-blue-800"
|
|
||||||
onClick={() => setActiveRangePicker(null)}
|
|
||||||
>
|
|
||||||
Fertig
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-2 border-b">
|
<td className="px-4 py-2 border-b">
|
||||||
<div className="flex items-center justify-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
@@ -1437,6 +1413,75 @@ function App() {
|
|||||||
Konfiguration speichern
|
Konfiguration speichern
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{activeRangeEntry && !activeRangeEntry.desiredWeekday && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 z-40 flex items-center justify-center bg-black bg-opacity-40 px-4"
|
||||||
|
onClick={() => setActiveRangePicker(null)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="bg-white rounded-2xl shadow-2xl w-full max-w-lg"
|
||||||
|
onClick={(event) => event.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className="px-5 pt-5 pb-3 border-b">
|
||||||
|
<p className="text-xs uppercase tracking-wide text-gray-500">Zeitraum auswählen für</p>
|
||||||
|
<p className="text-lg font-semibold text-gray-900">
|
||||||
|
{activeRangeEntry.label || `Store ${activeRangeEntry.id}`}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="px-2 py-4">
|
||||||
|
<DateRange
|
||||||
|
onChange={(ranges) => {
|
||||||
|
const { startDate, endDate } = ranges.selection;
|
||||||
|
handleDateRangeSelection(activeRangeEntry.id, startDate, endDate);
|
||||||
|
}}
|
||||||
|
moveRangeOnFirstSelection={false}
|
||||||
|
ranges={[
|
||||||
|
buildSelectionRange(
|
||||||
|
activeRangeEntry.desiredDateRange?.start,
|
||||||
|
activeRangeEntry.desiredDateRange?.end,
|
||||||
|
minSelectableDate
|
||||||
|
)
|
||||||
|
]}
|
||||||
|
rangeColors={['#2563EB']}
|
||||||
|
months={1}
|
||||||
|
direction="horizontal"
|
||||||
|
showDateDisplay={false}
|
||||||
|
locale={de}
|
||||||
|
minDate={minSelectableDate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between px-5 py-3 border-t bg-gray-50 rounded-b-2xl">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-sm text-gray-600 hover:text-gray-900"
|
||||||
|
onClick={() => {
|
||||||
|
handleDateRangeSelection(activeRangeEntry.id, null, null);
|
||||||
|
setActiveRangePicker(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Zurücksetzen
|
||||||
|
</button>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-sm text-gray-600 hover:text-gray-900"
|
||||||
|
onClick={() => setActiveRangePicker(null)}
|
||||||
|
>
|
||||||
|
Abbrechen
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-sm font-semibold text-white bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-md"
|
||||||
|
onClick={() => setActiveRangePicker(null)}
|
||||||
|
>
|
||||||
|
Fertig
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { DateRange } from 'react-date-range';
|
import { DateRange } from 'react-date-range';
|
||||||
import { format, parseISO, isValid } from 'date-fns';
|
import { format, parseISO, isValid, startOfDay } from 'date-fns';
|
||||||
import { de } from 'date-fns/locale';
|
import { de } from 'date-fns/locale';
|
||||||
import 'react-date-range/dist/styles.css';
|
import 'react-date-range/dist/styles.css';
|
||||||
import 'react-date-range/dist/theme/default.css';
|
import 'react-date-range/dist/theme/default.css';
|
||||||
@@ -37,9 +37,16 @@ const formatRangeLabel = (start, end) => {
|
|||||||
return 'Zeitraum auswählen';
|
return 'Zeitraum auswählen';
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildSelectionRange = (start, end) => {
|
const buildSelectionRange = (start, end, minDate) => {
|
||||||
const startDate = parseDateValue(start) || parseDateValue(end) || new Date();
|
const minimum = minDate || startOfDay(new Date());
|
||||||
const endDate = parseDateValue(end) || parseDateValue(start) || startDate;
|
let startDate = parseDateValue(start) || parseDateValue(end) || minimum;
|
||||||
|
let endDate = parseDateValue(end) || parseDateValue(start) || startDate;
|
||||||
|
if (startDate < minimum) {
|
||||||
|
startDate = minimum;
|
||||||
|
}
|
||||||
|
if (endDate < minimum) {
|
||||||
|
endDate = startDate;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
@@ -53,6 +60,7 @@ const PickupConfigEditor = () => {
|
|||||||
const [status, setStatus] = useState('');
|
const [status, setStatus] = useState('');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [activeRangePicker, setActiveRangePicker] = useState(null);
|
const [activeRangePicker, setActiveRangePicker] = useState(null);
|
||||||
|
const minSelectableDate = startOfDay(new Date());
|
||||||
|
|
||||||
// Simulierte API-Endpunkte - diese müssen in Ihrer tatsächlichen Implementierung angepasst werden
|
// Simulierte API-Endpunkte - diese müssen in Ihrer tatsächlichen Implementierung angepasst werden
|
||||||
const API_URL = '/api/iobroker/pickup-config';
|
const API_URL = '/api/iobroker/pickup-config';
|
||||||
@@ -62,6 +70,16 @@ const PickupConfigEditor = () => {
|
|||||||
fetchConfig();
|
fetchConfig();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!activeRangePicker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const entry = config.find((item) => item.id === activeRangePicker);
|
||||||
|
if (!entry || entry.desiredWeekday) {
|
||||||
|
setActiveRangePicker(null);
|
||||||
|
}
|
||||||
|
}, [activeRangePicker, config]);
|
||||||
|
|
||||||
const fetchConfig = async () => {
|
const fetchConfig = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError('');
|
setError('');
|
||||||
@@ -155,27 +173,38 @@ const PickupConfigEditor = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDateRangeSelection = (index, startDate, endDate) => {
|
const handleDateRangeSelection = (entryId, startDate, endDate) => {
|
||||||
const newConfig = [...config];
|
|
||||||
const startValue = formatDateValue(startDate);
|
const startValue = formatDateValue(startDate);
|
||||||
const endValue = formatDateValue(endDate);
|
const endValue = formatDateValue(endDate);
|
||||||
if (startValue || endValue) {
|
setConfig((prev) =>
|
||||||
newConfig[index].desiredDateRange = {
|
prev.map((item) => {
|
||||||
start: startValue || endValue,
|
if (item.id !== entryId) {
|
||||||
end: endValue || startValue
|
return item;
|
||||||
};
|
}
|
||||||
if (newConfig[index].desiredWeekday) {
|
const updated = { ...item };
|
||||||
delete newConfig[index].desiredWeekday;
|
if (startValue || endValue) {
|
||||||
}
|
updated.desiredDateRange = {
|
||||||
} else if (newConfig[index].desiredDateRange) {
|
start: startValue || endValue,
|
||||||
delete newConfig[index].desiredDateRange;
|
end: endValue || startValue
|
||||||
}
|
};
|
||||||
if (newConfig[index].desiredDate) {
|
if (updated.desiredWeekday) {
|
||||||
delete newConfig[index].desiredDate;
|
delete updated.desiredWeekday;
|
||||||
}
|
}
|
||||||
setConfig(newConfig);
|
} else if (updated.desiredDateRange) {
|
||||||
|
delete updated.desiredDateRange;
|
||||||
|
}
|
||||||
|
if (updated.desiredDate) {
|
||||||
|
delete updated.desiredDate;
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const activeRangeEntry = activeRangePicker
|
||||||
|
? config.find((item) => item.id === activeRangePicker) || null
|
||||||
|
: null;
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div className="text-center p-8">Lade Konfiguration...</div>;
|
return <div className="text-center p-8">Lade Konfiguration...</div>;
|
||||||
}
|
}
|
||||||
@@ -265,62 +294,24 @@ const PickupConfigEditor = () => {
|
|||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-2">
|
<td className="px-4 py-2">
|
||||||
<div className="relative">
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
onClick={() => {
|
||||||
onClick={() => {
|
if (item.desiredWeekday) {
|
||||||
if (item.desiredWeekday) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
setActiveRangePicker(item.id);
|
||||||
setActiveRangePicker((prev) => (prev === item.id ? null : item.id));
|
}}
|
||||||
}}
|
disabled={Boolean(item.desiredWeekday)}
|
||||||
disabled={Boolean(item.desiredWeekday)}
|
className={`w-full border rounded p-2 text-left transition focus:outline-none focus:ring-2 focus:ring-blue-500 ${
|
||||||
className={`w-full border rounded p-2 text-left transition focus:outline-none focus:ring-2 focus:ring-blue-500 ${
|
item.desiredWeekday
|
||||||
item.desiredWeekday
|
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||||
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
: 'bg-white hover:border-blue-400'
|
||||||
: 'bg-white hover:border-blue-400'
|
}`}
|
||||||
}`}
|
>
|
||||||
>
|
<span className="block text-sm text-gray-700">{formatRangeLabel(rangeStart, rangeEnd)}</span>
|
||||||
<span className="block text-sm text-gray-700">{formatRangeLabel(rangeStart, rangeEnd)}</span>
|
<span className="block text-xs text-gray-500">Klicke zum Auswählen</span>
|
||||||
<span className="block text-xs text-gray-500">Klicke zum Auswählen</span>
|
</button>
|
||||||
</button>
|
|
||||||
{activeRangePicker === item.id && !item.desiredWeekday && (
|
|
||||||
<div className="absolute z-20 mt-2 bg-white border border-gray-200 rounded-lg shadow-2xl">
|
|
||||||
<DateRange
|
|
||||||
onChange={(ranges) => {
|
|
||||||
const { startDate, endDate } = ranges.selection;
|
|
||||||
handleDateRangeSelection(index, startDate, endDate);
|
|
||||||
}}
|
|
||||||
moveRangeOnFirstSelection={false}
|
|
||||||
ranges={[buildSelectionRange(rangeStart, rangeEnd)]}
|
|
||||||
rangeColors={['#2563EB']}
|
|
||||||
months={1}
|
|
||||||
direction="horizontal"
|
|
||||||
showDateDisplay={false}
|
|
||||||
locale={de}
|
|
||||||
/>
|
|
||||||
<div className="flex items-center justify-between px-4 py-2 border-t text-sm bg-gray-50 rounded-b-lg">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="text-gray-600 hover:text-gray-900"
|
|
||||||
onClick={() => {
|
|
||||||
handleDateRangeSelection(index, null, null);
|
|
||||||
setActiveRangePicker(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Zurücksetzen
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="text-blue-600 font-semibold hover:text-blue-800"
|
|
||||||
onClick={() => setActiveRangePicker(null)}
|
|
||||||
>
|
|
||||||
Fertig
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
@@ -350,6 +341,75 @@ const PickupConfigEditor = () => {
|
|||||||
{JSON.stringify(config, null, 2)}
|
{JSON.stringify(config, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{activeRangeEntry && !activeRangeEntry.desiredWeekday && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 z-40 flex items-center justify-center bg-black bg-opacity-40 px-4"
|
||||||
|
onClick={() => setActiveRangePicker(null)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="bg-white rounded-2xl shadow-2xl w-full max-w-lg"
|
||||||
|
onClick={(event) => event.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className="px-5 pt-5 pb-3 border-b">
|
||||||
|
<p className="text-xs uppercase tracking-wide text-gray-500">Zeitraum auswählen für</p>
|
||||||
|
<p className="text-lg font-semibold text-gray-900">
|
||||||
|
{activeRangeEntry.label || `Store ${activeRangeEntry.id}`}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="px-2 py-4">
|
||||||
|
<DateRange
|
||||||
|
onChange={(ranges) => {
|
||||||
|
const { startDate, endDate } = ranges.selection;
|
||||||
|
handleDateRangeSelection(activeRangeEntry.id, startDate, endDate);
|
||||||
|
}}
|
||||||
|
moveRangeOnFirstSelection={false}
|
||||||
|
ranges={[
|
||||||
|
buildSelectionRange(
|
||||||
|
activeRangeEntry.desiredDateRange?.start,
|
||||||
|
activeRangeEntry.desiredDateRange?.end,
|
||||||
|
minSelectableDate
|
||||||
|
)
|
||||||
|
]}
|
||||||
|
rangeColors={['#2563EB']}
|
||||||
|
months={1}
|
||||||
|
direction="horizontal"
|
||||||
|
showDateDisplay={false}
|
||||||
|
locale={de}
|
||||||
|
minDate={minSelectableDate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between px-5 py-3 border-t bg-gray-50 rounded-b-2xl">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-sm text-gray-600 hover:text-gray-900"
|
||||||
|
onClick={() => {
|
||||||
|
handleDateRangeSelection(activeRangeEntry.id, null, null);
|
||||||
|
setActiveRangePicker(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Zurücksetzen
|
||||||
|
</button>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-sm text-gray-600 hover:text-gray-900"
|
||||||
|
onClick={() => setActiveRangePicker(null)}
|
||||||
|
>
|
||||||
|
Abbrechen
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-sm font-semibold text-white bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-md"
|
||||||
|
onClick={() => setActiveRangePicker(null)}
|
||||||
|
>
|
||||||
|
Fertig
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user