@autobusal/common 0.0.24 → 0.0.26

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/Gender.tsx ADDED
@@ -0,0 +1,39 @@
1
+ import { TFunction } from 'i18next';
2
+ import { UseFormRegister } from 'react-hook-form';
3
+
4
+ interface Props {
5
+ name: string
6
+ defaultValue?: number
7
+ t: TFunction<'common'>
8
+ refs: UseFormRegister<any>
9
+ }
10
+
11
+ const Gender = ({ name, defaultValue, t, refs }: Props) => (
12
+ <div className="row">
13
+ <div className="list">
14
+ <label>
15
+ <input
16
+ type="radio"
17
+ value={ 0 }
18
+ defaultChecked={ defaultValue === undefined || defaultValue == 0 }
19
+ { ...refs(name) }
20
+ />
21
+
22
+ { t('data.gender.male') }
23
+ </label>
24
+
25
+ <label>
26
+ <input
27
+ type="radio"
28
+ value={ 1 }
29
+ defaultChecked={ defaultValue == 1 }
30
+ { ...refs(name) }
31
+ />
32
+
33
+ { t('data.gender.female') }
34
+ </label>
35
+ </div>
36
+ </div>
37
+ );
38
+
39
+ export default Gender;
@@ -0,0 +1,69 @@
1
+ import { useState } from 'react';
2
+ import { UseFormRegister } from 'react-hook-form';
3
+ import { TFunction } from 'i18next';
4
+ import { FaCheck } from 'react-icons/fa';
5
+ import { MdEventSeat } from 'react-icons/md';
6
+ import { validate } from '@autobusal/utilities';
7
+ import Unavailable from './Unavailable';
8
+ import Preview from './Preview';
9
+ import { ButtonSeat } from './styles';
10
+ import { OccupiedData } from '@autobusal/providers/types/buses';
11
+ import { PersonData } from '@modules/Providers/types/persons';
12
+
13
+ interface Props {
14
+ name: string
15
+ type: 'from' | 'to'
16
+ defaultValue?: number
17
+ bus: OccupiedData
18
+ picked: number[]
19
+ validation: string
20
+ t: TFunction<'common'>
21
+ refs: UseFormRegister<PersonData | any>
22
+ onUpdate: (name: string, type: ('from' | 'to'), value: number, previous: number) => void
23
+ }
24
+
25
+ const ChooseSeat = ({ name, type, defaultValue, bus, picked, validation, t, refs, onUpdate }: Props): JSX.Element => {
26
+ const [ show, setShow ] = useState<boolean>(false);
27
+ const [ selected, setSelected ] = useState<number>(defaultValue ?? 0);
28
+
29
+ // if we don't have a bus, we just show a notification
30
+ if (! bus.bus) {
31
+ return <Unavailable t={ t } />;
32
+ }
33
+
34
+ const onSelect = (seat: number, occupied: boolean): void => {
35
+ if (!occupied) {
36
+ onUpdate(name, type, seat, selected);
37
+
38
+ setSelected(seat);
39
+
40
+ setShow(false);
41
+ }
42
+ };
43
+
44
+ return (
45
+ <div>
46
+ <ButtonSeat type="button" $selected={ selected > 0 } onClick={ () => setShow(true) }>
47
+ { selected > 0
48
+ ? <><FaCheck /> { t('seats.chosen', { number: selected }) }</>
49
+ : <><MdEventSeat /> { t('seats.choose') }</> }
50
+ </ButtonSeat>
51
+
52
+ { (show && bus.bus !== undefined) && (
53
+ <Preview
54
+ bus={ bus.bus }
55
+ occupied={ bus.occupied }
56
+ picked={ picked }
57
+ selected={ selected }
58
+ t={ t }
59
+ onSelect={ onSelect }
60
+ onClose={ () => setShow(false) }
61
+ />
62
+ ) }
63
+
64
+ <input type="hidden" defaultValue={ selected } { ...refs(name, validate(validation, t)) } />
65
+ </div>
66
+ );
67
+ };
68
+
69
+ export default ChooseSeat;
@@ -0,0 +1,54 @@
1
+ import { TFunction } from 'i18next';
2
+ import { MdEventSeat } from 'react-icons/md';
3
+ import { Modal } from '@autobusal/common';
4
+ import { Seats, SeatsInner, ButtonOccupy } from './styles';
5
+ import { BusData } from '@autobusal/providers/types/buses';
6
+
7
+ interface Props {
8
+ bus: BusData
9
+ occupied: number[]
10
+ picked: number[]
11
+ selected: number
12
+ t: TFunction<'general'>
13
+ onSelect: (seat: number, occupied: boolean) => void
14
+ onClose: () => void
15
+ }
16
+
17
+ const Preview = ({ bus, occupied, picked, selected, t, onSelect, onClose }: Props): JSX.Element => {
18
+ const items = bus.seats.map((item, index) => {
19
+ const isOccupied = occupied.includes(item.no) || picked.includes(item.no);
20
+
21
+ return (
22
+ <ButtonOccupy
23
+ key={ index }
24
+ type="button"
25
+ $top={ item.top }
26
+ $left={ item.left }
27
+ $width={ item.width }
28
+ $height={ item.height }
29
+ $selected={ selected === item.no }
30
+ $occupied={ isOccupied }
31
+ onClick={ () => onSelect(item.no, isOccupied) }
32
+ >
33
+ <MdEventSeat /> { item.no }
34
+ </ButtonOccupy>
35
+ );
36
+ });
37
+
38
+ return (
39
+ <Modal
40
+ width={ 1040 }
41
+ title={ t('seats.title', { bus: bus.name }) }
42
+ content={ (
43
+ <Seats>
44
+ <SeatsInner $image={ bus.image_url }>
45
+ { items }
46
+ </SeatsInner>
47
+ </Seats>
48
+ ) }
49
+ onClose={ onClose }
50
+ />
51
+ );
52
+ };
53
+
54
+ export default Preview;
@@ -0,0 +1,20 @@
1
+ import { TFunction } from 'i18next';
2
+ import { MdEventSeat } from 'react-icons/md';
3
+ import { SeatUnavailable, TitleUnavailable } from './styles';
4
+
5
+ interface Props {
6
+ t: TFunction<'public'>
7
+ }
8
+
9
+ const Unavailable = ({ t }: Props): JSX.Element => (
10
+ <SeatUnavailable>
11
+ <TitleUnavailable>
12
+ <MdEventSeat />
13
+ { t('seats.unavailable.title') }
14
+ </TitleUnavailable>
15
+
16
+ { t('seats.unavailable.content') }
17
+ </SeatUnavailable>
18
+ );
19
+
20
+ export default Unavailable;
@@ -0,0 +1,132 @@
1
+ import styled, { css } from 'styled-components';
2
+
3
+ export const ButtonSeat = styled.button<{ $selected: boolean }>`
4
+ display: flex;
5
+ gap: 5px;
6
+ align-items: center;
7
+ padding: 4px 10px;
8
+ background: ${ props => props.theme.background.neutral };
9
+ border-radius: ${ props => props.theme.borderRadius };
10
+ transition: all 0.3s ease;
11
+
12
+ &:hover {
13
+ background: ${ props => props.theme.primary.contrast };
14
+ background: ${ props => props.theme.primary.normal };
15
+ }
16
+
17
+ ${ props => props.$selected && css`
18
+ color: ${ props => props.theme.font.success };
19
+ background: none;
20
+
21
+ &:hover {
22
+ color: #FFF;
23
+ background: ${ props => props.theme.font.success };
24
+ }
25
+ ` }
26
+ `;
27
+
28
+ export const Seats = styled.div`
29
+ overflow-x: auto;
30
+ `;
31
+
32
+ export const SeatsInner = styled.div<{ $image: (string | undefined) }>`
33
+ position: relative;
34
+ width: 1000px;
35
+ height: 400px;
36
+ background: url('${ props => props.$image }');
37
+ `;
38
+
39
+ export const ButtonOccupy = styled.button<{
40
+ $top: number
41
+ $left: number
42
+ $width: number
43
+ $height: number
44
+ $selected: boolean
45
+ $occupied: boolean
46
+ }>`
47
+ position: absolute;
48
+ top: ${ props => props.$top }px;
49
+ left: ${ props => props.$left }px;
50
+ width: ${ props => props.$width }px;
51
+ height: ${ props => props.$height }px;
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ gap: 2px;
56
+ font-weight: 700;
57
+ font-size: ${ props => props.theme.size.l };
58
+ color: ${ props => props.theme.font.normal };
59
+ background: ${ props => props.theme.foreground.normal };
60
+ border-radius: ${ props => props.theme.borderRadius };
61
+ box-shadow: ${ props => props.theme.boxShadow };
62
+ transition: all 0.3s ease;
63
+
64
+ ${ props => props.$selected && css`
65
+ color: ${ props => props.theme.primary.contrast };
66
+ background: ${ props => props.theme.primary.normal };
67
+ ` }
68
+
69
+ ${ props => props.$occupied && css`
70
+ color: #FFFFFF;
71
+ background: ${ props => props.theme.font.error };
72
+ ` }
73
+
74
+ &:hover {
75
+ opacity: .8;
76
+ }
77
+ `;
78
+
79
+ export const SeatUnavailable = styled.div`
80
+ font-size: ${ props => props.theme.size.xs };
81
+ font-weight: 400;
82
+ `;
83
+
84
+ export const TitleUnavailable = styled.div`
85
+ display: flex;
86
+ gap: 6px;
87
+ align-items: center;
88
+ font-weight: 700;
89
+ font-size: ${ props => props.theme.size.s };
90
+ `;
91
+
92
+ // // @todo: finish adding a seat
93
+ // // .choose-seats {
94
+ // // .bus-plan {
95
+ // // .bus-seat {
96
+ // // .remove {
97
+ // // position: absolute;
98
+ // // top: 0;
99
+ // // right: 0;
100
+ // // z-index: 1;
101
+ // // width: 20px;
102
+ // // height: 20px;
103
+ // // background-color: $red;
104
+ // // border-radius: $border-radius - 3;
105
+
106
+ // // svg {
107
+ // // margin: 1px auto 0;
108
+ // // font-size: $size-info;
109
+ // // color: $white;
110
+ // // }
111
+ // // }
112
+ // // }
113
+
114
+ // // .add-seat {
115
+ // // display: block;
116
+ // // position: absolute;
117
+ // // z-index: 5;
118
+ // // bottom: -58px;
119
+ // // width: 50px;
120
+ // // height: 38px;
121
+ // // text-align: center;
122
+ // // line-height: 32px;
123
+ // // color: $blue;
124
+ // // border: 3px solid $blue;
125
+ // // border-radius: 100px;
126
+
127
+ // // svg {
128
+ // // margin: 0;
129
+ // // }
130
+ // // }
131
+ // // }
132
+ // // }
package/index.ts CHANGED
@@ -3,7 +3,9 @@ import BackTo from './BackTo';
3
3
  import Calendar from './Calendar/Calendar';
4
4
  import CookieNotification from './CookieNotification/CookieNotification';
5
5
  import ChangeLanguage from './ChangeLanguage/ChangeLanguage';
6
+ import ChooseSeat from './Seats/ChooseSeat';
6
7
  import { Button } from './Button/Button';
8
+ import Gender from './Gender';
7
9
  import { General, Inline, Paragraph } from './Loading/Loading';
8
10
  import Modal from './Modal/Modal';
9
11
  import Meta from './Meta';
@@ -20,6 +22,8 @@ export {
20
22
  Calendar,
21
23
  CookieNotification,
22
24
  ChangeLanguage,
25
+ ChooseSeat,
26
+ Gender,
23
27
  General,
24
28
  Inline,
25
29
  Meta,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/common",
3
- "version": "0.0.24",
3
+ "version": "0.0.26",
4
4
  "type": "module",
5
5
  "main": "index.ts"
6
6
  }