@autobusal/operator-routes 1.0.4 → 1.0.5
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/Locations/Add/Add.tsx +71 -0
- package/Locations/Add/Loading.tsx +17 -0
- package/Locations/Add/styles.ts +39 -0
- package/Locations/Browse/Actions.tsx +90 -0
- package/Locations/Browse/Browse.tsx +45 -0
- package/Locations/Browse/Item.tsx +92 -0
- package/Locations/Browse/styles.ts +36 -0
- package/Locations/Manage.tsx +44 -0
- package/Locations/services.ts +105 -0
- package/Locations/types.ts +9 -0
- package/Locations/utilities.tsx +53 -0
- package/Transiting/Countries.tsx +1 -1
- package/index.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { TFunction } from 'i18next';
|
|
2
|
+
import { useForm } from 'react-hook-form';
|
|
3
|
+
import { FiPlus } from 'react-icons/fi';
|
|
4
|
+
import { Button } from '@autobusal/common';
|
|
5
|
+
import { Validate, Display, success } from '@autobusal/utilities';
|
|
6
|
+
import Loading from './Loading';
|
|
7
|
+
import { getStops } from '../utilities';
|
|
8
|
+
import { Container, Title, ContainerAdd, Choose, Notice } from './styles';
|
|
9
|
+
import { AddForm } from '../types';
|
|
10
|
+
import { GetStops, AddLocation } from '../services';
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
routeId: number
|
|
14
|
+
t: TFunction<'normal'>
|
|
15
|
+
onReload: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const Add = ({ routeId, t, onReload }: Props): JSX.Element => {
|
|
19
|
+
const { register, handleSubmit, formState: { errors } } = useForm<AddForm>();
|
|
20
|
+
|
|
21
|
+
const { data, isLoading } = GetStops(routeId);
|
|
22
|
+
|
|
23
|
+
const { mutate: Save, isPending } = AddLocation(routeId);
|
|
24
|
+
|
|
25
|
+
if (isLoading) {
|
|
26
|
+
return <Loading t={ t } />;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const onSubmit = (data: AddForm): void => {
|
|
30
|
+
Save(data, {
|
|
31
|
+
onSuccess: () => {
|
|
32
|
+
success(t('locations_manage.messages.added', { ns: 'common' }));
|
|
33
|
+
|
|
34
|
+
onReload();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Container className="box">
|
|
41
|
+
<Title>{ t('locations_manage.add_city.title', { ns: 'common' }) }</Title>
|
|
42
|
+
|
|
43
|
+
<form onSubmit={ handleSubmit(onSubmit) }>
|
|
44
|
+
<ContainerAdd>
|
|
45
|
+
<Choose>
|
|
46
|
+
<select { ...register('group_id', Validate('required', t)) }>
|
|
47
|
+
{ getStops(t, data) }
|
|
48
|
+
</select>
|
|
49
|
+
|
|
50
|
+
{ Display(errors.group_id) }
|
|
51
|
+
</Choose>
|
|
52
|
+
|
|
53
|
+
<Button
|
|
54
|
+
loading={ isPending }
|
|
55
|
+
text={
|
|
56
|
+
<>
|
|
57
|
+
<FiPlus />
|
|
58
|
+
{ t('locations_manage.add_city.action', { ns: 'common' }) }
|
|
59
|
+
</>
|
|
60
|
+
}
|
|
61
|
+
noMargin
|
|
62
|
+
/>
|
|
63
|
+
</ContainerAdd>
|
|
64
|
+
|
|
65
|
+
<Notice>{ t('locations_manage.add_city.notice', { ns: 'common' }) }</Notice>
|
|
66
|
+
</form>
|
|
67
|
+
</Container>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export default Add;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TFunction } from 'i18next';
|
|
2
|
+
import { Inline } from '@autobusal/common';
|
|
3
|
+
import { Container, Title } from './styles';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
t: TFunction<'normal'>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const Loading = ({ t }: Props): JSX.Element => (
|
|
10
|
+
<Container className="box">
|
|
11
|
+
<Title>{ t('locations_manage.add_city.title', { ns: 'common' }) }</Title>
|
|
12
|
+
|
|
13
|
+
<Inline text={ t('locations_manage.add_city.loading', { ns: 'common' }) } />
|
|
14
|
+
</Container>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export default Loading;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
|
|
3
|
+
export const Container = styled.div`
|
|
4
|
+
margin-bottom: 25px;
|
|
5
|
+
`;
|
|
6
|
+
|
|
7
|
+
export const Title = styled.h5`
|
|
8
|
+
margin-bottom: 10px;
|
|
9
|
+
padding-bottom: 15px;
|
|
10
|
+
font-size: ${ props => props.theme.size.m };
|
|
11
|
+
border-bottom: 1px solid ${ props => props.theme.background.neutral };
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
export const ContainerAdd = styled.div`
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: 20px;
|
|
19
|
+
|
|
20
|
+
@media (min-width: 640px) {
|
|
21
|
+
flex-direction: row;
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
export const Choose = styled.div`
|
|
26
|
+
flex: 1;
|
|
27
|
+
width: 100%;
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
export const Notice = styled.div`
|
|
31
|
+
margin-top: 15px;
|
|
32
|
+
font-size: ${ props => props.theme.size.xs };
|
|
33
|
+
color: ${ props => props.theme.font.info };
|
|
34
|
+
text-align: center;
|
|
35
|
+
|
|
36
|
+
@media (min-width: 640px) {
|
|
37
|
+
text-align: left;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { TFunction } from 'i18next';
|
|
2
|
+
import { FiArrowDownCircle, FiArrowUpCircle } from 'react-icons/fi';
|
|
3
|
+
import { BiEditAlt, BiTrash } from 'react-icons/bi';
|
|
4
|
+
import { Button } from '@autobusal/common';
|
|
5
|
+
import { ContainerActions, Group } from './styles';
|
|
6
|
+
import { LocationData } from '@autobusal/providers/types/locations';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
item: LocationData
|
|
10
|
+
loading: boolean
|
|
11
|
+
t: TFunction<'normal'>
|
|
12
|
+
onMove: (order: number) => void
|
|
13
|
+
onDelete: () => void
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const Actions = ({ item, loading, t, onMove, onDelete }: Props): JSX.Element => {
|
|
17
|
+
const onChange = (type: 'up' | 'down'): void => {
|
|
18
|
+
if (!window.confirm(t('locations_manage.actions.move', { ns: 'common' }))) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const order = type === 'up' ? item.order_id - 1 : item.order_id + 1;
|
|
23
|
+
|
|
24
|
+
onMove(order);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const onAskDelete = (): void => {
|
|
28
|
+
if (window.confirm(t('locations_manage.actions.delete', { ns: 'common' }))) {
|
|
29
|
+
onDelete();
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<ContainerActions>
|
|
35
|
+
<Group>
|
|
36
|
+
<Button
|
|
37
|
+
type="button"
|
|
38
|
+
loading={ loading }
|
|
39
|
+
subtype="secondary"
|
|
40
|
+
size="small"
|
|
41
|
+
text={ <FiArrowUpCircle /> }
|
|
42
|
+
noMargin
|
|
43
|
+
onClick={ () => onChange('up') }
|
|
44
|
+
/>
|
|
45
|
+
|
|
46
|
+
<Button
|
|
47
|
+
type="button"
|
|
48
|
+
subtype="secondary"
|
|
49
|
+
loading={ loading }
|
|
50
|
+
size="small"
|
|
51
|
+
text={ <FiArrowDownCircle /> }
|
|
52
|
+
noMargin
|
|
53
|
+
onClick={ () => onChange('down') }
|
|
54
|
+
/>
|
|
55
|
+
</Group>
|
|
56
|
+
|
|
57
|
+
<Group>
|
|
58
|
+
<Button
|
|
59
|
+
type="submit"
|
|
60
|
+
loading={ loading }
|
|
61
|
+
size="small"
|
|
62
|
+
text={
|
|
63
|
+
<>
|
|
64
|
+
<BiEditAlt />
|
|
65
|
+
{ t('table.actions.update', { ns: 'common' }) }
|
|
66
|
+
</>
|
|
67
|
+
}
|
|
68
|
+
noMargin
|
|
69
|
+
/>
|
|
70
|
+
|
|
71
|
+
<Button
|
|
72
|
+
type="button"
|
|
73
|
+
loading={ loading }
|
|
74
|
+
size="small"
|
|
75
|
+
subtype="delete"
|
|
76
|
+
text={
|
|
77
|
+
<>
|
|
78
|
+
<BiTrash />
|
|
79
|
+
{ t('table.actions.delete', { ns: 'common' }) }
|
|
80
|
+
</>
|
|
81
|
+
}
|
|
82
|
+
noMargin
|
|
83
|
+
onClick={ onAskDelete }
|
|
84
|
+
/>
|
|
85
|
+
</Group>
|
|
86
|
+
</ContainerActions>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export default Actions;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { TFunction } from 'i18next';
|
|
2
|
+
import Item from './Item';
|
|
3
|
+
import { Items, NotFound } from './styles';
|
|
4
|
+
import { LocationData } from '@autobusal/providers/types/locations';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
routeId: number
|
|
8
|
+
data?: LocationData[]
|
|
9
|
+
t: TFunction<'normal'>
|
|
10
|
+
onReload: () => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Browse = ({ routeId, data, t, onReload }: Props): JSX.Element => {
|
|
14
|
+
if (data === undefined || data.length === 0) {
|
|
15
|
+
return (
|
|
16
|
+
<NotFound className="box">
|
|
17
|
+
{ t('locations_manage.no_locations', { ns: 'common' }) }
|
|
18
|
+
</NotFound>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const items = data.map(item => (
|
|
23
|
+
<Item
|
|
24
|
+
key={ item.id }
|
|
25
|
+
item={ item }
|
|
26
|
+
routeId={ routeId }
|
|
27
|
+
t={ t }
|
|
28
|
+
onReload={ onReload }
|
|
29
|
+
/>
|
|
30
|
+
));
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<h2>
|
|
35
|
+
{ t('locations_manage.browse', { ns: 'common' }) }
|
|
36
|
+
</h2>
|
|
37
|
+
|
|
38
|
+
<Items>
|
|
39
|
+
{ items }
|
|
40
|
+
</Items>
|
|
41
|
+
</>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default Browse;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { TFunction } from 'i18next';
|
|
2
|
+
import { useForm } from 'react-hook-form';
|
|
3
|
+
import { Validate, Display, success } from '@autobusal/utilities';
|
|
4
|
+
import Actions from './Actions';
|
|
5
|
+
import { getTomorrow } from '../utilities';
|
|
6
|
+
import { Data } from './styles';
|
|
7
|
+
import { LocationForm } from '../types';
|
|
8
|
+
import { LocationData } from '@autobusal/providers/types/locations';
|
|
9
|
+
import { PostMove, DeleteLocation, PostUpdate } from '../services';
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
routeId: number
|
|
13
|
+
item: LocationData
|
|
14
|
+
t: TFunction<'normal'>
|
|
15
|
+
onReload: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const Item = ({ routeId, item, t, onReload }: Props): JSX.Element => {
|
|
19
|
+
const { register, handleSubmit, formState: { errors } } = useForm<LocationForm>();
|
|
20
|
+
|
|
21
|
+
const { mutate: Save, isPending: isPendingUpdate } = PostUpdate(routeId, item.id);
|
|
22
|
+
|
|
23
|
+
const { mutate: Move, isPending: isPendingMove } = PostMove(routeId, item.id);
|
|
24
|
+
|
|
25
|
+
const { mutate: Delete, isPending: isPendingDelete } = DeleteLocation(routeId, item.id);
|
|
26
|
+
|
|
27
|
+
const onSubmit = (data: LocationForm): void => {
|
|
28
|
+
Save(data);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const onMove = (order: number): void => {
|
|
32
|
+
Move(order, {
|
|
33
|
+
onSuccess: () => {
|
|
34
|
+
success(t('locations_manage.messages.moved', { ns: 'common' }));
|
|
35
|
+
|
|
36
|
+
onReload();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const onDelete = (): void => {
|
|
42
|
+
Delete({}, {
|
|
43
|
+
onSuccess: () => {
|
|
44
|
+
success(t('locations_manage.messages.deleted', { ns: 'common' }));
|
|
45
|
+
|
|
46
|
+
onReload();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div className="box">
|
|
53
|
+
<h4>{ item.city.country?.name } › { item.city.name } › { item.stop?.name }</h4>
|
|
54
|
+
|
|
55
|
+
<form onSubmit={ handleSubmit(onSubmit) }>
|
|
56
|
+
<Data>
|
|
57
|
+
<div className="row">
|
|
58
|
+
{ t('locations_manage.city.tomorrow', { ns: 'common' }) }
|
|
59
|
+
|
|
60
|
+
<select defaultValue={ item.tomorrow } { ...register('tomorrow') }>
|
|
61
|
+
{ getTomorrow(t) }
|
|
62
|
+
</select>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div className="row">
|
|
66
|
+
{ t('locations_manage.city.departure', { ns: 'common' }) }
|
|
67
|
+
|
|
68
|
+
<input type="text" defaultValue={ item.departure } { ...register('departure', Validate('required', t)) } />
|
|
69
|
+
{ Display(errors.departure) }
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<div className="row">
|
|
73
|
+
{ t('locations_manage.city.arrival', { ns: 'common' }) }
|
|
74
|
+
|
|
75
|
+
<input type="text" defaultValue={ item.arrival } { ...register('arrival', Validate('required', t)) } />
|
|
76
|
+
{ Display(errors.arrival) }
|
|
77
|
+
</div>
|
|
78
|
+
</Data>
|
|
79
|
+
|
|
80
|
+
<Actions
|
|
81
|
+
item={ item }
|
|
82
|
+
loading={ isPendingMove || isPendingDelete || isPendingUpdate }
|
|
83
|
+
t={ t }
|
|
84
|
+
onMove={ onMove }
|
|
85
|
+
onDelete={ onDelete }
|
|
86
|
+
/>
|
|
87
|
+
</form>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export default Item;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
|
|
3
|
+
export const Items = styled.div`
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
gap: 15px;
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
export const NotFound = styled.div`
|
|
10
|
+
margin-top: 15px;
|
|
11
|
+
padding: 30px 0;
|
|
12
|
+
color: ${ props => props.theme.font.neutral };
|
|
13
|
+
text-align: center;
|
|
14
|
+
font-size: ${ props => props.theme.size.xs };
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export const Data = styled.div`
|
|
18
|
+
display: flex;
|
|
19
|
+
gap: 10px;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
|
|
22
|
+
@media (min-width: 480px) {
|
|
23
|
+
flex-direction: row;
|
|
24
|
+
gap: 15px;
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
export const ContainerActions = styled.div`
|
|
29
|
+
display: flex;
|
|
30
|
+
justify-content: space-between;
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
export const Group = styled.div`
|
|
34
|
+
display: flex;
|
|
35
|
+
gap: 10px;
|
|
36
|
+
`;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { TFunction } from 'i18next';
|
|
2
|
+
import { useParams } from 'react-router-dom';
|
|
3
|
+
import { Meta, BackWithTitle, Report } from '@autobusal/common';
|
|
4
|
+
import { usePage } from '@autobusal/hooks';
|
|
5
|
+
import Add from './Add/Add';
|
|
6
|
+
import Browse from './Browse/Browse';
|
|
7
|
+
import { GetLocations } from './services';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
url: string
|
|
11
|
+
t: TFunction<'common'>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const Manage = ({ url, t }: Props): JSX.Element => {
|
|
15
|
+
const params = useParams();
|
|
16
|
+
|
|
17
|
+
const id = Number(params.id);
|
|
18
|
+
|
|
19
|
+
url = url.replace('[id]', String(id));
|
|
20
|
+
|
|
21
|
+
usePage('routes');
|
|
22
|
+
|
|
23
|
+
const { data, refetch } = GetLocations(id);
|
|
24
|
+
|
|
25
|
+
const onReload = (): void => {
|
|
26
|
+
refetch();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const title = t('locations_manage.title', { name: data?.name, ns: 'common' });
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Meta title={ title }>
|
|
33
|
+
<BackWithTitle title={ title } to={ url } t={ t } />
|
|
34
|
+
|
|
35
|
+
<Add routeId={ id } t={ t } onReload={ onReload } />
|
|
36
|
+
|
|
37
|
+
<Report margin={ 15 } question={ t('locations_manage.report', { ns: 'common' }) } type="location" t={ t } />
|
|
38
|
+
|
|
39
|
+
<Browse routeId={ id } data={ data?.locations } t={ t } onReload={ onReload } />
|
|
40
|
+
</Meta>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default Manage;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { UseMutationResult, UseQueryResult, UseSuspenseQueryResult, useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query';
|
|
2
|
+
import { apiClient } from '@autobusal/providers';
|
|
3
|
+
import { RouteData } from '@autobusal/providers/types/routes';
|
|
4
|
+
import { CountryData } from '@autobusal/providers/types/locations';
|
|
5
|
+
import { AddForm, LocationForm } from './types';
|
|
6
|
+
|
|
7
|
+
export const GetLocations = (id: number): UseSuspenseQueryResult<RouteData> => (
|
|
8
|
+
useSuspenseQuery({
|
|
9
|
+
queryKey: ['operator-locations', { id }],
|
|
10
|
+
queryFn: async () => (
|
|
11
|
+
await apiClient
|
|
12
|
+
.get('/api/locations/operator/get', {
|
|
13
|
+
params: { id }
|
|
14
|
+
})
|
|
15
|
+
.then(response => (
|
|
16
|
+
response.data
|
|
17
|
+
))
|
|
18
|
+
)
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export const GetStops = (routeId: number): UseQueryResult<CountryData[]> => (
|
|
23
|
+
useQuery({
|
|
24
|
+
queryKey: ['operator-stops', { routeId }],
|
|
25
|
+
queryFn: async () => (
|
|
26
|
+
await apiClient
|
|
27
|
+
.get('/api/stops/operator/browse', {
|
|
28
|
+
params: {
|
|
29
|
+
route_id: routeId
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
.then(response => (
|
|
33
|
+
response.data
|
|
34
|
+
))
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export const AddLocation = (id: number): UseMutationResult<void, Error, AddForm, unknown> => (
|
|
40
|
+
useMutation({
|
|
41
|
+
mutationKey: ['operator-locations-add', { id }],
|
|
42
|
+
mutationFn: async (data: AddForm) => {
|
|
43
|
+
await apiClient
|
|
44
|
+
.post('/api/locations/operator/add', {
|
|
45
|
+
...data,
|
|
46
|
+
id
|
|
47
|
+
})
|
|
48
|
+
.then(response => (
|
|
49
|
+
response.data
|
|
50
|
+
))
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
export const PostMove = (id: number, location_id: number): UseMutationResult<void, Error, number, unknown> => (
|
|
56
|
+
useMutation({
|
|
57
|
+
mutationKey: ['operator-locations-move', { id, location_id }],
|
|
58
|
+
mutationFn: async (order: number) => (
|
|
59
|
+
await apiClient
|
|
60
|
+
.post('/api/locations/operator/move', {
|
|
61
|
+
order,
|
|
62
|
+
id,
|
|
63
|
+
location_id
|
|
64
|
+
})
|
|
65
|
+
.then(response => (
|
|
66
|
+
response.data
|
|
67
|
+
))
|
|
68
|
+
)
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
export const DeleteLocation = (id: number, location_id: number): UseMutationResult<void> => (
|
|
73
|
+
useMutation({
|
|
74
|
+
mutationKey: ['operator-locations-delete', { id, location_id }],
|
|
75
|
+
mutationFn: async () => (
|
|
76
|
+
await apiClient
|
|
77
|
+
.delete('/api/locations/operator/delete', {
|
|
78
|
+
params: {
|
|
79
|
+
id,
|
|
80
|
+
location_id
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
.then(response => (
|
|
84
|
+
response.data
|
|
85
|
+
))
|
|
86
|
+
)
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
export const PostUpdate = (id: number, location_id: number): UseMutationResult<void, Error, LocationForm, unknown> => (
|
|
91
|
+
useMutation({
|
|
92
|
+
mutationKey: ['operator-locations-update', { id, location_id }],
|
|
93
|
+
mutationFn: async (data: LocationForm) => (
|
|
94
|
+
await apiClient
|
|
95
|
+
.post('/api/locations/operator/update', {
|
|
96
|
+
...data,
|
|
97
|
+
id,
|
|
98
|
+
location_id
|
|
99
|
+
})
|
|
100
|
+
.then(response => (
|
|
101
|
+
response.data
|
|
102
|
+
))
|
|
103
|
+
)
|
|
104
|
+
})
|
|
105
|
+
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { TFunction } from 'i18next';
|
|
2
|
+
import { CityData, CountryData } from '@autobusal/providers/types/locations';
|
|
3
|
+
|
|
4
|
+
export const getStops = (t: TFunction<'normal'>, countries?: CountryData[]): JSX.Element[] => {
|
|
5
|
+
const options: JSX.Element[] = [
|
|
6
|
+
<option key="-none=" value="">{ t('locations_manage.add_city.choose', { ns: 'common' }) }</option>
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
countries?.forEach(country => {
|
|
10
|
+
options.push(
|
|
11
|
+
<optgroup key={ country.id } label={ country.name }>
|
|
12
|
+
{ getOptions(country.cities) }
|
|
13
|
+
</optgroup>
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return options;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const getOptions = (cities?: CityData[]): JSX.Element[] => {
|
|
21
|
+
const options: JSX.Element[] = [];
|
|
22
|
+
|
|
23
|
+
cities?.forEach(city => {
|
|
24
|
+
city.stops?.forEach(stop => {
|
|
25
|
+
const value = `${ city.id }#${ stop.id }`;
|
|
26
|
+
|
|
27
|
+
options.push(
|
|
28
|
+
<option key={ value } value={ value }>{ city.name } › { stop.name }</option>
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return options;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const getTomorrow = (t: TFunction<'normal'>): JSX.Element[] => {
|
|
37
|
+
const available = [
|
|
38
|
+
{ name: t('locations_manage.tomorrow.same_day', { ns: 'common' }), value: 0 },
|
|
39
|
+
{ name: t('locations_manage.tomorrow.1_day', { ns: 'common' }), value: 1 },
|
|
40
|
+
{ name: t('locations_manage.tomorrow.2_days', { ns: 'common' }), value: 2 },
|
|
41
|
+
{ name: t('locations_manage.tomorrow.3_days', { ns: 'common' }), value: 3 },
|
|
42
|
+
{ name: t('locations_manage.tomorrow.4_days', { ns: 'common' }), value: 4 },
|
|
43
|
+
{ name: t('locations_manage.tomorrow.5_days', { ns: 'common' }), value: 5 },
|
|
44
|
+
{ name: t('locations_manage.tomorrow.6_days', { ns: 'common' }), value: 6 },
|
|
45
|
+
{ name: t('locations_manage.tomorrow.7_days', { ns: 'common' }), value: 7 }
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const options = available.map(item => (
|
|
49
|
+
<option key={ item.value } value={ item.value }>{ item.name }</option>
|
|
50
|
+
));
|
|
51
|
+
|
|
52
|
+
return options;
|
|
53
|
+
};
|
package/Transiting/Countries.tsx
CHANGED
|
@@ -17,7 +17,7 @@ const Countries = ({ transiting, t, onDelete }: Props): JSX.Element => {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const onDeleteConfirm = (id: number): void => {
|
|
20
|
-
if (window.confirm(t('
|
|
20
|
+
if (window.confirm(t('transiting_manage.confirm', { ns: 'confirm' }))) {
|
|
21
21
|
onDelete(id);
|
|
22
22
|
}
|
|
23
23
|
};
|
package/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Browse from './Browse';
|
|
2
2
|
import Manage from './Manage';
|
|
3
|
+
import LocationsManage from './Locations/Manage';
|
|
3
4
|
import SchedulesManage from './Schedule/Manage';
|
|
4
5
|
import TransitingManage from './Transiting/Manage';
|
|
5
6
|
import UnavailableBrowse from './Unavailable/Browse';
|
|
@@ -8,6 +9,7 @@ import UnavailableManage from './Unavailable/Manage';
|
|
|
8
9
|
export {
|
|
9
10
|
Browse,
|
|
10
11
|
Manage,
|
|
12
|
+
LocationsManage,
|
|
11
13
|
SchedulesManage,
|
|
12
14
|
TransitingManage,
|
|
13
15
|
UnavailableBrowse,
|