@autobusal/operator-routes 1.0.9 → 1.0.10

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 CHANGED
@@ -5,13 +5,14 @@ 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, useBuses, useRouteFeatures, useOperatorDrivers } from '@autobusal/hooks';
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, getBusType, getSeatingType, getTransiting } from './utilities';
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<string>('');
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 value={ seating } t={ t } onChange={ onSeating } />
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={ [
@@ -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.message.saved', { ns: 'common' }));
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
- value?: string
10
+ trip?: TripData
6
11
  t: TFunction<'normal'>
7
- onChange: (id: string) => void
12
+ onUpdated: (options: SeatingOptionsData) => void
8
13
  }
9
14
 
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>
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
- <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
- );
24
+ const buses = useBuses();
25
+
26
+ useEffect(() => {
27
+ onUpdated(data);
28
+ }, [data]);
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;
@@ -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={ [
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/operator-routes",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "type": "module",
5
5
  "main": "index.ts"
6
6
  }
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: string): UseMutationResult<void, Error, RouteData, unknown> => (
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
@@ -0,0 +1,6 @@
1
+ export interface SeatingOptionsData {
2
+ seating: string
3
+ bus_id?: number
4
+ blocked_seats?: number
5
+ available_seats?: number
6
+ }
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 {