@autobusal/routes-order 1.23.0 → 1.23.2
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 +13 -0
- package/Found/Dates/styles.ts +12 -4
- package/Step5/Addons/Addons.tsx +61 -40
- package/Step5/Addons/styles.ts +74 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.23.2
|
|
4
|
+
|
|
5
|
+
- Flexible Ticket detail is now behind a small **Read More** link rather than the title. Its own control, so the thing you click to *read* is never next to the thing you click to *buy*. Closed by default; one line — "without it, this ticket cannot be cancelled or changed" — stays outside the collapse, because that is the material fact and hiding it would be a dark pattern rather than a tidy layout.
|
|
6
|
+
- **Date strip: dropped the joining comma.** Above 1024px the day number carried a `::before` comma so the cell would read "Mon, 03 Aug" on one line. The cells are narrow enough that the two parts wrap anyway, so the comma led the second line and every desktop cell rendered as "Mon" over ", 03 Aug". Punctuation that only works when text happens not to wrap will keep breaking.
|
|
7
|
+
|
|
8
|
+
## 1.23.1
|
|
9
|
+
|
|
10
|
+
**Flexible Ticket as a title, a price and an Add button, with the detail collapsed.**
|
|
11
|
+
|
|
12
|
+
A button rather than a checkbox, because this is not the same kind of choice as the notification add-ons beside it — those are a cheap tick, this one changes what the ticket *is*. The toggle and the Add button are separate controls on purpose: reading the terms must never be a way to accidentally buy them.
|
|
13
|
+
|
|
14
|
+
One line stays **outside** the collapse — "without it, this ticket cannot be cancelled or changed". Everything else is detail somebody can choose to read, but that is the material fact, and hiding what a buyer gets for nothing behind a toggle is the shape of a dark pattern rather than a tidy layout.
|
|
15
|
+
|
|
3
16
|
## 1.23.0
|
|
4
17
|
|
|
5
18
|
**Flexible Ticket at checkout.**
|
package/Found/Dates/styles.ts
CHANGED
|
@@ -99,12 +99,20 @@ export const DayNumber = styled.span`
|
|
|
99
99
|
display: block;
|
|
100
100
|
line-height: 1.2;
|
|
101
101
|
|
|
102
|
+
/*
|
|
103
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
104
|
+
*
|
|
105
|
+
* NO JOINING COMMA. This carried a ::before comma above 1024px, to read
|
|
106
|
+
* "Mon, 03 Aug" on one line. The cells are narrow enough
|
|
107
|
+
* that the weekday and the date wrap anyway, and the comma then led the
|
|
108
|
+
* second line - every desktop cell rendered as "Mon" over ", 03 Aug".
|
|
109
|
+
*
|
|
110
|
+
* Punctuation that only works when the text happens not to wrap is
|
|
111
|
+
* punctuation that will keep breaking; the two parts read perfectly well
|
|
112
|
+
* stacked without it.
|
|
113
|
+
*/
|
|
102
114
|
@media (min-width: 1024px) {
|
|
103
115
|
display: inline;
|
|
104
|
-
|
|
105
|
-
&::before {
|
|
106
|
-
content: ', ';
|
|
107
|
-
}
|
|
108
116
|
}
|
|
109
117
|
`;
|
|
110
118
|
|
package/Step5/Addons/Addons.tsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { TFunction } from 'i18next';
|
|
2
|
-
import {
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { RiWhatsappLine, RiTelegramLine, RiCalendarCheckLine, RiArrowUpSLine, RiArrowDownSLine } from 'react-icons/ri';
|
|
3
4
|
import { FlexOffer } from '@autobusal/providers/types/routes';
|
|
4
5
|
import { SubTitle } from '../../styles';
|
|
5
|
-
import { Container, Option, Notice, Terms, Term } from './styles';
|
|
6
|
+
import { Container, Option, Notice, Terms, Term, FlexHeader, FlexTitle, FlexToggle, FlexPrice, FlexAdd, FlexDetails } from './styles';
|
|
6
7
|
|
|
7
8
|
interface AddonsData {
|
|
8
9
|
whatsapp: { available: boolean, price: number }
|
|
@@ -39,6 +40,11 @@ const Addons = ({ data, flexOffer, currency, whatsapp, whatsappNumber, telegram,
|
|
|
39
40
|
// than no checkbox.
|
|
40
41
|
const hasFlex = flexOffer?.available === true;
|
|
41
42
|
|
|
43
|
+
// Closed to begin with. The title, the price and the Add button are the
|
|
44
|
+
// decision; the windows and the small print are for somebody who wants to
|
|
45
|
+
// check before making it.
|
|
46
|
+
const [ open, setOpen ] = useState<boolean>(false);
|
|
47
|
+
|
|
42
48
|
if (!data || (!data.whatsapp.available && !data.telegram.available && !hasFlex)) {
|
|
43
49
|
return null;
|
|
44
50
|
}
|
|
@@ -96,53 +102,68 @@ const Addons = ({ data, flexOffer, currency, whatsapp, whatsappNumber, telegram,
|
|
|
96
102
|
|
|
97
103
|
{ hasFlex && (
|
|
98
104
|
<Option>
|
|
99
|
-
<
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
checked={ flex }
|
|
103
|
-
onChange={ (event) => onChangeFlex(event.target.checked) }
|
|
104
|
-
/>
|
|
105
|
+
<FlexHeader>
|
|
106
|
+
<FlexTitle>
|
|
107
|
+
<RiCalendarCheckLine />
|
|
105
108
|
|
|
106
|
-
|
|
109
|
+
{ t('routes_order.step5.flex.title') }
|
|
107
110
|
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
<FlexPrice>{ flexOffer?.price_display }</FlexPrice>
|
|
112
|
+
</FlexTitle>
|
|
113
|
+
|
|
114
|
+
<FlexAdd type="button" $added={ flex } onClick={ () => onChangeFlex(!flex) }>
|
|
115
|
+
{ flex ? t('routes_order.step5.flex.remove') : t('routes_order.step5.flex.add') }
|
|
116
|
+
</FlexAdd>
|
|
117
|
+
</FlexHeader>
|
|
110
118
|
|
|
111
119
|
{/*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
120
|
+
* Deliberately OUTSIDE the collapse. Everything else here is
|
|
121
|
+
* detail somebody can choose to read, but this one line is the
|
|
122
|
+
* material fact - a buyer is being asked to pay for a right they
|
|
123
|
+
* would otherwise not have, and hiding what they get for nothing
|
|
124
|
+
* behind a toggle is the shape of a dark pattern rather than a
|
|
125
|
+
* tidy layout.
|
|
116
126
|
*/}
|
|
117
127
|
<Notice>{ t('routes_order.step5.flex.default') }</Notice>
|
|
118
128
|
|
|
119
|
-
<
|
|
120
|
-
{
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
129
|
+
<FlexToggle type="button" aria-expanded={ open } onClick={ () => setOpen(!open) }>
|
|
130
|
+
{ open ? t('routes_order.step5.flex.less') : t('routes_order.step5.flex.more') }
|
|
131
|
+
|
|
132
|
+
{ open ? <RiArrowUpSLine /> : <RiArrowDownSLine /> }
|
|
133
|
+
</FlexToggle>
|
|
134
|
+
|
|
135
|
+
{ open && (
|
|
136
|
+
<FlexDetails>
|
|
137
|
+
<Terms>
|
|
138
|
+
{ flexOffer?.refund_hours != null && (
|
|
139
|
+
<Term>{ t('routes_order.step5.flex.refund', { hours: flexOffer.refund_hours }) }</Term>
|
|
140
|
+
) }
|
|
141
|
+
|
|
142
|
+
{/*
|
|
143
|
+
* Either half can be absent on its own. An operator who
|
|
144
|
+
* will move a booking but not refund it is a real case, and
|
|
145
|
+
* listing only what this booking actually includes is the
|
|
146
|
+
* difference between an offer and a misrepresentation.
|
|
147
|
+
*/}
|
|
148
|
+
{ flexOffer?.reschedule_hours != null && (
|
|
149
|
+
<Term>{ t('routes_order.step5.flex.reschedule', { hours: flexOffer.reschedule_hours }) }</Term>
|
|
150
|
+
) }
|
|
151
|
+
</Terms>
|
|
152
|
+
|
|
153
|
+
<Notice>{ t('routes_order.step5.flex.nonrefundable') }</Notice>
|
|
154
|
+
|
|
155
|
+
{/*
|
|
156
|
+
* Statutory rights when the OPERATOR cancels are untouched by
|
|
157
|
+
* this and by anything else sold here. Saying so is both
|
|
158
|
+
* accurate and reassuring; leaving it out would imply the
|
|
159
|
+
* add-on is what grants them.
|
|
160
|
+
*/}
|
|
161
|
+
<Notice>{ t('routes_order.step5.flex.carrier') }</Notice>
|
|
162
|
+
</FlexDetails>
|
|
163
|
+
) }
|
|
144
164
|
</Option>
|
|
145
165
|
) }
|
|
166
|
+
|
|
146
167
|
</Container>
|
|
147
168
|
);
|
|
148
169
|
};
|
package/Step5/Addons/styles.ts
CHANGED
|
@@ -50,3 +50,77 @@ export const Term = styled.li`
|
|
|
50
50
|
font-size: 14px;
|
|
51
51
|
line-height: 1.5;
|
|
52
52
|
`;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The Flexible Ticket row: what it is and its price on the left, the
|
|
56
|
+
* decision on the right.
|
|
57
|
+
*
|
|
58
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
59
|
+
*
|
|
60
|
+
* A button rather than a checkbox, because this is not the same kind of
|
|
61
|
+
* choice as the notification add-ons beside it - those are a cheap tick, this
|
|
62
|
+
* one changes what the ticket IS. The two halves are separate controls on
|
|
63
|
+
* purpose: reading the terms must never be a way to accidentally buy them.
|
|
64
|
+
*/
|
|
65
|
+
export const FlexHeader = styled.div`
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
justify-content: space-between;
|
|
69
|
+
gap: 10px;
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
export const FlexTitle = styled.span`
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: 6px;
|
|
76
|
+
font-weight: 700;
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* "Read More", small and quiet, under the one line that always shows.
|
|
81
|
+
*
|
|
82
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
83
|
+
* Its own control rather than the title, so the thing you click to READ is
|
|
84
|
+
* never next to the thing you click to BUY.
|
|
85
|
+
*/
|
|
86
|
+
export const FlexToggle = styled.button`
|
|
87
|
+
display: inline-flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: 2px;
|
|
90
|
+
margin-top: 4px;
|
|
91
|
+
margin-left: 22px;
|
|
92
|
+
padding: 0;
|
|
93
|
+
border: 0;
|
|
94
|
+
background: none;
|
|
95
|
+
color: ${ props => props.theme.primary.normal };
|
|
96
|
+
font-family: inherit;
|
|
97
|
+
font-size: ${ props => props.theme.size.xs };
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
text-decoration: underline;
|
|
100
|
+
`;
|
|
101
|
+
|
|
102
|
+
export const FlexPrice = styled.span`
|
|
103
|
+
font-weight: 700;
|
|
104
|
+
white-space: nowrap;
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
export const FlexAdd = styled.button<{ $added: boolean }>`
|
|
108
|
+
flex: 0 0 auto;
|
|
109
|
+
padding: 6px 16px;
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
border: 1px solid ${ props => props.theme.primary.normal };
|
|
112
|
+
background: ${ props => props.$added ? 'transparent' : props.theme.primary.normal };
|
|
113
|
+
color: ${ props => props.$added ? props.theme.primary.normal : props.theme.primary.contrast };
|
|
114
|
+
font-family: inherit;
|
|
115
|
+
font-size: ${ props => props.theme.size.xs };
|
|
116
|
+
font-weight: 700;
|
|
117
|
+
cursor: pointer;
|
|
118
|
+
|
|
119
|
+
&:hover {
|
|
120
|
+
opacity: 0.85;
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
export const FlexDetails = styled.div`
|
|
125
|
+
margin-left: 22px;
|
|
126
|
+
`;
|