@autobusal/common 1.21.0 → 1.23.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 CHANGED
@@ -6,6 +6,36 @@ All notable changes to `@autobusal/common` are documented here. This project fol
6
6
  > Note: 1.10.0 through 1.15.1 were published without changelog entries. The
7
7
  > gap is left as-is rather than reconstructed after the fact.
8
8
 
9
+ ## 1.23.0
10
+
11
+ An unbookable date is inert, not merely faded.
12
+
13
+ It was dimmed and otherwise fully interactive: the pointer cursor and the
14
+ hover highlight still invited a click, and the click was answered with a
15
+ browser alert saying the date was invalid. The calendar offered a day, let
16
+ somebody reach for it, then told them off for taking the offer.
17
+
18
+ `pointer-events: none` removes it from the conversation entirely — no cursor
19
+ change, no hover, no click to refuse — alongside the `aria-disabled` and
20
+ `tabIndex=-1` already on the element. Unreachable by mouse, keyboard and
21
+ screen reader alike, and the alert is gone with it.
22
+
23
+ ## 1.22.0
24
+
25
+ The booking calendar floors on the SERVER's date, not the browser's.
26
+
27
+ `new Date()` is the buyer's device clock, which says nothing about where they
28
+ are travelling. Somebody in Shanghai at 06:00 on the 5th, looking at an
29
+ Italian coach that does not leave until the evening of the 4th, had that day
30
+ greyed out — while the server would have sold them the seat quite happily. The
31
+ calendar was refusing a sale the API accepted.
32
+
33
+ It also makes the picker agree with the date strip beside it, which has always
34
+ been built server-side; the two used to disagree about which day came first.
35
+
36
+ A date of birth keeps the local clock, because that one genuinely is about the
37
+ person in front of the screen.
38
+
9
39
  ## 1.21.0
10
40
 
11
41
  `reply` joins the table actions with its own icon and label. The operator
package/Calendar/Days.tsx CHANGED
@@ -19,6 +19,9 @@ const Days = ({ type, value, selected, minDate, onSelected }: Props): JSX.Elemen
19
19
  setCalendar(getCalendar(value));
20
20
  }, [value]);
21
21
 
22
+ // Edited: Ferjolt Ozuni - Date: 2026-08-03
23
+ // Only used to mark which cell is "today" visually - the FLOOR comes from
24
+ // getLimits below, which for a booking picker follows the server.
22
25
  const today = prepareDate(new Date());
23
26
 
24
27
  const limits = getLimits(type);
@@ -19,8 +19,13 @@ const Picker = ({ type, value, selected, minDate, t, onClick }: Props): (JSX.Ele
19
19
  const [ prepared, setPrepared ] = useState<string>(value);
20
20
 
21
21
  const onSelected = (prepared: string, disabled: boolean): void => {
22
+ // Edited: Ferjolt Ozuni - Date: 2026-08-03
23
+ // Silently, not with an alert. A disabled day is now inert in CSS as
24
+ // well (see Day in styles), so this can only be reached by something
25
+ // focusing the element programmatically - and a control that cannot be
26
+ // used should not interrupt somebody to say so.
22
27
  if (disabled) {
23
- return alert(t('general:errors.invalid.date'));
28
+ return;
24
29
  }
25
30
 
26
31
  onClick(prepared);
@@ -51,8 +51,26 @@ export const Day = styled.div<{
51
51
  color: ${ props => props.theme.primary.normal };
52
52
  ` }
53
53
 
54
+ /**
55
+ * Edited: Ferjolt Ozuni - Date: 2026-08-03
56
+ *
57
+ * A date that cannot be booked is INERT, not merely faded.
58
+ *
59
+ * It was dimmed and otherwise fully interactive: the pointer cursor and
60
+ * the hover highlight still invited a click, and the click was answered
61
+ * with a browser alert saying the date was invalid. So the calendar
62
+ * offered a day, let somebody reach for it, and then told them off for
63
+ * taking the offer.
64
+ *
65
+ * pointer-events: none removes it from the conversation entirely - no
66
+ * cursor change, no hover, no click to refuse. Together with the
67
+ * aria-disabled and tabIndex=-1 already on the element, it is unreachable
68
+ * by mouse, keyboard and screen reader alike.
69
+ */
54
70
  ${ props => props.$disabled === true && css`
55
71
  opacity: .3;
72
+ cursor: default;
73
+ pointer-events: none;
56
74
  ` }
57
75
 
58
76
  ${ props => props.$selected && css`
@@ -1,8 +1,48 @@
1
1
  import { createDate } from '@autobusal/utilities';
2
2
  import { CalendarLimit, DatesLimit, CalendarData } from '../types';
3
3
 
4
+ /**
5
+ * The earliest bookable date, as the server reckons it.
6
+ *
7
+ * Edited: Ferjolt Ozuni - Date: 2026-08-03
8
+ *
9
+ * Set once at startup from the settings payload. A module-level value rather
10
+ * than a prop threaded through four components: every calendar in the app
11
+ * wants the same answer, and the alternative was passing it through Picker
12
+ * and Days to reach the one function that needs it.
13
+ */
14
+ let serverToday: Date | null = null;
15
+
16
+ export const setServerToday = (value?: string): void => {
17
+ if (!value) {
18
+ return;
19
+ }
20
+
21
+ const [ day, month, year ] = value.split('/').map(Number);
22
+
23
+ if (!day || !month || !year) {
24
+ return;
25
+ }
26
+
27
+ serverToday = new Date(year, month - 1, day, 0, 0, 0, 0);
28
+ };
29
+
4
30
  export const getLimits = (type: ('picker' | 'dob' | 'date')): CalendarLimit => {
5
- const today = new Date();
31
+ // Edited: Ferjolt Ozuni - Date: 2026-08-03
32
+ //
33
+ // The BOOKING floor comes from the server; a date of birth does not.
34
+ //
35
+ // `new Date()` is the buyer's device clock, which has nothing to do with
36
+ // where they are travelling: somebody in Shanghai at 06:00 on the 5th
37
+ // looking at an Italian coach leaving on the evening of the 4th had that
38
+ // day greyed out, because their phone said it was past. The server would
39
+ // have sold them the seat; the calendar would not let them ask.
40
+ //
41
+ // A date of birth genuinely is about the person in front of the screen,
42
+ // so that one keeps the local clock.
43
+ const today = (type === 'picker' && serverToday)
44
+ ? new Date(serverToday.getTime())
45
+ : new Date();
6
46
 
7
47
  today.setHours(0, 0, 0, 0);
8
48
 
package/index.ts CHANGED
@@ -26,6 +26,7 @@ import Paragraph from './Loading/Paragraph';
26
26
  import Passengers from './Passengers/Passengers';
27
27
  import Password from './Password/Password';
28
28
  import Rating from './Rating/Rating';
29
+ import { setServerToday } from './Calendar/utilities/settings';
29
30
  import Policy from './Policy/Policy';
30
31
  import Report from './Report/Report';
31
32
  import RouteFeature from './RouteFeature/RouteFeature';
@@ -75,6 +76,7 @@ export {
75
76
  Passengers,
76
77
  Password,
77
78
  Rating,
79
+ setServerToday,
78
80
  Policy,
79
81
  Report,
80
82
  RouteFeature,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/common",
3
- "version": "1.21.0",
3
+ "version": "1.23.0",
4
4
  "author": "Ferjolt Ozuni",
5
5
  "type": "module",
6
6
  "main": "index.ts"