@autobusal/operator-routes 1.0.9 → 1.0.11
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/Manage.tsx +14 -22
- package/Schedule/Manage.tsx +4 -3
- package/Seating.tsx +139 -14
- package/Transiting/Manage.tsx +2 -1
- package/Unavailable/Manage.tsx +2 -1
- package/package.json +1 -1
- package/services.ts +3 -2
- package/types.ts +6 -0
- package/utilities.tsx +0 -40
package/Manage.tsx
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { useState
|
|
1
|
+
import { useState } from 'react';
|
|
2
2
|
import { TFunction } from 'i18next';
|
|
3
3
|
import { useParams, useNavigate } from 'react-router-dom';
|
|
4
4
|
import { RiMoneyEuroCircleLine } from 'react-icons/ri';
|
|
5
5
|
import { FaMapMarkerAlt } from 'react-icons/fa';
|
|
6
6
|
import { IoCalendarClearOutline } from 'react-icons/io5';
|
|
7
7
|
import { Meta, BackWithTitle, Viewer } from '@autobusal/common';
|
|
8
|
-
import { usePage,
|
|
8
|
+
import { usePage, useRouteFeatures, useOperatorDrivers } from '@autobusal/hooks';
|
|
9
9
|
import { success } from '@autobusal/utilities';
|
|
10
10
|
import Template from './Template';
|
|
11
11
|
import Options from './Options';
|
|
12
12
|
import Seating from './Seating';
|
|
13
|
-
import { getType, getLanguagesExtended, getTemplates,
|
|
13
|
+
import { getType, getLanguagesExtended, getTemplates, getTransiting } from './utilities';
|
|
14
14
|
import { RouteData } from '@autobusal/providers/types/routes';
|
|
15
|
+
import { SeatingOptionsData } from './types';
|
|
15
16
|
import { useGetRoute, usePostRoute, useDeleteRoute } from './services';
|
|
16
17
|
|
|
17
18
|
interface Props {
|
|
@@ -20,7 +21,7 @@ interface Props {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
const Manage = ({ url, t }: Props): JSX.Element => {
|
|
23
|
-
const [ seating, setSeating ] = useState<
|
|
24
|
+
const [ seating, setSeating ] = useState<SeatingOptionsData | undefined>(undefined);
|
|
24
25
|
|
|
25
26
|
const params = useParams();
|
|
26
27
|
|
|
@@ -30,26 +31,16 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
30
31
|
|
|
31
32
|
const navigate = useNavigate();
|
|
32
33
|
|
|
33
|
-
const { data } = useGetRoute(id);
|
|
34
|
+
const { data, isFetching } = useGetRoute(id);
|
|
34
35
|
|
|
35
36
|
const { mutate: Update, isPending: isPendingSave } = usePostRoute(id, seating);
|
|
36
37
|
|
|
37
38
|
const { mutate: Delete, isPending: isPendingDelete } = useDeleteRoute();
|
|
38
39
|
|
|
39
|
-
const buses = useBuses();
|
|
40
|
-
|
|
41
40
|
const features = useRouteFeatures();
|
|
42
41
|
|
|
43
42
|
const drivers = useOperatorDrivers('id');
|
|
44
43
|
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
setSeating(data?.trip.seating ?? 'free');
|
|
47
|
-
}, [data]);
|
|
48
|
-
|
|
49
|
-
const onSeating = (id: string): void => {
|
|
50
|
-
setSeating(id);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
44
|
const onSave = (data: RouteData): void => {
|
|
54
45
|
Update(data, {
|
|
55
46
|
onSuccess: () => {
|
|
@@ -69,7 +60,11 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
69
60
|
}
|
|
70
61
|
});
|
|
71
62
|
};
|
|
72
|
-
|
|
63
|
+
|
|
64
|
+
const onSeatingUpdated = (options: SeatingOptionsData): void => {
|
|
65
|
+
setSeating(options);
|
|
66
|
+
};
|
|
67
|
+
|
|
73
68
|
const title = id > 0 ? t('operator_routes.manage.title.update', { name: data?.name, ns: 'common' }) : t('operator_routes.manage.title.new', { ns: 'common' });
|
|
74
69
|
|
|
75
70
|
return (
|
|
@@ -95,12 +90,8 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
95
90
|
label: t('operator_routes.manage.seat_reservation', { ns: 'common' }),
|
|
96
91
|
type: 'component',
|
|
97
92
|
name: 'seating',
|
|
98
|
-
value: <Seating
|
|
99
|
-
}, {},
|
|
100
|
-
getBusType(buses, seating, t, data?.trip.bus?.id)
|
|
101
|
-
) , (
|
|
102
|
-
getSeatingType(seating, t, data?.trip)
|
|
103
|
-
), {} , {
|
|
93
|
+
value: <Seating trip={ data?.trip } t={ t } onUpdated={ onSeatingUpdated } />
|
|
94
|
+
}, {} , {
|
|
104
95
|
label: t('operator_routes.manage.schedule.title', { ns: 'common' }),
|
|
105
96
|
name: 'schedule',
|
|
106
97
|
type: 'link',
|
|
@@ -223,6 +214,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
223
214
|
<Options id={ id } t={ t } />
|
|
224
215
|
)
|
|
225
216
|
}] }
|
|
217
|
+
fetching={ isFetching }
|
|
226
218
|
pending={ isPendingSave || isPendingDelete }
|
|
227
219
|
t={ t }
|
|
228
220
|
actions={ [
|
package/Schedule/Manage.tsx
CHANGED
|
@@ -23,7 +23,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
23
23
|
|
|
24
24
|
const navigate = useNavigate();
|
|
25
25
|
|
|
26
|
-
const { data } = useGetSchedule(id);
|
|
26
|
+
const { data, isFetching } = useGetSchedule(id);
|
|
27
27
|
|
|
28
28
|
const { mutate: Update, isPending } = usePostSchedule(id);
|
|
29
29
|
|
|
@@ -34,7 +34,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
34
34
|
const onSave = (data: AvailableData): void => {
|
|
35
35
|
Update(data, {
|
|
36
36
|
onSuccess: () => {
|
|
37
|
-
success(t('schedules_manage.
|
|
37
|
+
success(t('schedules_manage.messages.saved', { ns: 'common' }));
|
|
38
38
|
|
|
39
39
|
navigate(url);
|
|
40
40
|
}
|
|
@@ -42,7 +42,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
const title = t('schedules_manage.title', { name: data?.name, ns: 'common' });
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
return (
|
|
47
47
|
<Meta title={ title }>
|
|
48
48
|
<BackWithTitle title={ title } to={ url } t={ t } />
|
|
@@ -68,6 +68,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
68
68
|
values: getSchedules(t),
|
|
69
69
|
selected: data?.available.schedule ?? []
|
|
70
70
|
}] }
|
|
71
|
+
fetching={ isFetching }
|
|
71
72
|
pending={ isPending }
|
|
72
73
|
t={ t }
|
|
73
74
|
actions={ [
|
package/Seating.tsx
CHANGED
|
@@ -1,29 +1,154 @@
|
|
|
1
|
+
import { useState, useEffect, ChangeEvent } from 'react';
|
|
1
2
|
import { TFunction } from 'i18next';
|
|
3
|
+
import { useBuses } from '@autobusal/hooks';
|
|
4
|
+
import { Display } from '@autobusal/common/Viewer/styles';
|
|
2
5
|
import styled from 'styled-components';
|
|
6
|
+
import { TripData } from '@autobusal/providers/types/routes';
|
|
7
|
+
import { SeatingOptionsData } from './types';
|
|
3
8
|
|
|
4
9
|
interface Props {
|
|
5
|
-
|
|
10
|
+
trip?: TripData
|
|
6
11
|
t: TFunction<'normal'>
|
|
7
|
-
|
|
12
|
+
onUpdated: (options: SeatingOptionsData) => void
|
|
8
13
|
}
|
|
9
14
|
|
|
10
|
-
const Seating = ({
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
const Seating = ({ trip, t, onUpdated }: Props): JSX.Element => {
|
|
16
|
+
const [ data, setData ] = useState<SeatingOptionsData>({
|
|
17
|
+
seating: trip?.seating ?? 'free',
|
|
18
|
+
bus_id: trip?.bus?.id,
|
|
19
|
+
blocked_seats: Number(trip?.blocked_seats),
|
|
20
|
+
available_seats: Number(trip?.available_seats)
|
|
21
|
+
});
|
|
22
|
+
const [ type, setType ] = useState<string>(data.seating);
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
const buses = useBuses();
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
onUpdated(data);
|
|
28
|
+
}, [data, onUpdated]);
|
|
29
|
+
|
|
30
|
+
const onSeatingChange = (type: string): void => {
|
|
31
|
+
const newData = { ...data };
|
|
32
|
+
|
|
33
|
+
newData.seating = type;
|
|
34
|
+
|
|
35
|
+
if (type === 'free') {
|
|
36
|
+
newData.bus_id = undefined;
|
|
37
|
+
newData.blocked_seats = 0;
|
|
38
|
+
} else {
|
|
39
|
+
newData.bus_id = Number(buses[0].id);
|
|
40
|
+
newData.available_seats = 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setType(type);
|
|
44
|
+
setData(newData);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const onBusChange = (event: ChangeEvent<HTMLSelectElement>): void => {
|
|
48
|
+
setData({
|
|
49
|
+
...data,
|
|
50
|
+
bus_id: Number(event.target.value)
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const onSeatsChange = (event: ChangeEvent<HTMLInputElement>, type: string): void => {
|
|
55
|
+
const seatsNo = Number(event.target.value);
|
|
56
|
+
|
|
57
|
+
if (type === 'blocked_seats') {
|
|
58
|
+
setData({
|
|
59
|
+
...data,
|
|
60
|
+
blocked_seats: seatsNo
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (type === 'available_seats') {
|
|
65
|
+
setData({
|
|
66
|
+
...data,
|
|
67
|
+
available_seats: seatsNo
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const busOptions = buses.map(bus => (
|
|
73
|
+
<option key={ bus.id } value={ bus.id }>
|
|
74
|
+
{ bus.name }
|
|
75
|
+
</option>
|
|
76
|
+
));
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<>
|
|
80
|
+
<div className="row">
|
|
81
|
+
<Container>
|
|
82
|
+
<label>
|
|
83
|
+
<input checked={ type === 'free' } type="radio" name="seating" onChange={ () => onSeatingChange('free') } />
|
|
84
|
+
{ t('operator_routes.manage.seating.free', { ns: 'common' }) }
|
|
85
|
+
</label>
|
|
86
|
+
|
|
87
|
+
<label>
|
|
88
|
+
<input checked={ type === 'reservation' } type="radio" name="seating" onChange={ () => onSeatingChange('reservation') } />
|
|
89
|
+
{ t('operator_routes.manage.seating.reservation', { ns: 'common' }) }
|
|
90
|
+
</label>
|
|
91
|
+
</Container>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<Column className="column">
|
|
95
|
+
<div className="row">
|
|
96
|
+
{ type === 'reservation' && (
|
|
97
|
+
<>
|
|
98
|
+
{ t('operator_routes.manage.bus.reservation', { ns: 'common' }) }
|
|
99
|
+
|
|
100
|
+
<select defaultValue={ trip?.bus?.id } onChange={ onBusChange }>
|
|
101
|
+
{ busOptions }
|
|
102
|
+
</select>
|
|
103
|
+
</>
|
|
104
|
+
) }
|
|
105
|
+
|
|
106
|
+
{ type === 'free' && (
|
|
107
|
+
<>
|
|
108
|
+
{ t('operator_routes.manage.bus.title', { ns: 'common' }) }
|
|
109
|
+
|
|
110
|
+
<Display className="row-data">{ t('operator_routes.manage.bus.free', { ns: 'common' }) }</Display>
|
|
111
|
+
</>
|
|
112
|
+
) }
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div className="row row-nomargin">
|
|
116
|
+
{ type === 'reservation' && (
|
|
117
|
+
<>
|
|
118
|
+
{ t('operator_routes.manage.seats.blocked', { ns: 'common' }) }
|
|
119
|
+
|
|
120
|
+
<input type="number" name="blocked_seats" defaultValue={ data.blocked_seats } onChange={ (event) => onSeatsChange(event, 'blocked_seats') } />
|
|
121
|
+
</>
|
|
122
|
+
) }
|
|
123
|
+
|
|
124
|
+
{ type === 'free' && (
|
|
125
|
+
<>
|
|
126
|
+
{ t('operator_routes.manage.seats.available', { ns: 'common' }) }
|
|
127
|
+
|
|
128
|
+
<input type="number" name="available_seats" defaultValue={ data.available_seats } onChange={ (event) => onSeatsChange(event, 'available_seats') } />
|
|
129
|
+
</>
|
|
130
|
+
) }
|
|
131
|
+
</div>
|
|
132
|
+
</Column>
|
|
133
|
+
</>
|
|
134
|
+
);
|
|
135
|
+
};
|
|
23
136
|
|
|
24
137
|
const Container = styled.div`
|
|
25
138
|
display: flex;
|
|
26
139
|
gap: 15px;
|
|
27
140
|
`;
|
|
28
141
|
|
|
142
|
+
const Column = styled.div`
|
|
143
|
+
& > div:first-of-type {
|
|
144
|
+
margin-bottom: 15px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@media (min-width: 540px) {
|
|
148
|
+
& > div:first-of-type {
|
|
149
|
+
margin-bottom: 0;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
`;
|
|
153
|
+
|
|
29
154
|
export default Seating;
|
package/Transiting/Manage.tsx
CHANGED
|
@@ -24,7 +24,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
24
24
|
|
|
25
25
|
const { data: CountriesData, isLoading } = useCountries('available');
|
|
26
26
|
|
|
27
|
-
const { data, refetch } = useGetTransiting(id);
|
|
27
|
+
const { data, isFetching, refetch } = useGetTransiting(id);
|
|
28
28
|
|
|
29
29
|
const { mutate: Update, isPending: isPendingSave } = usePostTransiting(id);
|
|
30
30
|
|
|
@@ -79,6 +79,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
79
79
|
value: 0,
|
|
80
80
|
rules: 'required|min:1'
|
|
81
81
|
}] }
|
|
82
|
+
fetching={ isFetching }
|
|
82
83
|
pending={ isPendingSave || isPendingDelete }
|
|
83
84
|
t={ t }
|
|
84
85
|
actions={ [
|
package/Unavailable/Manage.tsx
CHANGED
|
@@ -23,7 +23,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
23
23
|
|
|
24
24
|
const navigate = useNavigate();
|
|
25
25
|
|
|
26
|
-
const { data } = useGetUnavailable(routeId, id);
|
|
26
|
+
const { data, isFetching } = useGetUnavailable(routeId, id);
|
|
27
27
|
|
|
28
28
|
const { mutate: Update, isPending: isPendingSave } = usePostUnavailable(routeId, id);
|
|
29
29
|
|
|
@@ -76,6 +76,7 @@ const Manage = ({ url, t }: Props): JSX.Element => {
|
|
|
76
76
|
value: unavailable?.end_inactive,
|
|
77
77
|
rules: 'required'
|
|
78
78
|
}] }
|
|
79
|
+
fetching={ isFetching }
|
|
79
80
|
pending={ isPendingSave || isPendingDelete }
|
|
80
81
|
t={ t }
|
|
81
82
|
actions={ [
|
package/package.json
CHANGED
package/services.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { apiClient } from '@autobusal/providers';
|
|
|
3
3
|
import { PaginationData } from '@autobusal/providers/types/pagination';
|
|
4
4
|
import { RouteData } from '@autobusal/providers/types/routes';
|
|
5
5
|
import { TableParamsData } from '@autobusal/providers/types/other';
|
|
6
|
+
import { SeatingOptionsData } from './types';
|
|
6
7
|
|
|
7
8
|
export const useGetRoutes = (params: TableParamsData): UseQueryResult<PaginationData<RouteData>> => (
|
|
8
9
|
useQuery({
|
|
@@ -36,7 +37,7 @@ export const useGetRoute = (id: number): UseSuspenseQueryResult<RouteData> => (
|
|
|
36
37
|
})
|
|
37
38
|
);
|
|
38
39
|
|
|
39
|
-
export const usePostRoute = (id: number, seating
|
|
40
|
+
export const usePostRoute = (id: number, seating?: SeatingOptionsData): UseMutationResult<void, Error, RouteData, unknown> => (
|
|
40
41
|
useMutation({
|
|
41
42
|
mutationKey: ['operator-routes-save', { id, seating }],
|
|
42
43
|
mutationFn: async (data: RouteData) => (
|
|
@@ -44,7 +45,7 @@ export const usePostRoute = (id: number, seating: string): UseMutationResult<voi
|
|
|
44
45
|
.post('/api/routes/operator/update', {
|
|
45
46
|
...data,
|
|
46
47
|
id,
|
|
47
|
-
seating,
|
|
48
|
+
...seating,
|
|
48
49
|
features: JSON.stringify(data.features),
|
|
49
50
|
drivers: JSON.stringify(data.drivers)
|
|
50
51
|
})
|
package/types.ts
ADDED
package/utilities.tsx
CHANGED
|
@@ -2,7 +2,6 @@ import { TFunction } from 'i18next';
|
|
|
2
2
|
import { IoGlobeOutline } from 'react-icons/io5';
|
|
3
3
|
import { getLanguages } from '@autobusal/utilities';
|
|
4
4
|
import { DropdownData } from '@autobusal/providers/types/other';
|
|
5
|
-
import { TripData } from '@autobusal/providers/types/routes';
|
|
6
5
|
import { ViewData } from '@autobusal/common/Viewer/types';
|
|
7
6
|
|
|
8
7
|
export const getType = (id: number, value: string, t: TFunction<'normal'>): ViewData => {
|
|
@@ -53,45 +52,6 @@ export const getTemplates = (t: TFunction<'normal'>): DropdownData[] => ([
|
|
|
53
52
|
}
|
|
54
53
|
]);
|
|
55
54
|
|
|
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
55
|
export const getTransiting = (id: number, t: TFunction<'normal'>, type?: string): ViewData => {
|
|
96
56
|
if (type == 'national') {
|
|
97
57
|
return {
|