@autobusal/routes-search 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/RoutesSearch.tsx +48 -4
- package/package.json +2 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
**The date picker follows the departure city.** Choosing a "from" city now sets the picker's floor to that city's timezone, and a pre-filled form (a shared link, or the search form kept on the results page) sets it on mount rather than waiting for a keystroke.
|
|
6
|
+
|
|
7
|
+
An unknown city *clears* the zone rather than keeping the last one — silently flooring a new search on the previous journey's clock is the subtler version of the same bug.
|
|
8
|
+
|
|
9
|
+
All notable changes to `@autobusal/routes-search` are documented here. This
|
|
10
|
+
project adheres to [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
11
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
12
|
+
|
|
13
|
+
## [1.1.1] - 2026-08-01
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **The return date could be set before the departure date.** The picker
|
|
18
|
+
floored at today, so an invalid pair was selectable and only refused by
|
|
19
|
+
an alert after pressing search. It now floors at whatever departure
|
|
20
|
+
currently holds, and follows it when that changes.
|
|
21
|
+
|
|
22
|
+
## [1.1.0] - 2026-07-25
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **Recovered as canonical source.** This package was published to npm and
|
|
27
|
+
in active use, but had no source anywhere in this monorepo (no
|
|
28
|
+
`packages/routes-search` directory, no git history) - the only copy of its
|
|
29
|
+
code existed as the published npm artifact. Recreated here,
|
|
30
|
+
byte-for-byte identical to the published 1.1.0 tarball (verified via
|
|
31
|
+
`diff` against the installed `node_modules/@autobusal/routes-search`), so it
|
|
32
|
+
can be edited and republished like every other package instead of
|
|
33
|
+
requiring reverse-engineering from `node_modules` or the npm tarball.
|
|
34
|
+
History prior to this point is not recoverable - no git log,
|
|
35
|
+
changelog, or other record of it exists.
|
|
36
|
+
|
|
37
|
+
Authored by Ferjolt Ozuni.
|
package/RoutesSearch.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import { TFunction } from 'i18next';
|
|
3
3
|
import { useForm } from 'react-hook-form';
|
|
4
4
|
import { FaArrowUp, FaHistory } from 'react-icons/fa';
|
|
5
5
|
import { AiOutlineSearch } from 'react-icons/ai';
|
|
6
|
-
import { Button, Autocomplete, Calendar, Passengers } from '@autobusal/common';
|
|
6
|
+
import { Button, Autocomplete, Calendar, Passengers, setDepartureZone } from '@autobusal/common';
|
|
7
7
|
import { Display, createDate } from '@autobusal/utilities';
|
|
8
8
|
import { getCities } from './utilities';
|
|
9
9
|
import { Options, Columns, Column, Item, Title, Action } from './styles';
|
|
@@ -26,10 +26,43 @@ interface Props {
|
|
|
26
26
|
const RoutesSearch = ({ type, from, to, departure, _return, adultsNo, childrenNo, babiesNo, t, onSearch }: Props): JSX.Element => {
|
|
27
27
|
const [ selected, setSelected ] = useState<'departure' | 'return'>(type);
|
|
28
28
|
|
|
29
|
+
// Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
30
|
+
// Tracked in state rather than read from the form, because the return
|
|
31
|
+
// picker's floor has to move the moment the departure date changes -
|
|
32
|
+
// react-hook-form's value alone would not re-render this.
|
|
33
|
+
const [ departureDate, setDepartureDate ] = useState<string>(departure);
|
|
34
|
+
|
|
29
35
|
const { register, handleSubmit, formState: { errors }, setValue } = useForm<RoutesSearchForm>();
|
|
30
36
|
|
|
31
37
|
const { data: CitiesData } = useGetSuggestions();
|
|
32
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Tell the date picker which clock this journey starts on.
|
|
41
|
+
*
|
|
42
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
43
|
+
*
|
|
44
|
+
* The picker used to floor on the buyer's device, then on our server's
|
|
45
|
+
* date - both wrong for the same reason: neither has anything to do with
|
|
46
|
+
* where the coach leaves from. Somebody in Shanghai at 06:00 on the 5th
|
|
47
|
+
* looking at an Italian coach leaving on the evening of the 4th had that
|
|
48
|
+
* day greyed out and could not ask for a seat the server would have sold.
|
|
49
|
+
*
|
|
50
|
+
* The value carries an optional stop (`slug:id`), so only the slug is
|
|
51
|
+
* matched. An unknown city clears the zone rather than keeping the last
|
|
52
|
+
* one, which would silently floor a new search on the old journey's clock.
|
|
53
|
+
*/
|
|
54
|
+
const onDeparture = useCallback((value: string): void => {
|
|
55
|
+
const slug = String(value).split(':')[0];
|
|
56
|
+
|
|
57
|
+
setDepartureZone(CitiesData.find(city => city.slug === slug)?.country?.timezone ?? null);
|
|
58
|
+
}, [CitiesData]);
|
|
59
|
+
|
|
60
|
+
// the form can also arrive pre-filled - from a shared link, or the search
|
|
61
|
+
// form kept on the results page - so the zone cannot wait for a keystroke
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
onDeparture(from);
|
|
64
|
+
}, [from, onDeparture]);
|
|
65
|
+
|
|
33
66
|
const onClick = (type: ('departure' | 'return')): void => {
|
|
34
67
|
setSelected(type);
|
|
35
68
|
};
|
|
@@ -104,7 +137,7 @@ const RoutesSearch = ({ type, from, to, departure, _return, adultsNo, childrenNo
|
|
|
104
137
|
validation="required"
|
|
105
138
|
t={ t }
|
|
106
139
|
refs={ register }
|
|
107
|
-
onUpdate={ setValue }
|
|
140
|
+
onUpdate={ (_, value) => { setValue('from', value); onDeparture(String(value)); } }
|
|
108
141
|
/>
|
|
109
142
|
|
|
110
143
|
{ Display(errors.from) }
|
|
@@ -138,7 +171,11 @@ const RoutesSearch = ({ type, from, to, departure, _return, adultsNo, childrenNo
|
|
|
138
171
|
t={ t }
|
|
139
172
|
validation="required"
|
|
140
173
|
refs={ register }
|
|
141
|
-
onUpdate={
|
|
174
|
+
onUpdate={ ((name, value) => {
|
|
175
|
+
setValue(name, value);
|
|
176
|
+
|
|
177
|
+
setDepartureDate(String(value));
|
|
178
|
+
}) as typeof setValue }
|
|
142
179
|
/>
|
|
143
180
|
|
|
144
181
|
{ Display(errors.departure) }
|
|
@@ -148,10 +185,17 @@ const RoutesSearch = ({ type, from, to, departure, _return, adultsNo, childrenNo
|
|
|
148
185
|
<Item>
|
|
149
186
|
<Title>{ t('routes_search.return', { ns: 'common' }) }</Title>
|
|
150
187
|
|
|
188
|
+
{ /* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
189
|
+
The return leg cannot start before the outbound one, so
|
|
190
|
+
the picker floors at whatever departure currently holds.
|
|
191
|
+
It used to floor at today, which let someone pick a
|
|
192
|
+
return before their departure and only told them so with
|
|
193
|
+
an alert after they pressed search. */ }
|
|
151
194
|
<Calendar
|
|
152
195
|
type="picker"
|
|
153
196
|
name="_return"
|
|
154
197
|
defaultValue={ _return }
|
|
198
|
+
minDate={ departureDate }
|
|
155
199
|
t={ t }
|
|
156
200
|
validation="required"
|
|
157
201
|
refs={ register }
|