feat: Enhance TimePointSelector with range input and apply changes functionality
- Updated PlotHistoricalSession to handle time range changes. - Modified TimePointSelector to include a new range input for selecting time range in seconds. - Implemented state management for the new range input and synchronized it with time changes. - Added apply changes button to confirm both time and range adjustments. - Improved logging for better debugging and tracking of changes.
This commit is contained in:
parent
0f928c50e7
commit
3803cc92ae
File diff suppressed because it is too large
Load Diff
|
@ -418,9 +418,12 @@ export default function PlotHistoricalSession({
|
|||
}
|
||||
|
||||
// Handle time change from TimePointSelector
|
||||
const handleTimePointChange = (newCentralTime) => {
|
||||
console.log('📊 Time selector change:', newCentralTime)
|
||||
const handleTimePointChange = (newCentralTime, newRangeSeconds = null) => {
|
||||
console.log('📊 Time selector change:', { newCentralTime, newRangeSeconds })
|
||||
setCentralTime(newCentralTime)
|
||||
if (newRangeSeconds !== null) {
|
||||
setTimeRangeSeconds(newRangeSeconds)
|
||||
}
|
||||
}
|
||||
|
||||
// Color mode
|
||||
|
@ -586,6 +589,7 @@ export default function PlotHistoricalSession({
|
|||
minDate={dateRange.minDate}
|
||||
maxDate={dateRange.maxDate}
|
||||
initial={centralTime}
|
||||
initialRangeSeconds={timeRangeSeconds}
|
||||
stepMinutes={1}
|
||||
dataSegments={dataSegments}
|
||||
onTimeChange={handleTimePointChange}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useMemo, useState, useCallback, useRef, useEffect } from "react";
|
||||
import { Box, Flex, Text, Slider, SliderTrack, SliderFilledTrack, SliderThumb, Button, IconButton, useColorModeValue } from "@chakra-ui/react";
|
||||
import { Box, Flex, Text, Slider, SliderTrack, SliderFilledTrack, SliderThumb, Button, IconButton, useColorModeValue, NumberInput, NumberInputField, NumberInputStepper, NumberIncrementStepper, NumberDecrementStepper } from "@chakra-ui/react";
|
||||
import { CheckIcon } from "@chakra-ui/icons";
|
||||
import DatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
|
@ -9,6 +9,7 @@ export default function TimePointSelector({
|
|||
minDate,
|
||||
maxDate,
|
||||
initial,
|
||||
initialRangeSeconds = 1000,
|
||||
stepMinutes = 5,
|
||||
dataSegments = [],
|
||||
onTimeChange,
|
||||
|
@ -32,6 +33,10 @@ export default function TimePointSelector({
|
|||
// Estado temporal del slider (solo para UI, no dispara eventos)
|
||||
const [sliderValue, setSliderValue] = useState(() => value.getTime());
|
||||
|
||||
// Estado para el range temporal (para UI y apply)
|
||||
const [rangeSeconds, setRangeSeconds] = useState(initialRangeSeconds);
|
||||
const [tempRangeSeconds, setTempRangeSeconds] = useState(initialRangeSeconds);
|
||||
|
||||
// Estado para detectar si hay cambios pendientes
|
||||
const [hasPendingChanges, setHasPendingChanges] = useState(false);
|
||||
|
||||
|
@ -57,6 +62,14 @@ export default function TimePointSelector({
|
|||
}, 0);
|
||||
}, [initial, minMs, maxMs]);
|
||||
|
||||
// Sincronizar con cambios externos en el range
|
||||
useEffect(() => {
|
||||
if (!isExternalUpdateRef.current) return; // Solo para actualizaciones externas
|
||||
|
||||
setRangeSeconds(initialRangeSeconds);
|
||||
setTempRangeSeconds(initialRangeSeconds);
|
||||
}, [initialRangeSeconds]);
|
||||
|
||||
const valueMs = value.getTime();
|
||||
|
||||
// Redondea al paso del slider
|
||||
|
@ -94,19 +107,20 @@ export default function TimePointSelector({
|
|||
};
|
||||
}, []);
|
||||
|
||||
// Función para aplicar los cambios pendientes del slider
|
||||
const applySliderChanges = useCallback(() => {
|
||||
// Función para aplicar los cambios pendientes (tiempo y/o range)
|
||||
const applyPendingChanges = useCallback(() => {
|
||||
if (!hasPendingChanges) return;
|
||||
|
||||
const newValue = new Date(sliderValue);
|
||||
setValue(newValue);
|
||||
setRangeSeconds(tempRangeSeconds);
|
||||
setHasPendingChanges(false);
|
||||
|
||||
if (onTimeChange) {
|
||||
console.log('📊 TimeSelector: Applying slider changes', newValue);
|
||||
onTimeChange(newValue);
|
||||
console.log('📊 TimeSelector: Applying changes', { time: newValue, range: tempRangeSeconds });
|
||||
onTimeChange(newValue, tempRangeSeconds);
|
||||
}
|
||||
}, [sliderValue, hasPendingChanges, onTimeChange]);
|
||||
}, [sliderValue, tempRangeSeconds, hasPendingChanges, onTimeChange]);
|
||||
|
||||
// Cambio desde el DatePicker (inmediato, actualiza ambos valores)
|
||||
const onPick = (d) => {
|
||||
|
@ -117,10 +131,10 @@ export default function TimePointSelector({
|
|||
setSliderValue(newValue.getTime());
|
||||
setHasPendingChanges(false);
|
||||
|
||||
// DatePicker es cambio directo
|
||||
// DatePicker es cambio directo - usar range actual
|
||||
if (onTimeChange) {
|
||||
console.log('📊 TimeSelector: DatePicker change (immediate)', newValue);
|
||||
onTimeChange(newValue);
|
||||
onTimeChange(newValue, rangeSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -129,7 +143,20 @@ export default function TimePointSelector({
|
|||
if (isExternalUpdateRef.current) return;
|
||||
|
||||
setSliderValue(ms);
|
||||
setHasPendingChanges(Math.abs(ms - value.getTime()) > 1000); // Solo marcar si hay diferencia significativa
|
||||
checkForPendingChanges(ms, tempRangeSeconds);
|
||||
};
|
||||
|
||||
// Cambio en el range input
|
||||
const onRangeChange = (newRangeSeconds) => {
|
||||
setTempRangeSeconds(newRangeSeconds);
|
||||
checkForPendingChanges(sliderValue, newRangeSeconds);
|
||||
};
|
||||
|
||||
// Función para verificar si hay cambios pendientes
|
||||
const checkForPendingChanges = (currentSliderValue, currentRangeSeconds) => {
|
||||
const timeChanged = Math.abs(currentSliderValue - value.getTime()) > 1000;
|
||||
const rangeChanged = Math.abs(currentRangeSeconds - rangeSeconds) > 0;
|
||||
setHasPendingChanges(timeChanged || rangeChanged);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -197,20 +224,7 @@ export default function TimePointSelector({
|
|||
</Box>
|
||||
|
||||
<Box flex="1" minW="260px">
|
||||
<Flex align="center" mb={1}>
|
||||
<Text color={textColor}>Navigate with slider</Text>
|
||||
{hasPendingChanges && (
|
||||
<Button
|
||||
size="xs"
|
||||
ml={2}
|
||||
colorScheme="blue"
|
||||
leftIcon={<CheckIcon />}
|
||||
onClick={applySliderChanges}
|
||||
>
|
||||
Apply
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
<Text color={textColor} mb={1}>Navigate with slider</Text>
|
||||
|
||||
{/* Slider with integrated data availability */}
|
||||
<Box position="relative" mb={2}>
|
||||
|
@ -264,6 +278,45 @@ export default function TimePointSelector({
|
|||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
{/* Range and Apply Controls */}
|
||||
<Flex mt={3} gap={3} align="center" wrap="wrap">
|
||||
<Box>
|
||||
<Text fontSize="sm" fontWeight="medium" color={textColor} mb={1}>
|
||||
Time Range (seconds)
|
||||
</Text>
|
||||
<NumberInput
|
||||
value={tempRangeSeconds}
|
||||
onChange={(valueString, valueNumber) => onRangeChange(isNaN(valueNumber) ? 1000 : valueNumber)}
|
||||
min={60}
|
||||
max={86400}
|
||||
size="sm"
|
||||
width="120px"
|
||||
>
|
||||
<NumberInputField />
|
||||
<NumberInputStepper>
|
||||
<NumberIncrementStepper />
|
||||
<NumberDecrementStepper />
|
||||
</NumberInputStepper>
|
||||
</NumberInput>
|
||||
</Box>
|
||||
|
||||
{hasPendingChanges && (
|
||||
<Box>
|
||||
<Text fontSize="sm" color="orange.500" mb={1}>
|
||||
Pending changes
|
||||
</Text>
|
||||
<Button
|
||||
size="sm"
|
||||
colorScheme="blue"
|
||||
leftIcon={<CheckIcon />}
|
||||
onClick={applyPendingChanges}
|
||||
>
|
||||
Apply Changes
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
|
|
Loading…
Reference in New Issue