@autobusal/operator-routes 1.10.5 → 1.11.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.
@@ -19,10 +19,14 @@ const Browse = ({ routeId, data, t, onReload }: Props): JSX.Element => {
19
19
  );
20
20
  }
21
21
 
22
- const items = data.map(item => (
22
+ const items = data.map((item, index) => (
23
23
  <Item
24
24
  key={ item.id }
25
25
  item={ item }
26
+ /* which end of the journey this is - nobody arrives at the stop they
27
+ board at, and nobody departs the one they get off at */
28
+ isFirst={ index === 0 }
29
+ isLast={ index === data.length - 1 }
26
30
  routeId={ routeId }
27
31
  t={ t }
28
32
  onReload={ onReload }
@@ -13,11 +13,13 @@ import Withdraw from '../Withdraw/Withdraw';
13
13
  interface Props {
14
14
  routeId: number
15
15
  item: LocationData
16
+ isFirst: boolean
17
+ isLast: boolean
16
18
  t: TFunction<'normal'>
17
19
  onReload: () => void
18
20
  }
19
21
 
20
- const Item = ({ routeId, item, t, onReload }: Props): JSX.Element => {
22
+ const Item = ({ routeId, item, isFirst, isLast, t, onReload }: Props): JSX.Element => {
21
23
  const { register, handleSubmit, formState: { errors } } = useForm<LocationForm>();
22
24
 
23
25
  const { mutate: Save, isPending: isPendingUpdate } = usePostUpdate(routeId, item.id);
@@ -97,18 +99,41 @@ const Item = ({ routeId, item, t, onReload }: Props): JSX.Element => {
97
99
  </select>
98
100
  </div>
99
101
 
102
+ { /*
103
+ Claude - 2026-08-30 (asked for by Ferjolt): ARRIVAL FIRST, then
104
+ departure - that is the order the coach does them in, and the
105
+ order a timetable is read in. It was the other way round.
106
+
107
+ And each end of the journey has only one meaningful time:
108
+ nobody arrives at the stop they board at, nobody departs the
109
+ one they get off at. Those are shown as not applicable rather
110
+ than demanded; the server mirrors the meaningful one into the
111
+ column so everything that reads both still works.
112
+ */ }
100
113
  <div className="row">
101
- { t('locations_manage.city.departure', { ns: 'common' }) }
114
+ { t('locations_manage.city.arrival', { ns: 'common' }) }
102
115
 
103
- <input type="text" defaultValue={ item.departure } { ...register('departure', Validate('required', t)) } />
104
- { Display(errors.departure) }
116
+ { isFirst ? (
117
+ <input type="text" disabled value="" placeholder={ t('locations_manage.city.not_applicable', { ns: 'common' }) } />
118
+ ) : (
119
+ <>
120
+ <input type="text" defaultValue={ item.arrival } { ...register('arrival', Validate('required', t)) } />
121
+ { Display(errors.arrival) }
122
+ </>
123
+ ) }
105
124
  </div>
106
125
 
107
126
  <div className="row">
108
- { t('locations_manage.city.arrival', { ns: 'common' }) }
127
+ { t('locations_manage.city.departure', { ns: 'common' }) }
109
128
 
110
- <input type="text" defaultValue={ item.arrival } { ...register('arrival', Validate('required', t)) } />
111
- { Display(errors.arrival) }
129
+ { isLast ? (
130
+ <input type="text" disabled value="" placeholder={ t('locations_manage.city.not_applicable', { ns: 'common' }) } />
131
+ ) : (
132
+ <>
133
+ <input type="text" defaultValue={ item.departure } { ...register('departure', Validate('required', t)) } />
134
+ { Display(errors.departure) }
135
+ </>
136
+ ) }
112
137
  </div>
113
138
  </Data>
114
139
 
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "@autobusal/operator-routes",
3
- "version": "1.10.5",
3
+ "version": "1.11.0",
4
4
  "author": "Ferjolt Ozuni",
5
5
  "type": "module",
6
- "main": "index.ts"
6
+ "main": "index.ts",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ }
7
10
  }
package/CHANGELOG.md DELETED
@@ -1,109 +0,0 @@
1
- # Changelog
2
-
3
- ## 1.10.1 - 2026-08-30
4
-
5
- - Staged dynamic pricing (roadmap P5): a per-route screen for the price rules - the opt-in, the operator's own caps, and the rules as a NUMBERED list read top to bottom, because the first rule whose band matches is the only one that applies. Each row says what it will actually do once the cap has had its say.
6
-
7
- ## 1.10.0 (2026-08-29)
8
-
9
- - Editors offer Save & Close alongside Save & Stay, so correcting a record no longer bounces you back to its list every time (opt-in per page, editing only).
10
-
11
- ## 1.9.0 (2026-08-29)
12
-
13
- - Route schedules and unavailability periods can be planned five years ahead, not one - the picker's ceiling was the only limit.
14
- - The 'add a stop' picker is searchable: every station on the platform was one native select, so finding your own city meant scrolling hundreds of options in an order nothing sorted for you.
15
-
16
- ## 1.6.1
17
-
18
- ### Fixed
19
-
20
- - **A copied or reversed route could not be opened.** The manage page read `data.drivers.registered` with the optional chain stopping one level short, so a route whose `drivers` relation was null crashed the whole page. Guarded. (Platform audit RT-09e; the backend now also copies the drivers row.)
21
-
22
- ## 1.6.0
23
-
24
- ### Added
25
-
26
- - **The stops taken off a route can be put back.** Withdrawal never destroyed
27
- anything - the stop's row, its price rows and the fares on them all survive
28
- - and both the API endpoint and this package's `useRestoreLocation` hook
29
- had existed since it shipped. Nothing rendered them: the locations response
30
- filters on `active`, so a withdrawn stop was never mentioned and no screen
31
- could offer to bring one back. From the operator's side a withdrawal was
32
- invisible and permanent, which is the one thing it was built not to be.
33
- The section appears only when the route has something to restore.
34
-
35
- ## 1.5.2
36
-
37
- ### Removed
38
-
39
- - **The confirm dialog in front of removing a stop.** It asked the question
40
- the withdrawal panel already asks - the panel names the stop, lists
41
- everybody still travelling through it and has its own button - and it
42
- answered one part wrongly, warning that the fares would have to be entered
43
- again. That stopped being true when calibration began reconciling price
44
- rows instead of rebuilding them: measured on a ten-stop route, withdrawing
45
- a stop keeps fourteen of sixteen fares and drops only the two legs through
46
- the stop itself.
47
-
48
- ## 1.3.3
49
-
50
- ### Fixed
51
-
52
- - **The ticket-language dropdown offered a country code and three options.**
53
- It listed the two content languages plus Greek as `gr` - the code for the
54
- country; the language is `el` - so an operator choosing it got English
55
- tickets and no error to say so. Now all fifteen languages the API can
56
- print, under their own names and their real codes.
57
-
58
- ## 1.3.2
59
-
60
- ### Added
61
-
62
- - **A stop added in a multi-zone country says so.** Times are stored local
63
- to their stop, and a country with no zone recorded falls back to the
64
- application's clock - a duration that reads plausibly and is wrong by
65
- hours. The API now answers `warning: 'timezone'` and the operator is told,
66
- because the operator is who sees the wrong number and would otherwise
67
- "fix" it by editing times that are correct as stored.
68
-
69
- ### Fixed
70
-
71
- - **`useAddLocation` returns its response.** It was awaited and discarded,
72
- so `onSuccess` received undefined - harmless while the endpoint answered
73
- with an empty object, and it would have swallowed the warning above.
74
-
75
- ## [1.3.1] - 2026-08-07
76
-
77
- ### Fixed
78
-
79
- - **Transiting country select no longer defaults to Afghanistan.** `value`
80
- was `0`, so submitting without touching the field added the first country
81
- in the list to the route's transit list.
82
-
83
- ## 1.3.0
84
-
85
- **The operator's own notice windows.**
86
-
87
- - `information_en|sq` replaces `policies_en|sq` on the route form.
88
- - Two new fields: cancellation notice and reschedule notice, in hours before departure, with a note saying the two things an operator cannot guess from the labels — that **empty means "not offered on this line"** (not zero, which would be offering it right up until the coach pulls away), and that these numbers are **never shown to passengers**.
89
-
90
- They decide whether Flexible Ticket may be sold on the line and what window it grants. A passenger only ever sees the resolved consequence.
91
-
92
- All notable changes to this package are documented here. This project follows [Keep a Changelog](https://keepachangelog.com/) and [Semantic Versioning](https://semver.org/).
93
-
94
- ## [1.2.0] - 2026-07-25
95
-
96
- ### Added
97
-
98
- - **"Required Passenger Details" checkbox list on the route form** (sex /
99
- passport / phone / WhatsApp / Telegram), stored as
100
- `routes_trip.passenger_fields`. A checked detail is shown AND required at
101
- checkout; unchecked ones are hidden entirely.
102
-
103
- ## [1.1.2] - 2026-07-19
104
-
105
- ### Fixed
106
-
107
- - `Transiting/Manage.tsx`: relaxed the transiting-country select's validation rule from `required|min:1` to `required`. The `min:1` rule was rejecting the field's default value of `0`, making a valid country selection unsubmittable; `required` alone correctly enforces that a country is chosen without misfiring on the `0` sentinel.
108
-
109
- Authored by Ferjolt Ozuni. Consolidated from the magus and alvavel whitelabel patch sets into canonical @autobusal source (eliminates per-repo patch-package divergence).