@autobusal/routes-order 1.30.1 → 1.31.1
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 +33 -0
- package/Checkout/Checkout.tsx +17 -2
- package/Checkout/Sidebar/Sidebar.tsx +19 -5
- package/Step5/Payments/Payments.tsx +24 -1
- package/Step5/Summary/About/About.tsx +80 -64
- package/Step5/Summary/About/styles.ts +29 -0
- package/Step5/Summary/styles.ts +12 -5
- package/Step5/utilities.ts +39 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.31.1
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **One payment method means one button.** The picker no longer renders when
|
|
8
|
+
there is nothing to pick, and the button reads "Pay Now" rather than "Make
|
|
9
|
+
Payment" - a heading over a single option the buyer had to press before
|
|
10
|
+
pressing the real one was a click that only ever had one answer, on the
|
|
11
|
+
last screen before paying.
|
|
12
|
+
|
|
13
|
+
## 1.31.0
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **The checkout Order Summary stacks the legs vertically and numbers them**
|
|
18
|
+
— "Trip 1" above the outbound, "Trip 2" above the return.
|
|
19
|
+
|
|
20
|
+
They sat side by side from 768px up, which was written when the summary
|
|
21
|
+
spanned the page. It has lived in the checkout *sidebar* since 1.11.0 — a
|
|
22
|
+
narrow column — so two legs abreast left each about half the width a single
|
|
23
|
+
line like "Terminali Lindor Interurban dhe Nderkombetar i Autobusave (TEG)"
|
|
24
|
+
needs, and nothing said which was which. Vertical at every width now, in the
|
|
25
|
+
order they are travelled.
|
|
26
|
+
|
|
27
|
+
**The number is only rendered on a round trip.** A one-way has nothing to
|
|
28
|
+
enumerate, and a lone "Trip 1" would send the reader looking for a Trip 2
|
|
29
|
+
that was never bought. `Checkout/Sidebar` is the one component that knows
|
|
30
|
+
whether a second leg exists, so it is the one that decides — `About` just
|
|
31
|
+
takes an optional `number`.
|
|
32
|
+
|
|
33
|
+
"Trip" rather than "Segment": segment is airline jargon, and this is the
|
|
34
|
+
last screen before somebody pays for a bus ticket.
|
|
35
|
+
|
|
3
36
|
## 1.30.1
|
|
4
37
|
|
|
5
38
|
### Fixed
|
package/Checkout/Checkout.tsx
CHANGED
|
@@ -15,7 +15,7 @@ import Addons from '../Step5/Addons/Addons';
|
|
|
15
15
|
import Billing from '../Step5/Billing/Billing';
|
|
16
16
|
import Payments from '../Step5/Payments/Payments';
|
|
17
17
|
import Sidebar from './Sidebar/Sidebar';
|
|
18
|
-
import { getTotal, convertCoupon } from '../Step5/utilities';
|
|
18
|
+
import { getTotal, convertCoupon, getAvailablePayments } from '../Step5/utilities';
|
|
19
19
|
import { Title, Actions, Results, Listing } from '../styles';
|
|
20
20
|
import { RoutesSearchForm } from '@autobusal/routes-search/types';
|
|
21
21
|
import { PersonData, BillingData } from '@autobusal/providers/types/persons';
|
|
@@ -24,7 +24,7 @@ import { CouponData } from '@autobusal/providers/types/orders';
|
|
|
24
24
|
import { TotalData } from '../types';
|
|
25
25
|
import { useUserStore } from '@autobusal/providers/stores/user';
|
|
26
26
|
import { useGetSettings } from '@autobusal/providers/services';
|
|
27
|
-
import { usePostOrder, useGetFlex } from '../services';
|
|
27
|
+
import { usePostOrder, useGetFlex, useGetPayments } from '../services';
|
|
28
28
|
import { addon as commerceAddon, beginCheckout, stash } from '@autobusal/providers/Setup/commerce';
|
|
29
29
|
import { item as commerceItem } from '../commerce';
|
|
30
30
|
|
|
@@ -74,6 +74,20 @@ const Checkout = ({ values, step1, step2, step3, isPartner, t, onStore, onBack }
|
|
|
74
74
|
const [ total, setTotal ] = useState<TotalData>(getTotal(step2, step3));
|
|
75
75
|
const [ action, setAction ] = useState<string | undefined>(undefined);
|
|
76
76
|
|
|
77
|
+
/*
|
|
78
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-07
|
|
79
|
+
*
|
|
80
|
+
* Whether there is a payment CHOICE to be made, which decides both whether
|
|
81
|
+
* the picker draws itself and what the button says.
|
|
82
|
+
*
|
|
83
|
+
* The same query the picker runs, under the same key, so react-query
|
|
84
|
+
* answers it from cache - this reads the answer, it does not fetch it a
|
|
85
|
+
* second time.
|
|
86
|
+
*/
|
|
87
|
+
const { data: paymentsData } = useGetPayments();
|
|
88
|
+
|
|
89
|
+
const singleMethod = getAvailablePayments(paymentsData, isPartner ?? false).length === 1;
|
|
90
|
+
|
|
77
91
|
const [ addonWhatsapp, setAddonWhatsapp ] = useState<boolean>(false);
|
|
78
92
|
const [ addonWhatsappNumber, setAddonWhatsappNumber ] = useState<string>('');
|
|
79
93
|
const [ addonTelegram, setAddonTelegram ] = useState<boolean>(false);
|
|
@@ -312,6 +326,7 @@ const Checkout = ({ values, step1, step2, step3, isPartner, t, onStore, onBack }
|
|
|
312
326
|
coupon={ coupon }
|
|
313
327
|
total={ grandTotal }
|
|
314
328
|
action={ action }
|
|
329
|
+
single={ singleMethod }
|
|
315
330
|
pending={ isPending }
|
|
316
331
|
t={ t }
|
|
317
332
|
onPay={ onPay }
|
|
@@ -26,6 +26,7 @@ interface Props {
|
|
|
26
26
|
coupon?: CouponData
|
|
27
27
|
total: TotalData
|
|
28
28
|
action?: string
|
|
29
|
+
single?: boolean
|
|
29
30
|
pending: boolean
|
|
30
31
|
t: TFunction<'common'>
|
|
31
32
|
onPay: () => void
|
|
@@ -45,7 +46,7 @@ interface Props {
|
|
|
45
46
|
* page and scrolled away while add-ons were being ticked - so the number
|
|
46
47
|
* changed out of sight of the person it was changing for.
|
|
47
48
|
*/
|
|
48
|
-
const Sidebar = ({ step1, step2, step3, fare, addons, coupon, total, action, pending, t, onPay, children, payments }: Props): JSX.Element => (
|
|
49
|
+
const Sidebar = ({ step1, step2, step3, fare, addons, coupon, total, action, single, pending, t, onPay, children, payments }: Props): JSX.Element => (
|
|
49
50
|
<Container>
|
|
50
51
|
<Panel className="box">
|
|
51
52
|
<SubTitle>
|
|
@@ -53,9 +54,14 @@ const Sidebar = ({ step1, step2, step3, fare, addons, coupon, total, action, pen
|
|
|
53
54
|
{ t('routes_order.step5.summary.title') }
|
|
54
55
|
</SubTitle>
|
|
55
56
|
|
|
57
|
+
{ /* Edited: Ferjolt Ozuni - Date: 2026-08-06
|
|
58
|
+
Numbered only on a ROUND TRIP. This is the one place that knows
|
|
59
|
+
whether a second leg exists, so it is the one place that can
|
|
60
|
+
decide - a one-way labelled "Trip 1" would send the reader looking
|
|
61
|
+
for a Trip 2 that was never bought. */ }
|
|
56
62
|
<Information>
|
|
57
|
-
<About type="departure" step1={ step1 } data={ step2 } t={ t } />
|
|
58
|
-
<About type="return" step1={ step1 } data={ step3 } t={ t } />
|
|
63
|
+
<About type="departure" step1={ step1 } data={ step2 } number={ step3 ? 1 : undefined } t={ t } />
|
|
64
|
+
<About type="return" step1={ step1 } data={ step3 } number={ step3 ? 2 : undefined } t={ t } />
|
|
59
65
|
</Information>
|
|
60
66
|
|
|
61
67
|
{ /* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
@@ -84,7 +90,13 @@ const Sidebar = ({ step1, step2, step3, fare, addons, coupon, total, action, pen
|
|
|
84
90
|
{ /* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
85
91
|
The label follows the chosen method, so the button says what it
|
|
86
92
|
is about to do - "Reserve" does not take money, and a button
|
|
87
|
-
reading "Make Payment" for it would be a lie.
|
|
93
|
+
reading "Make Payment" for it would be a lie.
|
|
94
|
+
|
|
95
|
+
Edited: Ferjolt Ozuni - Date: 2026-08-07
|
|
96
|
+
And when there is only one method, the picker above renders
|
|
97
|
+
nothing, so this is the whole payment step. "Make Payment" reads
|
|
98
|
+
as "proceed to the part where you pay"; with nothing left in
|
|
99
|
+
between, it should say what actually happens next. */ }
|
|
88
100
|
<Button
|
|
89
101
|
loading={ pending }
|
|
90
102
|
noMargin
|
|
@@ -93,7 +105,9 @@ const Sidebar = ({ step1, step2, step3, fare, addons, coupon, total, action, pen
|
|
|
93
105
|
<MdDone />
|
|
94
106
|
{ action === 'reserve'
|
|
95
107
|
? t('routes_order.step5.reserve')
|
|
96
|
-
:
|
|
108
|
+
: single
|
|
109
|
+
? t('routes_order.step5.pay_now')
|
|
110
|
+
: t('routes_order.step5.next') }
|
|
97
111
|
</>
|
|
98
112
|
) }
|
|
99
113
|
onClick={ onPay }
|
|
@@ -7,6 +7,7 @@ import { Inline } from '@autobusal/common';
|
|
|
7
7
|
import { SubTitle } from '../../styles';
|
|
8
8
|
import { Container, ContainerPayments, ButtonPayment } from './styles';
|
|
9
9
|
import { useGetPayments } from '../../services';
|
|
10
|
+
import { getAvailablePayments } from '../utilities';
|
|
10
11
|
|
|
11
12
|
interface Props {
|
|
12
13
|
selected: string
|
|
@@ -15,9 +16,11 @@ interface Props {
|
|
|
15
16
|
onChange: (action: string) => void
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const Payments = ({ selected, isPartner, t, onChange }: Props): JSX.Element => {
|
|
19
|
+
const Payments = ({ selected, isPartner, t, onChange }: Props): JSX.Element | null => {
|
|
19
20
|
const { data, isLoading, isSuccess } = useGetPayments();
|
|
20
21
|
|
|
22
|
+
const available = getAvailablePayments(data, isPartner);
|
|
23
|
+
|
|
21
24
|
useEffect(() => {
|
|
22
25
|
if (isSuccess) {
|
|
23
26
|
const found = Object.keys(data).find(item => {
|
|
@@ -37,6 +40,26 @@ const Payments = ({ selected, isPartner, t, onChange }: Props): JSX.Element => {
|
|
|
37
40
|
);
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
/*
|
|
44
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-07
|
|
45
|
+
*
|
|
46
|
+
* One method is not a choice, so there is nothing to draw.
|
|
47
|
+
*
|
|
48
|
+
* A heading reading "Payment Method" over a single button the buyer must
|
|
49
|
+
* press before pressing the real one is a step that only ever has one
|
|
50
|
+
* answer - and it is the last screen before paying, which is the worst
|
|
51
|
+
* place to spend a click. The effect above has already selected it, so the
|
|
52
|
+
* button beside this can simply say "Pay Now".
|
|
53
|
+
*
|
|
54
|
+
* Rendering nothing rather than hiding with CSS: the picker is a control,
|
|
55
|
+
* and a control nobody can act on should not be in the page at all - it
|
|
56
|
+
* would still be reachable by keyboard and still announced by a screen
|
|
57
|
+
* reader as a thing to decide.
|
|
58
|
+
*/
|
|
59
|
+
if (available.length <= 1) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
40
63
|
return (
|
|
41
64
|
<>
|
|
42
65
|
<Container>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TFunction } from 'i18next';
|
|
2
2
|
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa';
|
|
3
3
|
import { FaCircleDot, FaLocationDot } from 'react-icons/fa6';
|
|
4
|
-
import { Container, ContainerIcon, Icon, Information, Title, Operator, Carrier, Logo, Leg, Point, PointIcon, PointCity, Country, PointMeta } from './styles';
|
|
4
|
+
import { Trip, TripLabel, Container, ContainerIcon, Icon, Information, Title, Operator, Carrier, Logo, Leg, Point, PointIcon, PointCity, Country, PointMeta } from './styles';
|
|
5
5
|
import { RoutesSearchForm } from '@autobusal/routes-search/types';
|
|
6
6
|
import { FoundData } from '@autobusal/providers/types/routes';
|
|
7
7
|
|
|
@@ -9,6 +9,16 @@ interface Props {
|
|
|
9
9
|
type: 'departure' | 'return'
|
|
10
10
|
step1: RoutesSearchForm
|
|
11
11
|
data?: FoundData
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Which leg of the journey this is, 1-based.
|
|
15
|
+
*
|
|
16
|
+
* Ferjolt Ozuni - Date: 2026-08-06
|
|
17
|
+
* Only passed on a ROUND TRIP - the caller is the one that knows whether
|
|
18
|
+
* there is a second leg, and a one-way has nothing to number.
|
|
19
|
+
*/
|
|
20
|
+
number?: number
|
|
21
|
+
|
|
12
22
|
t: TFunction<'public'>
|
|
13
23
|
}
|
|
14
24
|
|
|
@@ -26,7 +36,7 @@ interface Props {
|
|
|
26
36
|
* before someone pays, and "Thessaloniki, Greece" settles a doubt that
|
|
27
37
|
* "(GRC)" only half answers.
|
|
28
38
|
*/
|
|
29
|
-
const About = ({ type, step1, data, t }: Props): (JSX.Element | null) => {
|
|
39
|
+
const About = ({ type, step1, data, number, t }: Props): (JSX.Element | null) => {
|
|
30
40
|
if (!data) {
|
|
31
41
|
return null;
|
|
32
42
|
}
|
|
@@ -36,68 +46,74 @@ const About = ({ type, step1, data, t }: Props): (JSX.Element | null) => {
|
|
|
36
46
|
const date = type === 'departure' ? step1.departure : step1._return;
|
|
37
47
|
|
|
38
48
|
return (
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
49
|
+
<Trip>
|
|
50
|
+
{ number !== undefined && (
|
|
51
|
+
<TripLabel>{ t('routes_order.step5.summary.trip', { number }) }</TripLabel>
|
|
52
|
+
) }
|
|
53
|
+
|
|
54
|
+
<Container>
|
|
55
|
+
<ContainerIcon>
|
|
56
|
+
<Icon>{ icon }</Icon>
|
|
57
|
+
</ContainerIcon>
|
|
58
|
+
|
|
59
|
+
<Information>
|
|
60
|
+
<Title>{ data.name } ({ data.code })</Title>
|
|
61
|
+
|
|
62
|
+
{ /* Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
63
|
+
Mark and name together, ranged right. The name used to sit
|
|
64
|
+
alone at the foot of the block, so the logo read as decoration
|
|
65
|
+
rather than as the operator being identified. */ }
|
|
66
|
+
<Carrier>
|
|
67
|
+
{ data.operator.logo_url && (
|
|
68
|
+
<Logo src={ data.operator.logo_url } alt={ data.operator.company } />
|
|
69
|
+
) }
|
|
70
|
+
|
|
71
|
+
<Operator>{ data.operator.company }</Operator>
|
|
72
|
+
</Carrier>
|
|
73
|
+
|
|
74
|
+
<Leg>
|
|
75
|
+
<Point>
|
|
76
|
+
<PointIcon><FaCircleDot /></PointIcon>
|
|
77
|
+
|
|
78
|
+
<PointCity>
|
|
79
|
+
{ data.locations.from.city.name }
|
|
80
|
+
{ data.locations.from.city.country?.name && (
|
|
81
|
+
<Country>, { data.locations.from.city.country.name }</Country>
|
|
82
|
+
) }
|
|
83
|
+
</PointCity>
|
|
84
|
+
|
|
85
|
+
{ /* the date and time are what a buyer double-checks before
|
|
86
|
+
paying, so they carry the weight here */ }
|
|
87
|
+
<PointMeta $strong>
|
|
88
|
+
{ t('routes_order.step5.summary.departs', {
|
|
89
|
+
date,
|
|
90
|
+
hour: data.locations.from.departure,
|
|
91
|
+
stop: data.locations.from.stop?.name
|
|
92
|
+
}) }
|
|
93
|
+
</PointMeta>
|
|
94
|
+
</Point>
|
|
95
|
+
|
|
96
|
+
<Point>
|
|
97
|
+
<PointIcon><FaLocationDot /></PointIcon>
|
|
98
|
+
|
|
99
|
+
<PointCity>
|
|
100
|
+
{ data.locations.to.city.name }
|
|
101
|
+
{ data.locations.to.city.country?.name && (
|
|
102
|
+
<Country>, { data.locations.to.city.country.name }</Country>
|
|
103
|
+
) }
|
|
104
|
+
</PointCity>
|
|
105
|
+
|
|
106
|
+
<PointMeta>
|
|
107
|
+
{ t('routes_order.step5.summary.arrives', {
|
|
108
|
+
hour: data.locations.to.arrival,
|
|
109
|
+
stop: data.locations.to.stop?.name
|
|
110
|
+
}) }
|
|
111
|
+
</PointMeta>
|
|
112
|
+
</Point>
|
|
113
|
+
</Leg>
|
|
114
|
+
</Information>
|
|
115
|
+
</Container>
|
|
116
|
+
</Trip>
|
|
101
117
|
);
|
|
102
118
|
};
|
|
103
119
|
|
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
import styled from 'styled-components';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* One leg, with its number above it.
|
|
5
|
+
*
|
|
6
|
+
* Ferjolt Ozuni - Date: 2026-08-06
|
|
7
|
+
* This wrapper exists so the label can sit ACROSS the leg rather than beside
|
|
8
|
+
* the arrow: Container below is the icon-and-content row, and a heading
|
|
9
|
+
* placed inside it would indent into the content column and read as part of
|
|
10
|
+
* the route name.
|
|
11
|
+
*/
|
|
12
|
+
export const Trip = styled.div`
|
|
13
|
+
flex: 1;
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* "Trip 1", "Trip 2" - only rendered when there are two.
|
|
18
|
+
*
|
|
19
|
+
* Ferjolt Ozuni - Date: 2026-08-06
|
|
20
|
+
* A one-way booking has nothing to enumerate, and numbering a lone leg would
|
|
21
|
+
* invite the reader to go looking for the other one.
|
|
22
|
+
*/
|
|
23
|
+
export const TripLabel = styled.div`
|
|
24
|
+
margin-bottom: 8px;
|
|
25
|
+
color: ${ props => props.theme.font.faded };
|
|
26
|
+
font-size: ${ props => props.theme.size.xs };
|
|
27
|
+
font-weight: 700;
|
|
28
|
+
text-transform: uppercase;
|
|
29
|
+
letter-spacing: 0.06em;
|
|
30
|
+
`;
|
|
31
|
+
|
|
3
32
|
export const Container = styled.div`
|
|
4
33
|
flex: 1;
|
|
5
34
|
display: flex;
|
package/Step5/Summary/styles.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import styled from 'styled-components';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The legs of the booking, stacked.
|
|
5
|
+
*
|
|
6
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-06
|
|
7
|
+
* They used to sit SIDE BY SIDE from 768px up. That was written when the
|
|
8
|
+
* summary spanned the page; it now lives in the checkout sidebar, a narrow
|
|
9
|
+
* column, where two legs abreast left each one about half the room a single
|
|
10
|
+
* line like "Terminali Lindor Interurban dhe Nderkombetar i Autobusave
|
|
11
|
+
* (TEG)" needs. Vertical at every width, so each leg gets the panel's full
|
|
12
|
+
* width and the two read in the order they are travelled.
|
|
13
|
+
*/
|
|
3
14
|
export const Information = styled.div`
|
|
4
15
|
display: flex;
|
|
5
16
|
flex-direction: column;
|
|
6
|
-
gap:
|
|
7
|
-
|
|
8
|
-
@media (min-width: 768px) {
|
|
9
|
-
flex-direction: row;
|
|
10
|
-
}
|
|
17
|
+
gap: 20px;
|
|
11
18
|
`;
|
package/Step5/utilities.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FoundData } from '@autobusal/providers/types/routes';
|
|
2
2
|
import { CouponData } from '@autobusal/providers/types/orders';
|
|
3
|
-
import { TotalData } from '../types';
|
|
3
|
+
import { ActionData, TotalData } from '../types';
|
|
4
4
|
|
|
5
5
|
export const getTotal = (step2: FoundData, step3?: FoundData): TotalData => {
|
|
6
6
|
// we get the currency
|
|
@@ -21,4 +21,41 @@ export const convertCoupon = (data: CouponData): TotalData => {
|
|
|
21
21
|
display: data.total,
|
|
22
22
|
value: Number(currency[0])
|
|
23
23
|
};
|
|
24
|
-
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The payment methods actually offered on this checkout, in the order the
|
|
28
|
+
* picker shows them.
|
|
29
|
+
*
|
|
30
|
+
* Ferjolt Ozuni - Date: 2026-08-07
|
|
31
|
+
*
|
|
32
|
+
* Pulled out of Payments because two places need the same answer and they
|
|
33
|
+
* must not disagree: the picker decides what to draw, and the button decides
|
|
34
|
+
* whether it is asking the buyer to choose ("Make Payment", after picking a
|
|
35
|
+
* method) or simply to pay ("Pay Now", when there is nothing to pick). A
|
|
36
|
+
* second copy of these conditions would eventually drift and produce a
|
|
37
|
+
* button offering a choice that is not on screen.
|
|
38
|
+
*
|
|
39
|
+
* The conditions themselves are unchanged, including their oddities: `cash`
|
|
40
|
+
* rides on the `funds` flag rather than one of its own, and a partner is
|
|
41
|
+
* offered every card gateway regardless of what the label enabled. Both were
|
|
42
|
+
* already true; this is a move, not a rewrite.
|
|
43
|
+
*/
|
|
44
|
+
export const getAvailablePayments = (data?: ActionData, isPartner = false): string[] => {
|
|
45
|
+
if (!data) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const available: string[] = [];
|
|
50
|
+
|
|
51
|
+
if (data.reserve && !isPartner) { available.push('reserve'); }
|
|
52
|
+
if (data.funds && !isPartner) { available.push('funds', 'cash'); }
|
|
53
|
+
|
|
54
|
+
if (data.bkt || isPartner) { available.push('bkt'); }
|
|
55
|
+
if (data.stripe || isPartner) { available.push('stripe'); }
|
|
56
|
+
if (data.mollie || isPartner) { available.push('mollie'); }
|
|
57
|
+
if (data.raiffeisen || isPartner) { available.push('raiffeisen'); }
|
|
58
|
+
if (data.nexi || isPartner) { available.push('nexi'); }
|
|
59
|
+
|
|
60
|
+
return available;
|
|
61
|
+
};
|