Skip to content

Commit

Permalink
Realtime start
Browse files Browse the repository at this point in the history
  • Loading branch information
joao-vasconcelos committed Dec 5, 2023
1 parent c94b708 commit 217ba03
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ export default function LinesExplorerContentPatternPathStop({ pathStopData, path
<div className={styles.innerWrapper}>
<div className={styles.stopInfo}>
<LinesExplorerContentPatternPathStopName stopData={pathStopData.stop} isSelected={isThisStopSelected} />
{!isThisStopSelected && <LinesExplorerContentPatternPathStopRealtime patternId={linesExplorerContext.entities.pattern.id} stopId={pathStopData.stop.id} />}
{!isThisStopSelected && <LinesExplorerContentPatternPathStopRealtime patternId={linesExplorerContext.entities.pattern.id} stopId={pathStopData.stop.id} stopSequence={pathStopData.stop_sequence} />}
</div>

{isThisStopSelected && (
<div className={styles.content}>
<p className={styles.label}>Próximas circulações</p>
<LinesExplorerContentPatternPathStopRealtime patternId={linesExplorerContext.entities.pattern.id} stopId={pathStopData.stop.id} />
<LinesExplorerContentPatternPathStopRealtime patternId={linesExplorerContext.entities.pattern.id} stopId={pathStopData.stop.id} stopSequence={pathStopData.stop_sequence} />
</div>
)}

Expand Down Expand Up @@ -88,16 +88,14 @@ export default function LinesExplorerContentPatternPathStop({ pathStopData, path
</div>
)}

{/* {isThisStopSelected && (
<div className={styles.body}>
{isThisStopSelected && (
<div className={styles.content}>
<div className={styles.ids}>
<CopyBadge label={`#${pathStopData.stop.id}`} value={pathStopData.stop.id} />
<CopyBadge label={`${pathStopData.stop.lat}, ${pathStopData.stop.lon}`} value={`${pathStopData.stop.lat} ${pathStopData.stop.lon}`} />
</div>
<Text type="mini-label">Horários previstos nesta paragem</Text>
<LinesExplorerContentPatternPathStopTimetable stopSequence={pathStopData.stop_sequence} stopId={pathStopData.stop.id} />
</div>
)} */}
)}

{/* {isThisStopSelected && <LinesExplorerContentPatternPathStopPdf lineId={linesExplorerContext.entities.line.id} stopId={pathStopData.stop.id} direction={linesExplorerContext.entities.pattern.direction} />} */}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { useMemo } from 'react';
import { useTranslations, useFormatter, useNow } from 'next-intl';
import styles from './LinesExplorerContentPatternPathStopRealtime.module.css';
import LiveIcon from '@/components/LiveIcon/LiveIcon';
import parseStringToDate from '@/services/parseStringToDate';
import parseTimeStringToDate from '@/services/parseTimeStringToDate';

/* * */

export default function LinesExplorerContentPatternPathStopRealtime({ patternId, stopId }) {
export default function LinesExplorerContentPatternPathStopRealtime({ patternId, stopId, stopSequence }) {
//

//
Expand All @@ -23,76 +25,97 @@ export default function LinesExplorerContentPatternPathStopRealtime({ patternId,
//
// B. Fetch data

const { data: realtimeData } = useSWR(stopId && `https://api.carrismetropolitana.pt/stops/${stopId}/realtime`);
const { data: realtimeData } = useSWR(stopId && `https://api.carrismetropolitana.pt/stops/${stopId}/realtime`, { fetchInterval: 1000 });

//
// C. Handle actions

const estimatedNextArrivalTime = useMemo(() => {
//
if (!realtimeData) return '';
const nextEstimatedArrivals = useMemo(() => {
// Return early if no data is available
if (!realtimeData) return [];
// Filter estimates for the current pattern
const filteredRealtimeData = realtimeData.filter((item) => {
const filteredNextRealtimeArrivals = realtimeData.filter((item) => {
if (!item.estimated_arrival) return false;
const isForCurrentPattern = item.pattern_id === patternId;
return isForCurrentPattern;
const isForCurrentStopSequence = item.stop_sequence === stopSequence;
const isInTheFuture = parseTimeStringToDate(item.estimated_arrival) >= new Date();
return isForCurrentPattern && isForCurrentStopSequence && isInTheFuture;
});
// Sort by arrival_time
const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' });
const sortedRealtimeData = filteredRealtimeData.sort((a, b) => collator.compare(a.estimated_arrival, b.estimated_arrival));
// Exit early if no estimate matches this stop and pattern
if (!sortedRealtimeData.length) return '';
// Parse absolute time to relative
const relative = parseRelativeTime(sortedRealtimeData[0].estimated_arrival);
const sortedNextRealtimeArrivals = filteredNextRealtimeArrivals.sort((a, b) => collator.compare(a.estimated_arrival, b.estimated_arrival));
// Return result
return relative;

return sortedNextRealtimeArrivals;
//
}, [patternId, realtimeData]);

function parseRelativeTime(eta) {
// Skip if no eta
if (!eta) return null;

// Get current time
var now = new Date();
var currentHours = now.getHours();
var currentMinutes = now.getMinutes();
var currentSeconds = now.getSeconds();

// Parse ETA
var parts = eta.split(':');
var etaHours = parseInt(parts[0]);
var etaMinutes = parseInt(parts[1]);
var etaSeconds = parseInt(parts[2]);

// Calculate time difference
var diffHours = etaHours - currentHours;
var diffMinutes = etaMinutes - currentMinutes;
var diffSeconds = etaSeconds - currentSeconds;

// Convert time difference into minutes
var totalDiffMinutes = diffHours * 60 + diffMinutes + diffSeconds / 60;

// Check if the time is in the future
if (totalDiffMinutes >= 0) {
// Calculate the relative time as a Date object
var relativeTime = new Date();
relativeTime.setMinutes(relativeTime.getMinutes() + totalDiffMinutes);
return relativeTime;
} else {
// Return null for times that have already passed
return null;
}
}
}, [realtimeData, patternId, stopSequence]);

if (nextEstimatedArrivals.length > 0) console.log('filteredNextRealtimeArrivals', nextEstimatedArrivals);

// const estimatedNextArrivalTime = useMemo(() => {
// //
// if (!realtimeData) return '';
// // Filter estimates for the current pattern
// const filteredRealtimeData = realtimeData.filter((item) => {
// const isForCurrentPattern = item.pattern_id === patternId;
// return isForCurrentPattern;
// });
// // Sort by arrival_time
// const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' });
// const sortedRealtimeData = filteredRealtimeData.sort((a, b) => collator.compare(a.estimated_arrival, b.estimated_arrival));
// // Exit early if no estimate matches this stop and pattern
// if (!sortedRealtimeData.length) return '';
// // Parse absolute time to relative
// const relative = parseStringToDate(sortedRealtimeData[0].estimated_arrival);
// // console.log('sortedRealtimeData[0]', sortedRealtimeData[0]);
// // Return result
// return relative;
// //
// }, [patternId, realtimeData]);

// console.log(estimatedNextArrivalTime);

// function parseRelativeTime(eta) {
// // Skip if no eta
// if (!eta) return null;

// // Get current time
// var now = new Date();
// var currentHours = now.getHours();
// var currentMinutes = now.getMinutes();
// var currentSeconds = now.getSeconds();

// // Parse ETA
// var parts = eta.split(':');
// var etaHours = parseInt(parts[0]);
// var etaMinutes = parseInt(parts[1]);
// var etaSeconds = parseInt(parts[2]);

// // Calculate time difference
// var diffHours = etaHours - currentHours;
// var diffMinutes = etaMinutes - currentMinutes;
// var diffSeconds = etaSeconds - currentSeconds;

// // Convert time difference into minutes
// var totalDiffMinutes = diffHours * 60 + diffMinutes + diffSeconds / 60;

// // Calculate the relative time as a Date object
// var relativeTime = new Date();
// relativeTime.setMinutes(relativeTime.getMinutes() + totalDiffMinutes);
// return relativeTime;
// }

//
// C. Render components

return (
estimatedNextArrivalTime && (
nextEstimatedArrivals.length > 0 && (
<div className={styles.container}>
<LiveIcon />
<p className={styles.estimate}>{estimatedNextArrivalTime > new Date() ? t('will_pass', { value: format.relativeTime(estimatedNextArrivalTime, now) }) : t('just_passed', { value: format.relativeTime(estimatedNextArrivalTime, now) })}</p>
{nextEstimatedArrivals.map((item, index) => (
<div key={index} className={styles.container}>
<LiveIcon />
<p className={styles.estimate}>{item.estimated_arrival}</p>
</div>
))}
</div>
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import useSearch from '@/hooks/useSearch';
import { IconX, IconSearch } from '@tabler/icons-react';
import { useLinesExplorerContext } from '@/contexts/LinesExplorerContext';
import { useDebouncedValue } from '@mantine/hooks';
import LineDisplay from '../LineDisplay/LineDisplay';
import LineDisplay from '@/components/LineDisplay/LineDisplay';

/* * */

Expand Down Expand Up @@ -46,13 +46,16 @@ export default function LinesExplorerContentSelectPattern() {
}
// Update state with formatted patterns
setAllPatternsData(formattedPatternOptions);
// Pre-select the first pattern if none is selected
if (!linesExplorerContext.entities.pattern) {
linesExplorerContext.selectPattern(formattedPatternOptions[0]);
}
//
})();
}, [linesExplorerContext]);
}, [linesExplorerContext.entities.line?.id, linesExplorerContext.entities.line.patterns]);

useEffect(() => {
// Pre-select the first pattern if none is selected
if (!linesExplorerContext.entities.pattern && allPatternsData.length > 0) {
linesExplorerContext.selectPattern(allPatternsData[0]);
}
}, [allPatternsData, linesExplorerContext]);

//
// C. Search
Expand Down
3 changes: 2 additions & 1 deletion frontend/services/parseStringToDate.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
/* Explanation needed. */
/* * */

export default function parseStringToDate(dateString /* YYYYMMDD */) {
export default function parseStringToDate(dateString = '' /* YYYYMMDD */) {
if (!dateString.length === 8) return null;
// Extract year, month, and day from the string
const year = parseInt(dateString.slice(0, 4), 10);
const month = parseInt(dateString.slice(4, 6), 10) - 1; // Subtract 1 because months are zero-indexed in JavaScript
Expand Down
20 changes: 20 additions & 0 deletions frontend/services/parseTimeStringToDate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* * */
/* PARSE TIME STRING TO DATE */
/* Explanation needed. */
/* * */

export default function parseTimeStringToDate(timeString = '' /* HH:MM:DD */) {
if (!timeString.length === 8) return null;
// Extract hours, minutes, and seconds from the string
const timeStringParts = timeString.split(':');
const hours = parseInt(timeStringParts[0]);
const minutes = parseInt(timeStringParts[1]);
const seconds = parseInt(timeStringParts[2]);
// Create a new Date object with the extracted components
const dateObject = new Date();
dateObject.setHours(hours);
dateObject.setMinutes(minutes);
dateObject.setSeconds(seconds);
// Create a new Date object with the extracted components
return dateObject;
}
1 change: 1 addition & 0 deletions frontend/translations/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@
"placeholder": "Selecione uma data"
},
"LinesExplorerContent": {
"no_selection": "Selecione um destino",
"destination_label": "com destino a"
},
"LinesExplorerContentHeader": {
Expand Down

0 comments on commit 217ba03

Please sign in to comment.