@autobusal/operator-routes 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.
package/Browse.tsx ADDED
@@ -0,0 +1,79 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useSearchParams } from 'react-router-dom';
3
+ import { Meta, Table, Row } from '@autobusal/common';
4
+ import { usePage } from '@autobusal/hooks';
5
+ import { getParams } from '@autobusal/utilities';
6
+ import { Bags, Dates } from './Information';
7
+ import { GetRoutes } from './services';
8
+
9
+ interface Props {
10
+ url: string
11
+ t: TFunction<'common'>
12
+ }
13
+
14
+ const Browse = ({ url, t }: Props): JSX.Element => {
15
+ const [ searchParams ] = useSearchParams();
16
+
17
+ usePage('routes');
18
+
19
+ const { data, isLoading, isFetching } = GetRoutes(getParams(searchParams, ['page', 'sort', 'order', 'q']));
20
+
21
+ const rows = data?.data.map(item => (
22
+ <Row
23
+ key={ item.id }
24
+ id={ item.id }
25
+ data={ [
26
+ item.name,
27
+ item.code,
28
+ item.trip.bus?.name ?? '-',
29
+ <Bags key={ item.id } item={ item } t={ t } />,
30
+ <Dates key={ item.id } item={ item } t={ t } />
31
+ ] }
32
+ />
33
+ ));
34
+
35
+ return (
36
+ <Meta title={ t('operator_routes.browse.title.manage', { ns: 'common' }) }>
37
+ <h1>{ t('operator_routes.browse.title.manage', { ns: 'common' }) }</h1>
38
+
39
+ <Table
40
+ url={ url }
41
+ columns={ [{
42
+ name: t('operator_routes.browse.name', { ns: 'common' }),
43
+ width: 30,
44
+ slug: 'name',
45
+ type: 'az'
46
+ }, {
47
+ name: t('operator_routes.browse.code', { ns: 'common' }),
48
+ slug: 'code',
49
+ width: 10
50
+ }, {
51
+ name: t('operator_routes.browse.bus', { ns: 'common' }),
52
+ width: 10
53
+ }, {
54
+ name: t('operator_routes.browse.bags', { ns: 'common' }),
55
+ width: 20
56
+ }, {
57
+ name: t('operator_routes.browse.info', { ns: 'common' }),
58
+ slug: 'date',
59
+ width: 20
60
+ }] }
61
+ rows={ rows }
62
+ pages={ data }
63
+ sorting={ {
64
+ slug: 'name',
65
+ order: 'asc'
66
+ } }
67
+ search={ searchParams.get('q') }
68
+ loading={ isLoading }
69
+ fetching={ isFetching }
70
+ t={ t }
71
+ actions={ [
72
+ 'create', 'search', 'view'
73
+ ] }
74
+ />
75
+ </Meta>
76
+ );
77
+ };
78
+
79
+ export default Browse;
@@ -0,0 +1,46 @@
1
+ import { TFunction } from 'i18next';
2
+ import styled from 'styled-components';
3
+ import { RouteData } from '@autobusal/providers/types/routes';
4
+
5
+ interface Props {
6
+ item?: RouteData
7
+ t: TFunction<'common'>
8
+ }
9
+
10
+ export const Bags = ({ item, t }: Props): JSX.Element => (
11
+ <Container>
12
+ <div>
13
+ { t('operator_routes.browse.allowed.bags_no', { ns: 'common' }) }: <strong>{ item?.trip.bags_no_display }</strong>
14
+ </div>
15
+
16
+ <div>
17
+ { t('operator_routes.browse.allowed.bags_weight', { ns: 'common' }) }: <strong>{ item?.trip.bags_weight_display }</strong>
18
+ </div>
19
+ </Container>
20
+ );
21
+
22
+ export const Dates = ({ item, t }: Props): JSX.Element => (
23
+ <Container>
24
+ { item?.available.start_date && (
25
+ <div>
26
+ { t('operator_routes.browse.dates.start_date', { ns: 'common' }) }: <strong>{ item.available.start_date }</strong>
27
+ </div>
28
+ ) }
29
+
30
+ { item?.available.end_date && (
31
+ <div>
32
+ { t('operator_routes.browse.dates.end_date', { ns: 'common' }) }: <strong>{ item.available.end_date }</strong>
33
+ </div>
34
+ ) }
35
+
36
+ { item?.available.schedule_display && (
37
+ <div>
38
+ { t('operator_routes.browse.dates.schedule', { ns: 'common' }) }: <strong>{ item.available.schedule_display }</strong>
39
+ </div>
40
+ ) }
41
+ </Container>
42
+ );
43
+
44
+ const Container = styled.div`
45
+ text-align: left;
46
+ `;
package/Manage.tsx ADDED
@@ -0,0 +1,238 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { useParams, useNavigate } from 'react-router-dom';
4
+ import { RiMoneyEuroCircleLine } from 'react-icons/ri';
5
+ import { FaMapMarkerAlt } from 'react-icons/fa';
6
+ import { IoCalendarClearOutline } from 'react-icons/io5';
7
+ import { Meta, BackWithTitle, Viewer } from '@autobusal/common';
8
+ import { usePage, useBuses, useRouteFeatures, useOperatorDrivers } from '@autobusal/hooks';
9
+ import { success } from '@autobusal/utilities';
10
+ import Template from './Template';
11
+ import Options from './Options';
12
+ import Seating from './Seating';
13
+ import { getType, getLanguagesExtended, getTemplates, getBusType, getSeatingType, getTransiting } from './utilities';
14
+ import { RouteData } from '@autobusal/providers/types/routes';
15
+ import { GetRoute, PostRoute, DeleteRoute } from './services';
16
+
17
+ interface Props {
18
+ url: string
19
+ t: TFunction<'common'>
20
+ }
21
+
22
+ const Manage = ({ url, t }: Props): JSX.Element => {
23
+ const [ seating, setSeating ] = useState<string>('');
24
+
25
+ const params = useParams();
26
+
27
+ const id = Number(params.id);
28
+
29
+ usePage('routes');
30
+
31
+ const navigate = useNavigate();
32
+
33
+ const { data } = GetRoute(id);
34
+
35
+ const { mutate: Update, isPending: isPendingSave } = PostRoute(id, seating);
36
+
37
+ const { mutate: Delete, isPending: isPendingDelete } = DeleteRoute();
38
+
39
+ const buses = useBuses();
40
+
41
+ const features = useRouteFeatures();
42
+
43
+ const drivers = useOperatorDrivers('id');
44
+
45
+ useEffect(() => {
46
+ setSeating(data?.trip.seating ?? 'free');
47
+ }, [data]);
48
+
49
+ const onSeating = (id: string): void => {
50
+ setSeating(id);
51
+ };
52
+
53
+ const onSave = (data: RouteData): void => {
54
+ Update(data, {
55
+ onSuccess: () => {
56
+ success(t('operator_routes.manage.messages.saved', { ns: 'common' }));
57
+
58
+ navigate(url);
59
+ }
60
+ });
61
+ };
62
+
63
+ const onDelete = (): void => {
64
+ Delete(id, {
65
+ onSuccess: () => {
66
+ success(t('operator_routes.manage.messages.deleted', { ns: 'common' }));
67
+
68
+ navigate(url);
69
+ }
70
+ });
71
+ };
72
+
73
+ const title = id > 0 ? t('operator_routes.manage.title.update', { name: data?.name, ns: 'common' }) : t('operator_routes.manage.title.new', { ns: 'common' });
74
+
75
+ return (
76
+ <Meta title={ title }>
77
+ <BackWithTitle title={ title } to={ url } t={ t } />
78
+
79
+ <Viewer
80
+ id={ id }
81
+ data={ [{
82
+ label: t('operator_routes.manage.name', { ns: 'common' }),
83
+ name: 'name',
84
+ type: 'text',
85
+ value: data?.name,
86
+ rules: 'required|min_length:2|max_length:250'
87
+ }, {
88
+ label: t('operator_routes.manage.code', { ns: 'common' }),
89
+ name: 'code',
90
+ type: 'display',
91
+ value: (data?.code ?? '-')
92
+ }, (
93
+ getType(id, (data?.type ?? ''), t)
94
+ ), {}, {
95
+ label: t('operator_routes.manage.seat_reservation', { ns: 'common' }),
96
+ type: 'component',
97
+ name: 'seating',
98
+ value: <Seating value={ seating } t={ t } onChange={ onSeating } />
99
+ }, {}, (
100
+ getBusType(buses, seating, t, data?.trip.bus?.id)
101
+ ) , (
102
+ getSeatingType(seating, t, data?.trip)
103
+ ), {} , {
104
+ label: t('operator_routes.manage.schedule.title', { ns: 'common' }),
105
+ name: 'schedule',
106
+ type: 'link',
107
+ value: (
108
+ <>
109
+ <IoCalendarClearOutline />
110
+ { t('operator_routes.manage.schedule.link', { ns: 'common' }) }
111
+ </>
112
+ ),
113
+ url: `/operator/routes/schedule/${ id }`
114
+ }, (
115
+ getTransiting(id, t, data?.type)
116
+ ), {
117
+ label: t('operator_routes.manage.unavailable.title', { ns: 'common' }),
118
+ name: 'unavailable',
119
+ type: 'link',
120
+ value: (
121
+ <>
122
+ <IoCalendarClearOutline />
123
+ { t('operator_routes.manage.unavailable.link', { ns: 'common' }) }
124
+ </>
125
+ ),
126
+ url: `/operator/routes/unavailable/${ id }`
127
+ }, {}, {
128
+ label: t('operator_routes.manage.features', { ns: 'common' }),
129
+ name: 'features',
130
+ type: 'checkbox-list',
131
+ selected: data?.trip?.features ?? [],
132
+ values: features
133
+ }, {}, {
134
+ label: t('operator_routes.manage.bags_no', { ns: 'common' }),
135
+ name: 'bags_no',
136
+ type: 'number',
137
+ value: data?.trip.bags_no,
138
+ rules: 'required|min:1'
139
+ }, {
140
+ label: t('operator_routes.manage.bags_weight', { ns: 'common' }),
141
+ name: 'bags_weight',
142
+ type: 'number',
143
+ value: data?.trip.bags_weight,
144
+ rules: 'required|min:1'
145
+ }, {}, {
146
+ label: t('operator_routes.manage.language', { ns: 'common' }),
147
+ name: 'language',
148
+ type: 'select',
149
+ values: getLanguagesExtended(),
150
+ value: data?.language,
151
+ rules: 'required'
152
+ }, {
153
+ label: t('operator_routes.manage.template', { ns: 'common' }),
154
+ name: 'template',
155
+ type: 'select',
156
+ values: getTemplates(t),
157
+ value: data?.template,
158
+ rules: 'required'
159
+ }, {}, {
160
+ label: t('operator_routes.manage.locations.title', { ns: 'common' }),
161
+ type: 'link',
162
+ name: 'locations',
163
+ value: (
164
+ <>
165
+ <FaMapMarkerAlt />
166
+ { t('operator_routes.manage.locations.link', { ns: 'common' }) }
167
+ </>
168
+ ),
169
+ url: `/operator/routes/locations/${ id }`
170
+ }, {
171
+ label: t('operator_routes.manage.prices.title', { ns: 'common' }),
172
+ type: 'link',
173
+ name: 'prices',
174
+ value: (
175
+ <>
176
+ <RiMoneyEuroCircleLine />
177
+ { t('operator_routes.manage.prices.link', { ns: 'common' }) }
178
+ </>
179
+ ),
180
+ url: `/operator/routes/prices/${ id }`
181
+ }, {
182
+ label: t('operator_routes.manage.alternate.title', { ns: 'common' }),
183
+ type: 'link',
184
+ name: 'prices_alternates',
185
+ value: (
186
+ <>
187
+ <RiMoneyEuroCircleLine />
188
+ { t('operator_routes.manage.alternate.link', { ns: 'common' }) }
189
+ </>
190
+ ),
191
+ url: `/operator/routes/alternates/${ id }`
192
+ }, {}, {
193
+ label: t('operator_routes.manage.drivers', { ns: 'common' }),
194
+ name: 'drivers',
195
+ type: 'checkbox-list-all',
196
+ selected: data?.drivers.registered ?? [],
197
+ values: drivers
198
+ }, {}, {
199
+ label: t('operator_routes.manage.searchable', { ns: 'common' }),
200
+ name: 'searchable',
201
+ type: 'checkbox',
202
+ value: data?.searchable
203
+ }, {}, {
204
+ label: t('operator_routes.manage.policies_en', { ns: 'common' }),
205
+ name: 'policies_en',
206
+ type: 'textarea-html',
207
+ value: data?.policies_en
208
+ }, {}, {
209
+ label: t('operator_routes.manage.policies_sq', { ns: 'common' }),
210
+ name: 'policies_sq',
211
+ type: 'textarea-html',
212
+ value: data?.policies_sq
213
+ }, {}, {
214
+ label: t('operator_routes.manage.ticket.template', { ns: 'common' }),
215
+ type: 'component',
216
+ name: 'template_preview',
217
+ value: <Template type={ data?.template } t={ t } />
218
+ }, {
219
+ label: t('operator_routes.manage.options.title', { ns: 'common' }),
220
+ type: 'component',
221
+ name: 'options',
222
+ value: (
223
+ <Options id={ id } t={ t } />
224
+ )
225
+ }] }
226
+ pending={ isPendingSave || isPendingDelete }
227
+ t={ t }
228
+ actions={ [
229
+ 'save', 'delete'
230
+ ]}
231
+ onSave={ onSave }
232
+ onDelete={ onDelete }
233
+ />
234
+ </Meta>
235
+ );
236
+ };
237
+
238
+ export default Manage;
package/Options.tsx ADDED
@@ -0,0 +1,96 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import styled from 'styled-components';
4
+ import { AiOutlineCopy, AiOutlineReload } from 'react-icons/ai';
5
+ import { Button } from '@autobusal/common';
6
+ import { success } from '@autobusal/utilities';
7
+ import { PostCopy } from './services';
8
+
9
+ interface Props {
10
+ id: number
11
+ t: TFunction<'normal'>
12
+ }
13
+
14
+ const Options = ({ id, t }: Props): JSX.Element => {
15
+ const navigate = useNavigate();
16
+
17
+ const { mutate: Copy, isPending: isPendingCopy } = PostCopy(id);
18
+
19
+ const { mutate: Reverse, isPending: isPendingReverse } = PostCopy(id, true);
20
+
21
+ const onCopy = (): void => {
22
+ if (!window.confirm(t('operator_routes.manage.options.confirm', { ns: 'common' }))) {
23
+ return;
24
+ }
25
+
26
+ Copy({}, {
27
+ onSuccess: (data) => {
28
+ success(t('operator_routes.manage.messages.copied', { ns: 'common' }));
29
+
30
+ navigate(`/operator/routes/manage/${ data.id }`);
31
+ }
32
+ });
33
+ };
34
+
35
+ const onReverse = (): void => {
36
+ if (!window.confirm(t('operator_routes.manage.options.confirm', { ns: 'common' }))) {
37
+ return;
38
+ }
39
+
40
+ Reverse({}, {
41
+ onSuccess: (data) => {
42
+ success(t('operator_routes.manage.messages.reversed', { ns: 'common' }));
43
+
44
+ navigate(`/operator/routes/manage/${ data.id }`);
45
+ }
46
+ });
47
+ };
48
+
49
+ if (id === 0) {
50
+ return (
51
+ <>-</>
52
+ );
53
+ }
54
+
55
+ return (
56
+ <Container>
57
+ <Button
58
+ type="button"
59
+ size="small"
60
+ subtype="secondary"
61
+ loading={ isPendingCopy }
62
+ text={
63
+ <>
64
+ <AiOutlineCopy />
65
+ { t('operator_routes.manage.options.copy', { ns: 'common' }) }
66
+ </>
67
+ }
68
+ noMargin
69
+ onClick={ onCopy }
70
+ />
71
+
72
+ <Button
73
+ type="button"
74
+ size="small"
75
+ subtype="secondary"
76
+ loading={ isPendingReverse }
77
+ text={
78
+ <>
79
+ <AiOutlineReload />
80
+ { t('operator_routes.manage.options.reverse', { ns: 'common' }) }
81
+ </>
82
+ }
83
+ noMargin
84
+ onClick={ onReverse }
85
+ />
86
+ </Container>
87
+ );
88
+ };
89
+
90
+ const Container = styled.div`
91
+ display: flex;
92
+ flex-wrap: wrap;
93
+ gap: 10px;
94
+ `;
95
+
96
+ export default Options;
package/Seating.tsx ADDED
@@ -0,0 +1,29 @@
1
+ import { TFunction } from 'i18next';
2
+ import styled from 'styled-components';
3
+
4
+ interface Props {
5
+ value?: string
6
+ t: TFunction<'normal'>
7
+ onChange: (id: string) => void
8
+ }
9
+
10
+ const Seating = ({ value, t, onChange }: Props): JSX.Element => (
11
+ <Container>
12
+ <label>
13
+ <input checked={ value === 'free' } type="radio" name="seating" onChange={ () => onChange('free') } />
14
+ { t('operator_routes.manage.seating.free', { ns: 'common' }) }
15
+ </label>
16
+
17
+ <label>
18
+ <input checked={ value === 'reservation' } type="radio" name="seating" onChange={ () => onChange('reservation') } />
19
+ { t('operator_routes.manage.seating.reservation', { ns: 'common' }) }
20
+ </label>
21
+ </Container>
22
+ );
23
+
24
+ const Container = styled.div`
25
+ display: flex;
26
+ gap: 15px;
27
+ `;
28
+
29
+ export default Seating;
package/Template.tsx ADDED
@@ -0,0 +1,59 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import styled from 'styled-components';
4
+ import { RiEyeFill } from 'react-icons/ri';
5
+ import { Button, Modal } from '@autobusal/common';
6
+ import { GetSettings } from '@autobusal/providers/services';
7
+
8
+ interface Props {
9
+ type?: string
10
+ t: TFunction<'normal'>
11
+ }
12
+
13
+ const Template = ({ type, t }: Props): JSX.Element => {
14
+ const [ show, setShow ] = useState<boolean>(false);
15
+
16
+ const { data } = GetSettings();
17
+
18
+ if (!type) {
19
+ return (
20
+ <>-</>
21
+ );
22
+ }
23
+
24
+ return (
25
+ <>
26
+ <Button
27
+ type="button"
28
+ subtype="secondary"
29
+ size="small"
30
+ text={
31
+ <>
32
+ <RiEyeFill />
33
+ { t('operator_routes.manage.ticket.preview', { ns: 'common' }) }
34
+ </>
35
+ }
36
+ noMargin
37
+ onClick={ () => setShow(true) }
38
+ />
39
+
40
+ { show && (
41
+ <Modal
42
+ title={ t('operator_routes.manage.ticket.preview', { ns: 'common' }) }
43
+ width={ 900 }
44
+ content={
45
+ <Image src={ `${ data.url }/tickets/${ type }.png` } />
46
+ }
47
+ onClose={ () => setShow(false) }
48
+ />
49
+ ) }
50
+ </>
51
+ );
52
+ };
53
+
54
+ const Image = styled.img`
55
+ display: block;
56
+ width: 100%;
57
+ `;
58
+
59
+ export default Template;
package/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ import Browse from './Browse';
2
+ import Manage from './Manage';
3
+
4
+ export {
5
+ Browse,
6
+ Manage
7
+ };
package/package.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "@autobusal/operator-routes",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "index.ts"
6
+ }
package/services.ts ADDED
@@ -0,0 +1,84 @@
1
+ import { UseMutationResult, UseQueryResult, UseSuspenseQueryResult, useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query';
2
+ import { apiClient } from '@autobusal/providers';
3
+ import { PaginationData } from '@autobusal/providers/types/pagination';
4
+ import { RouteData } from '@autobusal/providers/types/routes';
5
+ import { TableParamsData } from '@autobusal/providers/types/other';
6
+
7
+ export const GetRoutes = (params: TableParamsData): UseQueryResult<PaginationData<RouteData>> => (
8
+ useQuery({
9
+ queryKey: ['operator-routes', params],
10
+ queryFn: async () => (
11
+ await apiClient
12
+ .get('/api/routes/operator/browse', { params })
13
+ .then(response => (
14
+ response.data
15
+ ))
16
+ )
17
+ })
18
+ );
19
+
20
+ export const GetRoute = (id: number): UseSuspenseQueryResult<RouteData> => (
21
+ useSuspenseQuery({
22
+ queryKey: ['operator-routes-manage', { id }],
23
+ queryFn: async () => {
24
+ if (id === 0) {
25
+ return null;
26
+ }
27
+
28
+ return await apiClient
29
+ .get('/api/routes/operator/get', {
30
+ params: { id }
31
+ })
32
+ .then(response => (
33
+ response.data
34
+ ))
35
+ }
36
+ })
37
+ );
38
+
39
+ export const PostRoute = (id: number, seating: string): UseMutationResult<void, Error, RouteData, unknown> => (
40
+ useMutation({
41
+ mutationKey: ['operator-routes-save', { id, seating }],
42
+ mutationFn: async (data: RouteData) => (
43
+ await apiClient
44
+ .post('/api/routes/operator/update', {
45
+ ...data,
46
+ id,
47
+ seating,
48
+ features: JSON.stringify(data.features),
49
+ drivers: JSON.stringify(data.drivers)
50
+ })
51
+ .then(response => (
52
+ response.data
53
+ ))
54
+ )
55
+ })
56
+ );
57
+
58
+ export const DeleteRoute = (): UseMutationResult<void, Error, number, unknown> => (
59
+ useMutation({
60
+ mutationKey: ['operator-routes-delete'],
61
+ mutationFn: async (id: number) => (
62
+ await apiClient
63
+ .delete('/api/routes/operator/delete', {
64
+ params: { id }
65
+ })
66
+ .then(response => (
67
+ response.data
68
+ ))
69
+ )
70
+ })
71
+ );
72
+
73
+ export const PostCopy = (id: number, reverse?: boolean): UseMutationResult<RouteData> => (
74
+ useMutation({
75
+ mutationKey: [`operator-routes-copy${ reverse && '-reverse' }`, { id }],
76
+ mutationFn: async () => (
77
+ await apiClient
78
+ .post(`/api/routes/operator/${ reverse ? 'reverse' : 'copy' }`, { id })
79
+ .then(response => (
80
+ response.data
81
+ ))
82
+ )
83
+ })
84
+ );
package/utilities.tsx ADDED
@@ -0,0 +1,117 @@
1
+ import { TFunction } from 'i18next';
2
+ import { IoGlobeOutline } from 'react-icons/io5';
3
+ import { getLanguages } from '@autobusal/utilities';
4
+ import { DropdownData } from '@autobusal/providers/types/other';
5
+ import { TripData } from '@autobusal/providers/types/routes';
6
+ import { ViewData } from '@autobusal/common/Viewer/types';
7
+
8
+ export const getType = (id: number, value: string, t: TFunction<'normal'>): ViewData => {
9
+ if (id === 0) {
10
+ return {
11
+ label: t('operator_routes.manage.type', { ns: 'common' }),
12
+ name: 'type',
13
+ type: 'select',
14
+ values: getOptionsTypes(t),
15
+ value,
16
+ rules: 'required|min_length:1'
17
+ };
18
+ }
19
+
20
+ return {
21
+ label: t('operator_routes.manage.type', { ns: 'common' }),
22
+ name: 'type',
23
+ type: 'display',
24
+ value
25
+ };
26
+ };
27
+
28
+ const getOptionsTypes = (t: TFunction<'common'>): DropdownData[] => ([
29
+ {
30
+ name: t('data.route_types.international', { ns: 'common' }),
31
+ id: 'international'
32
+ }, {
33
+ name: t('data.route_types.national', { ns: 'common' }),
34
+ id: 'national'
35
+ }
36
+ ]);
37
+
38
+ export const getLanguagesExtended = (): DropdownData[] => {
39
+ const languages = getLanguages();
40
+
41
+ languages.push({
42
+ name: 'Gr',
43
+ id: 'gr'
44
+ });
45
+
46
+ return languages;
47
+ };
48
+
49
+ export const getTemplates = (t: TFunction<'normal'>): DropdownData[] => ([
50
+ {
51
+ name: t('operator_routes.manage.templates.standard', { ns: 'common' }),
52
+ id: 'standard'
53
+ }
54
+ ]);
55
+
56
+ export const getBusType = (buses: DropdownData[], seating: string, t: TFunction<'normal'>, value?: number): ViewData => {
57
+ if (seating === 'free') {
58
+ return {
59
+ label: t('operator_routes.manage.bus.reservation', { ns: 'common' }),
60
+ name: 'bus_id',
61
+ type: 'display',
62
+ value: t('operator_routes.manage.bus.free', { ns: 'common' })
63
+ };
64
+ }
65
+
66
+ return {
67
+ label: t('operator_routes.manage.bus.title', { ns: 'common' }),
68
+ name: 'bus_id',
69
+ type: 'select',
70
+ values: buses,
71
+ value,
72
+ rules: 'required|min:1'
73
+ };
74
+ };
75
+
76
+ export const getSeatingType = (seating: string, t: TFunction<'normal'>, trip?: TripData): ViewData => {
77
+ if (seating === 'free') {
78
+ return {
79
+ label: t('operator_routes.manage.seats.available', { ns: 'common' }),
80
+ name: 'available_seats',
81
+ type: 'number',
82
+ value: trip?.available_seats,
83
+ rules: 'required|min:1'
84
+ };
85
+ }
86
+
87
+ return {
88
+ label: t('operator_routes.manage.seats.blocked', { ns: 'common' }),
89
+ name: 'blocked_seats',
90
+ type: 'number',
91
+ value: trip?.blocked_seats
92
+ };
93
+ };
94
+
95
+ export const getTransiting = (id: number, t: TFunction<'normal'>, type?: string): ViewData => {
96
+ if (type == 'national') {
97
+ return {
98
+ label: t('operator_routes.manage.transiting.title', { ns: 'common' }),
99
+ name: 'transiting',
100
+ type: 'display',
101
+ value: t('operator_routes.manage.transiting.cant', { ns: 'common' })
102
+ };
103
+ }
104
+
105
+ return {
106
+ label: t('operator_routes.manage.transiting.title', { ns: 'common' }),
107
+ name: 'transiting',
108
+ type: 'link',
109
+ value: (
110
+ <>
111
+ <IoGlobeOutline />
112
+ { t('operator_routes.manage.transiting.link', { ns: 'common' }) }
113
+ </>
114
+ ),
115
+ url: `/operator/routes/transiting/${ id }`
116
+ };
117
+ };