@autobusal/routes-order 1.0.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.
Files changed (50) hide show
  1. package/Found/Booking/Booking.tsx +61 -0
  2. package/Found/Booking/styles.ts +50 -0
  3. package/Found/Dates/Dates.tsx +82 -0
  4. package/Found/Dates/Loading.tsx +14 -0
  5. package/Found/Dates/styles.ts +50 -0
  6. package/Found/Found.tsx +31 -0
  7. package/Found/Header/Header.tsx +21 -0
  8. package/Found/Header/styles.ts +40 -0
  9. package/Found/Orders/Orders.tsx +40 -0
  10. package/Found/Orders/styles.ts +12 -0
  11. package/Found/Route/Route.tsx +112 -0
  12. package/Found/Route/styles.ts +187 -0
  13. package/RoutesOrder.tsx +130 -0
  14. package/Step1/Step1.tsx +63 -0
  15. package/Step1/prepare.ts +38 -0
  16. package/Step2.tsx +55 -0
  17. package/Step3.tsx +56 -0
  18. package/Step4/Loading.tsx +26 -0
  19. package/Step4/Passenger/Passenger.tsx +173 -0
  20. package/Step4/Passenger/styles.ts +10 -0
  21. package/Step4/Passengers/Display.tsx +50 -0
  22. package/Step4/Passengers/Passengers.tsx +96 -0
  23. package/Step4/Passengers/styles.ts +7 -0
  24. package/Step4/Step4.tsx +96 -0
  25. package/Step4/checkAge.ts +48 -0
  26. package/Step5/Billing/Billing.tsx +161 -0
  27. package/Step5/Billing/Loading.tsx +22 -0
  28. package/Step5/Billing/styles.ts +13 -0
  29. package/Step5/Coupons/Coupons.tsx +71 -0
  30. package/Step5/Coupons/styles.ts +20 -0
  31. package/Step5/Payments/Payments.tsx +82 -0
  32. package/Step5/Payments/styles.ts +42 -0
  33. package/Step5/Step5.tsx +131 -0
  34. package/Step5/Summary/About/About.tsx +48 -0
  35. package/Step5/Summary/About/styles.ts +49 -0
  36. package/Step5/Summary/Amount/Amount.tsx +24 -0
  37. package/Step5/Summary/Amount/styles.ts +29 -0
  38. package/Step5/Summary/Summary.tsx +44 -0
  39. package/Step5/Summary/Tickets/Preview.tsx +41 -0
  40. package/Step5/Summary/Tickets/Tickets.tsx +34 -0
  41. package/Step5/Summary/Tickets/styles.ts +36 -0
  42. package/Step5/Summary/styles.ts +11 -0
  43. package/Step5/utilities.ts +24 -0
  44. package/Steps/Steps.tsx +28 -0
  45. package/Steps/styles.ts +47 -0
  46. package/index.ts +3 -0
  47. package/package.json +6 -0
  48. package/services.ts +149 -0
  49. package/styles.ts +24 -0
  50. package/types.ts +32 -0
@@ -0,0 +1,173 @@
1
+ import { TFunction } from 'i18next';
2
+ import { FieldErrors, FieldValues, UseFormRegister } from 'react-hook-form';
3
+ import { Calendar, Gender, ChooseSeat } from '@autobusal/common';
4
+ import { Validate, Display } from '@autobusal/utilities';
5
+ import { Container, Title } from './styles';
6
+ import { PersonData } from '@autobusal/providers/types/persons';
7
+ import { OccupiedData } from '@autobusal/providers/types/buses';
8
+
9
+ interface Props {
10
+ type: 'adult' | 'child' | 'baby'
11
+ number: number
12
+ values?: PersonData
13
+ withReturn: boolean
14
+ busFrom: OccupiedData
15
+ busTo: OccupiedData
16
+ pickedFrom: number[]
17
+ pickedTo: number[]
18
+ t: TFunction<'public'>
19
+ errors: FieldErrors<FieldValues>
20
+ refs: UseFormRegister<PersonData>
21
+ onSeatSelect: (name: string, type: ('from' | 'to'), seat: number, previous: number) => void
22
+ onUpdate: (name: string, value: (string | number)) => void
23
+ }
24
+
25
+ const Passenger = ({ type, number, values, withReturn, busFrom, busTo, pickedFrom, pickedTo, t, errors, refs, onSeatSelect, onUpdate }: Props): JSX.Element => {
26
+ const name = `${ type }${ number }`;
27
+
28
+ const names = {
29
+ firstName: `${ name }_fn`,
30
+ lastName: `${ name }_ln`,
31
+ dob: `${ name }_dob`,
32
+ sex: `${ name }_sex`,
33
+ passport: `${ name }_pass`,
34
+ phone: `${ name }_phone`,
35
+ seatDeparture: `${ name }_sd`,
36
+ seatReturn: `${ name }_sr`
37
+ };
38
+
39
+ return (
40
+ <Container className="box">
41
+ <Title>
42
+ { `${ t('routes_order.step4.ticket', { no: number }) } (${ t(`data.persons.${ type }.singular`) })` }
43
+ </Title>
44
+
45
+ <div className="column">
46
+ <div className="row">
47
+ { t('routes_order.step4.first_name') }
48
+
49
+ <input
50
+ type="text"
51
+ defaultValue={ values !== undefined ? values[names.firstName] : '' }
52
+ { ...refs(names.firstName, Validate('required|min_length:2|max_length:100', t)) }
53
+ />
54
+
55
+ { Display(errors[names.firstName]) }
56
+ </div>
57
+
58
+ <div className="row">
59
+ { t('routes_order.step4.last_name') }
60
+
61
+ <input
62
+ type="text"
63
+ defaultValue={ values !== undefined ? values[names.lastName] : '' }
64
+ { ...refs(names.lastName, Validate('required|min_length:2|max_length:100', t)) }
65
+ />
66
+
67
+ { Display(errors[names.lastName]) }
68
+ </div>
69
+ </div>
70
+
71
+ <div className="column">
72
+ <div className="row">
73
+ { t('routes_order.step4.dob') }
74
+
75
+ <Calendar
76
+ type="dob"
77
+ name={ names.dob }
78
+ defaultValue={ values !== undefined ? String(values[names.dob]) : undefined }
79
+ t={ t }
80
+ validation="required"
81
+ refs={ refs }
82
+ onUpdate={ onUpdate }
83
+ />
84
+
85
+ { Display(errors[names.dob]) }
86
+ </div>
87
+
88
+ <div className="row">
89
+ { t('routes_order.step4.gender') }
90
+
91
+ <Gender
92
+ name={ names.sex }
93
+ defaultValue={ values !== undefined ? Number(values[names.sex]) : undefined }
94
+ t={ t }
95
+ refs={ refs }
96
+ />
97
+
98
+ { Display(errors[names.sex]) }
99
+ </div>
100
+ </div>
101
+
102
+ <div className="column">
103
+ <div className="row">
104
+ { t('routes_order.step4.passport') }
105
+
106
+ <input
107
+ type="text"
108
+ defaultValue={ values !== undefined ? values[names.passport] : '' }
109
+ { ...refs(names.passport, Validate('required|min_length:2|max_length:50', t)) }
110
+ />
111
+
112
+ { Display(errors[names.passport]) }
113
+ </div>
114
+
115
+ <div className="row">
116
+ { t('routes_order.step4.phone') }
117
+
118
+ <input
119
+ type="text"
120
+ defaultValue={ values !== undefined ? values[names.phone] : '' }
121
+ { ...refs(names.phone) }
122
+ />
123
+
124
+ { Display(errors[names.phone]) }
125
+ </div>
126
+ </div>
127
+
128
+ { type !== 'baby' && (
129
+ <div className="column">
130
+ <div className="row">
131
+ { t('seats.departure') }
132
+
133
+ <ChooseSeat
134
+ name={ names.seatDeparture }
135
+ type="from"
136
+ defaultValue={ values !== undefined ? Number(values[names.seatDeparture]) : undefined }
137
+ bus={ busFrom }
138
+ picked={ pickedFrom }
139
+ validation="required|min:1"
140
+ t={ t }
141
+ refs={ refs }
142
+ onUpdate={ onSeatSelect }
143
+ />
144
+
145
+ { Display(errors[names.seatDeparture]) }
146
+ </div>
147
+
148
+ { withReturn && (
149
+ <div className="row">
150
+ { t('seats.return') }
151
+
152
+ <ChooseSeat
153
+ name={ names.seatReturn }
154
+ type="to"
155
+ defaultValue={ values !== undefined ? Number(values[names.seatReturn]) : undefined }
156
+ bus={ busTo }
157
+ picked={ pickedTo }
158
+ validation="required|min:1"
159
+ t={ t }
160
+ refs={ refs }
161
+ onUpdate={ onSeatSelect }
162
+ />
163
+
164
+ { Display(errors[names.seatReturn]) }
165
+ </div>
166
+ ) }
167
+ </div>
168
+ ) }
169
+ </Container>
170
+ );
171
+ };
172
+
173
+ export default Passenger;
@@ -0,0 +1,10 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ margin-bottom: 5px;
5
+ `;
6
+
7
+ export const Title = styled.h3`
8
+ padding-bottom: 16px;
9
+ border-bottom: 1px solid ${ props => props.theme.background.neutral };
10
+ `;
@@ -0,0 +1,50 @@
1
+ import { TFunction } from 'i18next';
2
+ import { FieldErrors, FieldValues, UseFormRegister } from 'react-hook-form';
3
+ import Passenger from '../Passenger/Passenger';
4
+ import { PersonData } from '@autobusal/providers/types/persons';
5
+ import { OccupiedData } from '@autobusal/providers/types/buses';
6
+
7
+ interface Props {
8
+ type: 'adult' | 'child' | 'baby'
9
+ amount: number
10
+ withReturn: boolean
11
+ values?: PersonData
12
+ busFrom: OccupiedData
13
+ busTo: OccupiedData
14
+ pickedFrom: number[]
15
+ pickedTo: number[]
16
+ t: TFunction<'public'>
17
+ errors: FieldErrors<FieldValues>
18
+ refs: UseFormRegister<PersonData>
19
+ onSeatSelect: (name: string, type: ('from' | 'to'), seat: number, previous: number) => void
20
+ onUpdate: (name: string, value: (string | number)) => void
21
+ }
22
+
23
+ const Display = ({ type, amount, withReturn, values, busFrom, busTo, pickedFrom, pickedTo, t, errors, refs, onSeatSelect, onUpdate }: Props): JSX.Element[] => {
24
+ const passengers: JSX.Element[] = [];
25
+
26
+ for (let i = 1; i <= amount; i++) {
27
+ passengers.push(
28
+ <Passenger
29
+ key={ i }
30
+ type={ type }
31
+ number={ i }
32
+ withReturn={ withReturn }
33
+ values={ values }
34
+ busFrom={ busFrom }
35
+ busTo={ busTo }
36
+ pickedFrom={ pickedFrom }
37
+ pickedTo={ pickedTo }
38
+ t={ t }
39
+ errors={ errors }
40
+ refs={ refs }
41
+ onSeatSelect={ onSeatSelect }
42
+ onUpdate={ onUpdate }
43
+ />
44
+ );
45
+ }
46
+
47
+ return passengers;
48
+ };
49
+
50
+ export default Display;
@@ -0,0 +1,96 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { FieldErrors, FieldValues, UseFormRegister } from 'react-hook-form';
4
+ import Display from './Display';
5
+ import { Container } from './styles';
6
+ import { RoutesSearchForm } from '@autobusal/routes-search/types';
7
+ import { PersonData } from '@autobusal/providers/types/persons';
8
+ import { OccupiedData } from '@autobusal/providers/types/buses';
9
+
10
+ interface Props {
11
+ values?: PersonData
12
+ step1: RoutesSearchForm
13
+ busFrom: OccupiedData
14
+ busTo: OccupiedData
15
+ t: TFunction<'public'>
16
+ errors: FieldErrors<FieldValues>
17
+ refs: UseFormRegister<PersonData>
18
+ onUpdate: (name: string, value: (string | number)) => void
19
+ }
20
+
21
+ const Passengers = ({ values, step1, busFrom, busTo, t, errors, refs, onUpdate }: Props): JSX.Element => {
22
+ const [ pickedFrom, setPickedFrom ] = useState<number[]>([]);
23
+ const [ pickedTo, setPickedTo ] = useState<number[]>([]);
24
+
25
+ const onSeatSelect = (name: string, type: ('from' | 'to'), seat: number, previous: number): void => {
26
+ let newPicked = type === 'from' ? [...pickedFrom] : [...pickedTo];
27
+
28
+ if (previous > 0) {
29
+ newPicked = pickedFrom.filter(item => item !== previous);
30
+ }
31
+
32
+ newPicked.push(seat);
33
+
34
+ if (type === 'from') {
35
+ setPickedFrom(newPicked);
36
+ } else {
37
+ setPickedTo(newPicked);
38
+ }
39
+
40
+ onUpdate(name, seat);
41
+ };
42
+
43
+ return (
44
+ <Container>
45
+ <Display
46
+ type="adult"
47
+ amount={ step1.adults }
48
+ withReturn={ step1.type === 'return' }
49
+ values={ values }
50
+ busFrom={ busFrom }
51
+ busTo={ busTo }
52
+ pickedFrom={ pickedFrom }
53
+ pickedTo={ pickedTo }
54
+ t={ t }
55
+ errors={ errors }
56
+ refs={ refs }
57
+ onSeatSelect={ onSeatSelect }
58
+ onUpdate={ onUpdate }
59
+ />
60
+
61
+ <Display
62
+ type="child"
63
+ amount={ step1.children }
64
+ withReturn={ step1.type === 'return' }
65
+ values={ values }
66
+ busFrom={ busFrom }
67
+ busTo={ busTo }
68
+ pickedFrom={ pickedFrom }
69
+ pickedTo={ pickedTo }
70
+ t={ t }
71
+ errors={ errors }
72
+ refs={ refs }
73
+ onSeatSelect={ onSeatSelect }
74
+ onUpdate={ onUpdate }
75
+ />
76
+
77
+ <Display
78
+ type="baby"
79
+ amount={ step1.babies }
80
+ withReturn={ step1.type === 'return' }
81
+ values={ values }
82
+ busFrom={ busFrom }
83
+ busTo={ busTo }
84
+ pickedFrom={ pickedFrom }
85
+ pickedTo={ pickedTo }
86
+ t={ t }
87
+ errors={ errors }
88
+ refs={ refs }
89
+ onSeatSelect={ onSeatSelect }
90
+ onUpdate={ onUpdate }
91
+ />
92
+ </Container>
93
+ );
94
+ };
95
+
96
+ export default Passengers;
@@ -0,0 +1,7 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 30px;
7
+ `;
@@ -0,0 +1,96 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useForm } from 'react-hook-form';
3
+ import { HiUsers } from 'react-icons/hi';
4
+ import { RiShoppingCartLine } from 'react-icons/ri';
5
+ import { AiOutlineCaretLeft } from 'react-icons/ai';
6
+ import { useBusOccupied } from '@autobusal/hooks';
7
+ import { Button } from '@autobusal/common';
8
+ import Steps from '../Steps/Steps';
9
+ import Loading from './Loading';
10
+ import Passengers from './Passengers/Passengers';
11
+ import checkAge from './checkAge';
12
+ import { Title, Actions } from '../styles';
13
+ import { RoutesSearchForm } from '@autobusal/routes-search/types';
14
+ import { PersonData } from '@autobusal/providers/types/persons';
15
+ import { FoundData } from '@autobusal/providers/types/routes';
16
+
17
+ interface Props {
18
+ values?: PersonData
19
+ step1: RoutesSearchForm
20
+ step2: FoundData
21
+ step3?: FoundData
22
+ isPartner?: boolean
23
+ t: TFunction<'common'>
24
+ onSave: (data: PersonData) => void
25
+ onBack: (step: number) => void
26
+ }
27
+
28
+ const Step4 = ({ values, step1, step2, step3, isPartner, t, onSave, onBack }: Props): JSX.Element => {
29
+ const { register, handleSubmit, formState: { errors }, setValue, setError } = useForm<PersonData>();
30
+
31
+ const busFrom = useBusOccupied(step1.departure, step2.id);
32
+ const busTo = useBusOccupied(step1._return, step3?.id);
33
+
34
+ if (busFrom === undefined || busTo === undefined) {
35
+ return <Loading t={ t } />;
36
+ }
37
+
38
+ const onSubmit = (data: PersonData): void => {
39
+ // if all the ages are ok, we move forward
40
+ if (checkAge(step1, data, t)) {
41
+ onSave(data);
42
+ }
43
+ };
44
+
45
+ const onUpdate = (name: string, value: (string | number)): void => {
46
+ setValue(name, value);
47
+ setError(name, {});
48
+ };
49
+
50
+ const onSendForm = (): void => {
51
+ handleSubmit(onSubmit)();
52
+ };
53
+
54
+ return (
55
+ <>
56
+ <Title>
57
+ <HiUsers />
58
+ { t('routes_order.step4.title') }
59
+ </Title>
60
+
61
+ <Steps value={ 4 } />
62
+
63
+ <Passengers
64
+ values={ values }
65
+ step1={ step1 }
66
+ busFrom={ busFrom }
67
+ busTo={ busTo }
68
+ t={ t }
69
+ errors={ errors }
70
+ refs={ register }
71
+ onUpdate={ onUpdate }
72
+ />
73
+
74
+ <Actions>
75
+ { isPartner === undefined && (
76
+ <Button
77
+ type="button"
78
+ subtype="secondary"
79
+ text={ <><AiOutlineCaretLeft /> { t('routes_order.step4.back') }</> }
80
+ noMargin
81
+ onClick={ () => onBack(step1._return ? 3 : 2) }
82
+ />
83
+ ) }
84
+
85
+ <Button
86
+ type="button"
87
+ text={ <><RiShoppingCartLine /> { t('routes_order.step4.next') }</> }
88
+ noMargin
89
+ onClick={ onSendForm }
90
+ />
91
+ </Actions>
92
+ </>
93
+ );
94
+ };
95
+
96
+ export default Step4;
@@ -0,0 +1,48 @@
1
+ import { TFunction } from 'i18next';
2
+ import { error, differenceYears, createDate } from '@autobusal/utilities';
3
+ import { PersonData } from '@autobusal/providers/types/persons';
4
+ import { RoutesSearchForm } from '@autobusal/routes-search/types';
5
+
6
+ const checkAge = (step1: RoutesSearchForm, data: PersonData, t: TFunction<'general'>): boolean => {
7
+ // check adults ages
8
+ for (let i = 1; i <= step1.adults; i++) {
9
+ const age = getAge(data[`adult${ i }_dob`]);
10
+
11
+ if (age < 18) {
12
+ error(t('routes_order.step4.errors.age'));
13
+ return false;
14
+ }
15
+ }
16
+
17
+ // check children ages
18
+ for (let i = 1; i <= step1.children; i++) {
19
+ const age = getAge(data[`child${ i }_dob`])
20
+
21
+ if (age < 3 || age > 17) {
22
+ error(t('routes_order.step4.errors.age'));
23
+ return false;
24
+ }
25
+ }
26
+
27
+ // check babies ages
28
+ for (let i = 1; i <= step1.babies; i++) {
29
+ const age = getAge(data[`baby${ i }_dob`]);
30
+
31
+ if (age > 2) {
32
+ error(t('routes_order.step4.errors.age'));
33
+ return false;
34
+ }
35
+ }
36
+
37
+ return true;
38
+ };
39
+
40
+ const getAge = (date: string | number): number => {
41
+ const age = differenceYears(
42
+ createDate(String(date))
43
+ );
44
+
45
+ return age;
46
+ };
47
+
48
+ export default checkAge;
@@ -0,0 +1,161 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { UseFormRegister, FieldErrors } from 'react-hook-form';
4
+ import { RiPencilFill } from 'react-icons/ri';
5
+ import { AiOutlineInfoCircle } from 'react-icons/ai';
6
+ import { useCountries } from '@autobusal/hooks';
7
+ import { Validate, Display } from '@autobusal/utilities';
8
+ import Loading from './Loading';
9
+ import { SubTitle } from '../../styles';
10
+ import { Container, NoticeEmail } from './styles';
11
+ import { BillingData } from '@autobusal/providers/types/persons';
12
+
13
+ interface Props {
14
+ t: TFunction<'common'>
15
+ errors: FieldErrors
16
+ refs: UseFormRegister<BillingData>
17
+ }
18
+
19
+ const Billing = ({ errors, t, refs }: Props): JSX.Element => {
20
+ const [ company, setCompany ] = useState<boolean>(false);
21
+
22
+ const countries = useCountries('all');
23
+
24
+ if (countries.isLoading) {
25
+ return <Loading t={ t } />;
26
+ }
27
+
28
+ const items = countries.data?.map(item => (
29
+ <option key={ item.id } value={ item.id }>{ item.name }</option>
30
+ ));
31
+
32
+ const onAddCompany = (event: React.MouseEvent<HTMLInputElement>): void => {
33
+ setCompany((event.target as HTMLInputElement).checked);
34
+ }
35
+
36
+ return (
37
+ <Container className="box">
38
+ <SubTitle>
39
+ <RiPencilFill />
40
+ { t('routes_order.step5.billing.title') }
41
+ </SubTitle>
42
+
43
+ <div className="column">
44
+ <div className="row">
45
+ { t('routes_order.step5.billing.first_name') }
46
+
47
+ <input type="text" { ...refs('bill_fn', Validate('required|min_length:2|max_length:100', t)) } />
48
+
49
+ { Display(errors.bill_fn) }
50
+ </div>
51
+
52
+ <div className="row">
53
+ { t('routes_order.step5.billing.last_name') }
54
+
55
+ <input type="text" { ...refs('bill_ln', Validate('required|min_length:2|max_length:100', t)) } />
56
+
57
+ { Display(errors.bill_ln) }
58
+ </div>
59
+ </div>
60
+
61
+ <div className="column">
62
+ <div className="row">
63
+ { t('routes_order.step5.billing.email') }
64
+
65
+ <input type="email" { ...refs('email', Validate('required|email|max_length:255', t)) } />
66
+
67
+ { Display(errors.email) }
68
+
69
+ <NoticeEmail>
70
+ <AiOutlineInfoCircle /> { t('routes_order.step5.billing.email_info') }
71
+ </NoticeEmail>
72
+ </div>
73
+
74
+ <div className="row">
75
+ { t('routes_order.step5.billing.phone') }
76
+
77
+ <input type="text" { ...refs('bill_phone', Validate('required|min_length:10|max_length:20', t)) } />
78
+
79
+ { Display(errors.bill_phone) }
80
+ </div>
81
+ </div>
82
+
83
+ <div className="row">
84
+ { t('routes_order.step5.billing.address') }
85
+
86
+ <textarea { ...refs('bill_address', Validate('required|min_length:2', t)) }></textarea>
87
+
88
+ { Display(errors.bill_address) }
89
+ </div>
90
+
91
+ <div className="column">
92
+ <div className="row">
93
+ { t('routes_order.step5.billing.city') }
94
+
95
+ <input type="text" { ...refs('bill_city', Validate('required|min_length:2|max_length:100', t)) } />
96
+
97
+ { Display(errors.bill_city) }
98
+ </div>
99
+
100
+ <div className="row">
101
+ { t('routes_order.step5.billing.country') }
102
+
103
+ <select { ...refs('bill_country', Validate('required|min:1', t)) }>
104
+ <option value={ 0 }>{ t('routes_order.step5.billing.country_choose') }</option>
105
+ { items }
106
+ </select>
107
+
108
+ { Display(errors.bill_country) }
109
+ </div>
110
+ </div>
111
+
112
+ <div className="row">
113
+ <label>
114
+ <input type="checkbox" defaultChecked={ false } onClick={ (event: React.MouseEvent<HTMLInputElement>) => onAddCompany(event) } /> { t('routes_order.step5.billing.ask_company') }
115
+ </label>
116
+ </div>
117
+
118
+ { company && (
119
+ <div className="column">
120
+ <div className="row">
121
+ { t('routes_order.step5.billing.company') }
122
+
123
+ <input type="text" { ...refs('bill_company') } />
124
+
125
+ { Display(errors.bill_company) }
126
+ </div>
127
+
128
+ <div className="row">
129
+ { t('routes_order.step5.billing.nipt') }
130
+
131
+ <input type="text" { ...refs('bill_nipt') } />
132
+
133
+ { Display(errors.bill_nipt) }
134
+ </div>
135
+ </div>
136
+ ) }
137
+
138
+ <div className="row">
139
+ { t('routes_order.step5.billing.comments') }
140
+
141
+ <textarea { ...refs('comments') }></textarea>
142
+ </div>
143
+
144
+ <div className="row row-nomargin">
145
+ <label className="single">
146
+ <input type="checkbox" value="1" { ...refs('terms', Validate('required', t)) } />&nbsp;
147
+
148
+ <span dangerouslySetInnerHTML={{
149
+ __html: t('routes_order.step5.billing.terms', {
150
+ terms: `<a href="/page/terms" target="_blank">${ t('routes_order.step5.billing.terms_name') }</a>`
151
+ })
152
+ }} />
153
+ </label>
154
+
155
+ { Display(errors.terms) }
156
+ </div>
157
+ </Container>
158
+ );
159
+ };
160
+
161
+ export default Billing;
@@ -0,0 +1,22 @@
1
+ import { TFunction } from 'i18next';
2
+ import { RiPencilFill } from 'react-icons/ri';
3
+ import { Inline } from '@autobusal/common';
4
+ import { SubTitle } from '../../styles';
5
+ import { Container } from './styles';
6
+
7
+ interface Props {
8
+ t: TFunction<'common'>
9
+ }
10
+
11
+ const Loading = ({ t }: Props): JSX.Element => (
12
+ <Container className="box">
13
+ <SubTitle>
14
+ <RiPencilFill />
15
+ { t('routes_order.step5.billing.title') }
16
+ </SubTitle>
17
+
18
+ <Inline text={ t('routes_order.step5.billing.loading') } />
19
+ </Container>
20
+ );
21
+
22
+ export default Loading;
@@ -0,0 +1,13 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ margin-top: 25px;
5
+ `;
6
+
7
+ export const NoticeEmail = styled.div`
8
+ display: flex;
9
+ align-items: center;
10
+ gap: 4px;
11
+ font-size: ${ props => props.theme.size.xs };
12
+ color: ${ props => props.theme.font.info };
13
+ `;