@autobusal/common 0.0.14 → 0.0.16

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/BackTo.tsx ADDED
@@ -0,0 +1,35 @@
1
+ import { TFunction } from 'i18next';
2
+ import { Link } from 'react-router-dom';
3
+ import styled from 'styled-components';
4
+ import { BiChevronLeftCircle } from 'react-icons/bi';
5
+
6
+ interface Props {
7
+ to: string
8
+ t: TFunction<'general'>
9
+ }
10
+
11
+ const LinkStyled = styled(Link)`
12
+ display: inline-flex;
13
+ gap: 5px;
14
+ align-items: center;
15
+ padding: 4px 12px;
16
+ font-size: calc(${ props => props.theme.size.info } - 1px);
17
+ text-transform: uppercase;
18
+ background: ${ props => props.theme.neutral };
19
+ border-radius: ${ props => props.theme.borderRadius };
20
+ transition: all 0.3s ease;
21
+
22
+ &:hover {
23
+ text-decoration: none;
24
+ background: ${ props => props.theme.primaryTransparent };
25
+ }
26
+ `;
27
+
28
+ const BackTo = ({ to, t }: Props): JSX.Element => (
29
+ <LinkStyled to={ to }>
30
+ <BiChevronLeftCircle />
31
+ { t('general:back') }
32
+ </LinkStyled>
33
+ );
34
+
35
+ export default BackTo;
@@ -0,0 +1,27 @@
1
+ import { TFunction } from 'i18next';
2
+ import Modal from '../Modal/Modal';
3
+ import { GetPolicy } from './services';
4
+
5
+ interface Props {
6
+ id: number
7
+ t: TFunction<'common'>
8
+ onClose: () => void
9
+ }
10
+
11
+ const Policy = ({ id, t, onClose }: Props): JSX.Element => {
12
+ const { data, isFetching } = GetPolicy(id);
13
+
14
+ return (
15
+ <Modal
16
+ loading={ isFetching }
17
+ width={ 750 }
18
+ title={ t('policy.title') }
19
+ content={
20
+ <div dangerouslySetInnerHTML={{ __html: data?.policies ?? '' }} />
21
+ }
22
+ onClose={ onClose }
23
+ />
24
+ );
25
+ };
26
+
27
+ export default Policy;
@@ -0,0 +1,21 @@
1
+ import { useQuery, UseQueryResult } from '@tanstack/react-query';
2
+ import { apiClient } from '@autobusal/providers';
3
+ import { PolicyData } from '@autobusal/providers/types/routes';
4
+
5
+ export const GetPolicy = (id: number): UseQueryResult<PolicyData> => (
6
+ useQuery({
7
+ queryKey: ['route-policy', { id }],
8
+ queryFn: async () => (
9
+ await apiClient
10
+ .get('/api/routes/policy', {
11
+ params: {
12
+ id
13
+ }
14
+ })
15
+ .then(response => (
16
+ response.data
17
+ ))
18
+ .catch(() => {})
19
+ )
20
+ })
21
+ );
@@ -0,0 +1,15 @@
1
+ import { Container, Image, Name } from './styles';
2
+ import { FeatureData } from '@autobusal/providers/types/routes';
3
+
4
+ interface Props {
5
+ item: FeatureData
6
+ }
7
+
8
+ const RouteFeature = ({ item }: Props): JSX.Element => (
9
+ <Container>
10
+ <Image src={ item.image_url } title={ item.name } />
11
+ <Name>{ item.name }</Name>
12
+ </Container>
13
+ );
14
+
15
+ export default RouteFeature;
@@ -0,0 +1,19 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ display: flex;
5
+ align-items: center;
6
+ gap: 5px;
7
+ padding: 3px 6px;
8
+ border: 1px solid ${ props => props.theme.primary.normal };
9
+ border-radius: 100px;
10
+ `;
11
+
12
+ export const Image = styled.img`
13
+ display: block;
14
+ width: 15px;
15
+ `;
16
+
17
+ export const Name = styled.span`
18
+ font-size: ${ props => props.theme.size.xs };
19
+ `;
@@ -0,0 +1,30 @@
1
+ import { TFunction } from 'i18next';
2
+ import { HiOutlineMinusCircle } from 'react-icons/hi';
3
+ import { Information, Title } from './styles';
4
+ import { LocationData } from '@autobusal/providers/types/locations';
5
+
6
+ interface Props {
7
+ countries: LocationData[]
8
+ t: TFunction<'public'>
9
+ }
10
+
11
+ const Douane = ({ countries, t }: Props): JSX.Element => {
12
+ const items = countries.filter(item => {
13
+ return item.city.douane == 1;
14
+ }).map(item => (
15
+ item.city.name
16
+ ));
17
+
18
+ return (
19
+ <Information>
20
+ <Title>
21
+ <HiOutlineMinusCircle />
22
+ { t('route_item.douane') }:
23
+ </Title>
24
+
25
+ { items.join(', ') }
26
+ </Information>
27
+ );
28
+ };
29
+
30
+ export default Douane;
@@ -0,0 +1,21 @@
1
+ import RouteFeature from '../../RouteFeature/RouteFeature';
2
+ import { ContainerFeatures } from './styles';
3
+ import { FeatureData } from '@autobusal/providers/types/routes';
4
+
5
+ interface Props {
6
+ items: FeatureData[]
7
+ }
8
+
9
+ const Features = ({ items }: Props): JSX.Element => {
10
+ const images = items.map(item => (
11
+ <RouteFeature key={ item.id } item={ item } />
12
+ ));
13
+
14
+ return (
15
+ <ContainerFeatures>
16
+ { images }
17
+ </ContainerFeatures>
18
+ );
19
+ };
20
+
21
+ export default Features;
@@ -0,0 +1,33 @@
1
+ import { TFunction } from 'i18next';
2
+ import ReadPolicy from './ReadPolicy';
3
+ import Schedule from './Schedule';
4
+ import Transiting from './Transiting';
5
+ import Douane from './Douane';
6
+ import Features from './Features';
7
+ import { Container, Details, Policy } from './styles';
8
+ import { RouteData } from '@autobusal/providers/types/routes';
9
+
10
+ interface Props {
11
+ route: RouteData
12
+ t: TFunction<'public'>
13
+ }
14
+
15
+ const More = ({ route, t }: Props): JSX.Element => (
16
+ <Container>
17
+ <Details>
18
+ <Schedule available={ route.available } t={ t } />
19
+
20
+ { route.transiting.length > 0 && <Transiting countries={ route.transiting } t={ t } /> }
21
+
22
+ { route.locations.length > 0 && <Douane countries={ route.locations } t={ t } /> }
23
+
24
+ { route.trip.features_data.length > 0 && <Features items={ route.trip.features_data } /> }
25
+ </Details>
26
+
27
+ <Policy>
28
+ <ReadPolicy id={ route.id } t={ t } />
29
+ </Policy>
30
+ </Container>
31
+ );
32
+
33
+ export default More;
@@ -0,0 +1,27 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { IoDocumentText } from 'react-icons/io5';
4
+ import Policy from '../../Policy/Policy';
5
+ import { ButtonPolicy } from './styles';
6
+
7
+ interface Props {
8
+ id: number
9
+ t: TFunction<'public'>
10
+ }
11
+
12
+ const ReadPolicy = ({ id, t }: Props): JSX.Element => {
13
+ const [ view, setView ] = useState<boolean>(false);
14
+
15
+ return (
16
+ <>
17
+ <ButtonPolicy type="button" onClick={ () => setView(!view) }>
18
+ <IoDocumentText />
19
+ { t('route_item.policy') }
20
+ </ButtonPolicy>
21
+
22
+ { view && <Policy id={ id } t={ t } onClose={ () => setView(false) } /> }
23
+ </>
24
+ );
25
+ };
26
+
27
+ export default ReadPolicy;
@@ -0,0 +1,22 @@
1
+ import { TFunction } from 'i18next';
2
+ import { HiOutlineCalendar } from 'react-icons/hi';
3
+ import { Information, Title } from './styles';
4
+ import { AvailableData } from '@autobusal/providers/types/routes';
5
+
6
+ interface Props {
7
+ available: AvailableData
8
+ t: TFunction<'public'>
9
+ }
10
+
11
+ const Schedule = ({ available, t }: Props): JSX.Element => (
12
+ <Information>
13
+ <Title>
14
+ <HiOutlineCalendar />
15
+ { t('route_item.operating') }:
16
+ </Title>
17
+
18
+ { available.schedule_display }
19
+ </Information>
20
+ );
21
+
22
+ export default Schedule;
@@ -0,0 +1,28 @@
1
+ import { TFunction } from 'i18next';
2
+ import { RiMapPin2Line } from 'react-icons/ri';
3
+ import { Information, Title } from './styles';
4
+ import { TransitingData } from '@autobusal/providers/types/routes';
5
+
6
+ interface Props {
7
+ countries: TransitingData[]
8
+ t: TFunction<'public'>
9
+ }
10
+
11
+ const Transiting = ({ countries, t }: Props): JSX.Element => {
12
+ const items = countries.map(item => (
13
+ item.country.name
14
+ ));
15
+
16
+ return (
17
+ <Information>
18
+ <Title>
19
+ <RiMapPin2Line />
20
+ { t('route_item.transiting') }:
21
+ </Title>
22
+
23
+ { items.join(', ') }
24
+ </Information>
25
+ );
26
+ };
27
+
28
+ export default Transiting;
@@ -0,0 +1,78 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ display: flex;
5
+ gap: 5px;
6
+ flex-direction: column;
7
+ margin-top: 10px;
8
+ padding: 10px;
9
+ background: ${ props => props.theme.background.neutral };
10
+ border-radius: ${ props => props.theme.borderRadius };
11
+
12
+ @media (min-width: 480px) {
13
+ margin-left: 75px;
14
+ }
15
+
16
+ @media (min-width: 640px) {
17
+ flex-direction: row;
18
+ margin-left: 115px;
19
+ }
20
+ `;
21
+
22
+ export const Details = styled.div`
23
+ flex: 1;
24
+ display: flex;
25
+ flex-direction: column;
26
+ gap: 5px;
27
+ `;
28
+
29
+ export const Policy = styled.div`
30
+ flex: 1;
31
+ display: flex;
32
+
33
+ @media (min-width: 640px) {
34
+ flex: initial;
35
+ flex-basis: 200px;
36
+ justify-content: right;
37
+ align-items: flex-start;
38
+ }
39
+ `;
40
+
41
+ export const Information = styled.div`
42
+ display: flex;
43
+ flex-direction: column;
44
+ font-size: ${ props => props.theme.size.s };
45
+
46
+ @media (min-width: 768px) {
47
+ flex-direction: row;
48
+ align-items: center;
49
+ }
50
+ `;
51
+
52
+ export const Title = styled.h6`
53
+ display: inline-flex;
54
+ align-items: center;
55
+ gap: 4px;
56
+ margin: 0 5px 0 0;
57
+ font-size: ${ props => props.theme.size.s };
58
+ `;
59
+
60
+ export const ButtonPolicy = styled.button`
61
+ display: flex;
62
+ align-items: center;
63
+ gap: 5px;
64
+ color: ${ props => props.theme.font.info };
65
+ font-weight: 700;
66
+ font-size: ${ props => props.theme.size.xs };
67
+
68
+ &:hover {
69
+ text-decoration: underline;
70
+ }
71
+ `;
72
+
73
+ export const ContainerFeatures = styled.div`
74
+ display: flex;
75
+ flex-wrap: wrap;
76
+ gap: 8px;
77
+ margin-top: 5px;
78
+ `;
@@ -0,0 +1,74 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { HiOutlineInformationCircle, HiOutlineClock, HiArrowCircleRight } from 'react-icons/hi';
4
+ import More from './More/More';
5
+ import { Container, About, Image, Logo, Information, Name, Code, ButtonMore, Locations, Location, City, Date, Arrow, Order, LinkOrder } from './styles';
6
+ import { RouteData } from '@autobusal/providers/types/routes';
7
+
8
+ interface Props {
9
+ type: 'browse' | 'view'
10
+ route: RouteData
11
+ t: TFunction<'common'>
12
+ }
13
+
14
+ const RouteItem = ({ type, route, t }: Props): JSX.Element => {
15
+ const [ show, setShow ] = useState<boolean>(false);
16
+
17
+ const lastLocation = route.locations.length - 1;
18
+
19
+ return (
20
+ <Container className="box">
21
+ <About>
22
+ <Image>
23
+ <Logo to={ route.operator.link }>
24
+ <img src={ route.operator.logo_url } />
25
+ </Logo>
26
+ </Image>
27
+
28
+ <Information>
29
+ <Name to={ route.link }>{ route.name }</Name>
30
+
31
+ <Code>{ route.code }</Code>
32
+
33
+ <ButtonMore type="button" onClick={ () => setShow(!show) }>
34
+ <HiOutlineInformationCircle />
35
+ { t('route_item.info') }
36
+ </ButtonMore>
37
+ </Information>
38
+
39
+ <Locations>
40
+ <Location>
41
+ <City>{ route.locations[0].city.name }</City>
42
+
43
+ <Date>
44
+ { t('route_item.departure') }:
45
+ <HiOutlineClock /> { route.locations[0].departure }
46
+ </Date>
47
+ </Location>
48
+
49
+ <Arrow>
50
+ <HiArrowCircleRight />
51
+ </Arrow>
52
+
53
+ <Location>
54
+ <City>{ route.locations[lastLocation].city.name }</City>
55
+
56
+ <Date>
57
+ { t('route_item.arrival') }:
58
+ <HiOutlineClock /> { route.locations[lastLocation].arrival }
59
+ </Date>
60
+ </Location>
61
+ </Locations>
62
+
63
+ <Order>
64
+ { type === 'browse' && <LinkOrder to={ route.link } $type="normal">{ t('route_item.details') }</LinkOrder> }
65
+ <LinkOrder to={ route.link_purchase } $type={ type === 'browse' ? 'small' : 'normal' }>{ t('route_item.buy') }</LinkOrder>
66
+ </Order>
67
+ </About>
68
+
69
+ { show && <More route={ route } t={ t } /> }
70
+ </Container>
71
+ );
72
+ };
73
+
74
+ export default RouteItem;
@@ -0,0 +1,176 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { Link } from 'react-router-dom';
3
+ // import { Box } from '@layouts/styles';
4
+
5
+ export const Container = styled.div`
6
+ padding: 10px;
7
+ border-left: 4px solid ${ props => props.theme.primary.normal };
8
+ border-right: 4px solid ${ props => props.theme.primary.normal };
9
+ `;
10
+
11
+ export const About = styled.div`
12
+ display: flex;
13
+ gap: 15px;
14
+ flex-wrap: wrap;
15
+ `;
16
+
17
+ export const Image = styled.div`
18
+ flex-basis: 60px;
19
+
20
+ @media (min-width: 640px) {
21
+ flex-basis: 100px;
22
+ }
23
+ `;
24
+
25
+ export const Logo = styled(Link)`
26
+ display: block;
27
+ width: 100%;
28
+ overflow: hidden;
29
+ aspect-ratio: 1.35;
30
+ border-radius: ${ props => props.theme.borderRadius };
31
+
32
+ & > img {
33
+ display: block;
34
+ width: 100%;
35
+ }
36
+ `;
37
+
38
+ export const Information = styled.div`
39
+ flex: 1;
40
+ display: flex;
41
+ flex-direction: column;
42
+ gap: 2px;
43
+
44
+ @media (min-width: 640px) {
45
+ gap: 6px;
46
+ }
47
+ `;
48
+
49
+ export const Name = styled(Link)`
50
+ font-weight: 700;
51
+ `;
52
+
53
+ export const Code = styled.div`
54
+ color: ${ props => props.theme.font.faded };
55
+ font-size: ${ props => props.theme.size.xs };
56
+ `;
57
+
58
+ export const ButtonMore = styled.button`
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 4px;
62
+ color: ${ props => props.theme.font.info };
63
+ font-size: ${ props => props.theme.size.xs };
64
+ `;
65
+
66
+ export const Locations = styled.div`
67
+ display: flex;
68
+ flex-basis: 100%;
69
+ flex-direction: column;
70
+ gap: 20px;
71
+ padding-left: 75px;
72
+
73
+ @media (min-width: 480px) {
74
+ flex-direction: row;
75
+ }
76
+
77
+ @media (min-width: 640px) {
78
+ padding-left: 115px;
79
+ }
80
+
81
+ @media (min-width: 768px) {
82
+ flex: 1;
83
+ flex-basis: initial;
84
+ }
85
+
86
+ @media (min-width: 1024px) {
87
+ flex: 1.5;
88
+ }
89
+ `;
90
+
91
+ export const Location = styled.div`
92
+ flex: 1;
93
+ display: flex;
94
+ flex-direction: column;
95
+ gap: 4px;
96
+
97
+ @media (min-width: 480px) {
98
+ align-self: center;
99
+ }
100
+ `;
101
+
102
+ export const City = styled.h5`
103
+ margin: 0;
104
+ font-weight: 700;
105
+ `;
106
+
107
+ export const Date = styled.div`
108
+ display: flex;
109
+ align-items: center;
110
+ gap: 4px;
111
+ color: ${ props => props.theme.font.faded };
112
+ font-size: ${ props => props.theme.size.s };
113
+ `;
114
+
115
+ export const Arrow = styled.div`
116
+ position: relative;
117
+ border-bottom: 3px solid ${ props => props.theme.primary.neutral };
118
+
119
+ & > svg {
120
+ position: absolute;
121
+ top: calc(50% - 14px);
122
+ left: calc(50% - 14px);
123
+ width: 30px;
124
+ height: 30px;
125
+ color: ${ props => props.theme.font.info };
126
+ background-color: ${ props => props.theme.foreground.normal };
127
+ border: 4px solid ${ props => props.theme.foreground.normal };
128
+ }
129
+
130
+ @media (min-width: 480px) {
131
+ border-right: 3px solid ${ props => props.theme.primary.neutral };
132
+ border-bottom: 0;
133
+
134
+ & > svg {
135
+ left: -14px;
136
+ }
137
+ }
138
+ `;
139
+
140
+ export const Order = styled.div`
141
+ flex: 1;
142
+ flex-basis: 100%;
143
+ display: flex;
144
+ gap: 8px;
145
+ justify-content: center;
146
+
147
+ @media (min-width: 1024px) {
148
+ flex-basis: 120px;
149
+ flex: initial;
150
+ flex-direction: column;
151
+ }
152
+ `;
153
+
154
+ export const LinkOrder = styled(Link)<{ $type: 'normal' | 'small' }>`
155
+ display: flex;
156
+ min-width: 100px;
157
+ height: 30px;
158
+ justify-content: center;
159
+ align-items: center;
160
+ font-weight: 700;
161
+ border-radius: 100px;
162
+ transition: all 0.3s ease;
163
+
164
+ ${ props => props.$type === 'normal' && css`
165
+ background-color: ${ props => props.theme.primary.normal };
166
+ ` }
167
+
168
+ ${ props => props.$type === 'small' && css`
169
+ background-color: ${ props => props.theme.primary.neutral };
170
+ ` }
171
+
172
+ &:hover {
173
+ text-decoration: none;
174
+ opacity: .7;
175
+ }
176
+ `;
package/index.ts CHANGED
@@ -1,16 +1,20 @@
1
+ import BackTo from './BackTo';
1
2
  import CookieNotification from './CookieNotification/CookieNotification';
2
3
  import ChangeLanguage from './ChangeLanguage/ChangeLanguage';
3
4
  import { Button } from './Button/Button';
4
5
  import { General, Paragraph } from './Loading/Loading';
5
6
  import Modal from './Modal/Modal';
6
7
  import Meta from './Meta';
8
+ import RouteItem from './RouteItem/RouteItem';
7
9
 
8
10
  export {
11
+ BackTo,
9
12
  Button,
10
13
  CookieNotification,
11
14
  ChangeLanguage,
12
15
  General,
13
16
  Meta,
14
17
  Modal,
15
- Paragraph
18
+ Paragraph,
19
+ RouteItem
16
20
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/common",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "dependencies": {
@@ -11,6 +11,7 @@
11
11
  "react-helmet": "^6.1.0",
12
12
  "react-icons": "^5.0.1",
13
13
  "react-loading-skeleton": "^3.3.1",
14
+ "react-router-dom": "^6.21.3",
14
15
  "spinners-react": "^1.0.7",
15
16
  "styled-components": "^6.1.8"
16
17
  }