minor changes
This commit is contained in:
@@ -211,7 +211,11 @@ const NotificationPanel = ({
|
||||
<p>Standort wird geladen...</p>
|
||||
) : location ? (
|
||||
<p>
|
||||
Aktueller Standort: {location.lat.toFixed(4)}, {location.lon.toFixed(4)} (
|
||||
Aktueller Standort: {location.lat.toFixed(4)}, {location.lon.toFixed(4)}
|
||||
{location.label && (
|
||||
<span className="ml-1 font-semibold text-blue-900">– {location.label}</span>
|
||||
)}{' '}
|
||||
(
|
||||
{location.updatedAt ? new Date(location.updatedAt).toLocaleString('de-DE') : 'Zeit unbekannt'})
|
||||
</p>
|
||||
) : (
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
useReactTable
|
||||
} from '@tanstack/react-table';
|
||||
import { haversineDistanceKm } from '../utils/distance';
|
||||
import NotificationPanel from './NotificationPanel';
|
||||
|
||||
const REGION_STORAGE_KEY = 'storeWatchRegionSelection';
|
||||
const WATCH_TABLE_STATE_KEY = 'storeWatchTableState';
|
||||
@@ -92,7 +93,12 @@ const StoreWatchPage = ({
|
||||
knownStores = [],
|
||||
userLocation,
|
||||
onRequestLocation,
|
||||
locationLoading = false
|
||||
locationLoading = false,
|
||||
locationSaving = false,
|
||||
locationError = '',
|
||||
notificationPanelOpen = false,
|
||||
onToggleNotificationPanel = () => {},
|
||||
notificationProps
|
||||
}) => {
|
||||
const [regions, setRegions] = useState([]);
|
||||
const [selectedRegionId, setSelectedRegionId] = useState(() => {
|
||||
@@ -120,6 +126,9 @@ const StoreWatchPage = ({
|
||||
const [locationPromptTriggered, setLocationPromptTriggered] = useState(false);
|
||||
const [locationPromptPending, setLocationPromptPending] = useState(false);
|
||||
const [locationPromptError, setLocationPromptError] = useState('');
|
||||
const combinedLocationError = locationError || locationPromptError;
|
||||
const locationActionBusy = locationSaving || locationPromptPending;
|
||||
const formatCoordinate = (value) => (Number.isFinite(value) ? Number(value).toFixed(4) : '–');
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') {
|
||||
@@ -183,6 +192,16 @@ const StoreWatchPage = ({
|
||||
requestLocation();
|
||||
}, [userLocation, locationLoading, onRequestLocation, locationPromptTriggered, requestLocation]);
|
||||
|
||||
const handleManualDetectLocation = useCallback(() => {
|
||||
setLocationPromptError('');
|
||||
requestLocation();
|
||||
}, [requestLocation]);
|
||||
|
||||
const handleClearStoredLocation = useCallback(async () => {
|
||||
setLocationPromptError('');
|
||||
await onRequestLocation?.(null);
|
||||
}, [onRequestLocation]);
|
||||
|
||||
const watchedIds = useMemo(
|
||||
() => new Set(watchList.map((entry) => String(entry.storeId))),
|
||||
[watchList]
|
||||
@@ -848,6 +867,58 @@ const StoreWatchPage = ({
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 flex flex-wrap items-center justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onToggleNotificationPanel}
|
||||
className={`flex items-center justify-center w-11 h-11 rounded-full border ${
|
||||
notificationPanelOpen ? 'border-blue-500 text-blue-600' : 'border-gray-300 text-gray-600'
|
||||
} hover:text-blue-700 hover:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 transition`}
|
||||
title="Benachrichtigungen konfigurieren"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.89 3.31.877 2.42 2.42a1.724 1.724 0 0 0 1.065 2.572c1.757.426 1.757 2.924 0 3.35a1.724 1.724 0 0 0-1.066 2.573c.89 1.543-.877 3.31-2.42 2.42a1.724 1.724 0 0 0-2.572 1.065c-.426 1.757-2.924 1.757-3.35 0a1.724 1.724 0 0 0-2.573-1.066c-1.543.89-3.31-.877-2.42-2.42a1.724 1.724 0 0 0-1.065-2.572c-1.757-.426-1.757-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.89-1.543.877-3.31 2.42-2.42.996.575 2.273.155 2.573-1.065z"
|
||||
/>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z" />
|
||||
</svg>
|
||||
</button>
|
||||
{notificationProps?.loading && <span className="text-sm text-gray-500">Lade…</span>}
|
||||
</div>
|
||||
|
||||
{notificationPanelOpen && notificationProps && (
|
||||
<NotificationPanel
|
||||
{...notificationProps}
|
||||
location={userLocation}
|
||||
locationLoading={locationLoading}
|
||||
locationSaving={locationActionBusy}
|
||||
locationError={combinedLocationError}
|
||||
onDetectLocation={handleManualDetectLocation}
|
||||
onClearLocation={handleClearStoredLocation}
|
||||
/>
|
||||
)}
|
||||
|
||||
{userLocation && !notificationPanelOpen && (
|
||||
<div className="mb-4 rounded-lg border border-blue-100 bg-blue-50 p-4 text-sm text-blue-900">
|
||||
<p>
|
||||
Standort gespeichert:{' '}
|
||||
{userLocation.label ? (
|
||||
<span className="font-semibold">{userLocation.label}</span>
|
||||
) : (
|
||||
'Koordinaten'
|
||||
)}{' '}
|
||||
• {formatCoordinate(userLocation.lat)}, {formatCoordinate(userLocation.lon)}
|
||||
</p>
|
||||
<p className="text-xs text-blue-800 mt-1">
|
||||
Aktualisiert:{' '}
|
||||
{userLocation.updatedAt ? new Date(userLocation.updatedAt).toLocaleString('de-DE') : 'Zeit unbekannt'}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(error || status) && (
|
||||
<div className="mb-4 space-y-2">
|
||||
{error && (
|
||||
@@ -863,16 +934,16 @@ const StoreWatchPage = ({
|
||||
|
||||
{!userLocation && !locationLoading && onRequestLocation && (
|
||||
<div className="mb-6 rounded-lg border border-blue-200 bg-blue-50 p-4 text-sm text-blue-900">
|
||||
{locationPromptPending ? (
|
||||
{locationActionBusy ? (
|
||||
<p>Standort wird automatisch angefragt, um Entfernungen berechnen zu können...</p>
|
||||
) : locationPromptError ? (
|
||||
) : combinedLocationError ? (
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<p className="flex-1">{locationPromptError}</p>
|
||||
<p className="flex-1">{combinedLocationError}</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={requestLocation}
|
||||
onClick={handleManualDetectLocation}
|
||||
className="inline-flex items-center justify-center rounded-md bg-blue-600 px-4 py-2 text-sm font-semibold text-white hover:bg-blue-700 disabled:opacity-60"
|
||||
disabled={locationPromptPending}
|
||||
disabled={locationActionBusy}
|
||||
>
|
||||
Erneut versuchen
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user