@autobusal/operator-routes 1.0.2 → 1.0.4

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.
@@ -0,0 +1,42 @@
1
+ import { TFunction } from 'i18next';
2
+ import { BiTrash } from 'react-icons/bi';
3
+ import { Container, Item, ButtonDelete } from './styles';
4
+ import { TransitingData } from '@autobusal/providers/types/routes';
5
+
6
+ interface Props {
7
+ transiting: TransitingData[]
8
+ t: TFunction<'normal'>
9
+ onDelete: (id: number) => void
10
+ }
11
+
12
+ const Countries = ({ transiting, t, onDelete }: Props): JSX.Element => {
13
+ if (transiting.length == 0) {
14
+ return (
15
+ <>-</>
16
+ );
17
+ }
18
+
19
+ const onDeleteConfirm = (id: number): void => {
20
+ if (window.confirm(t('private.transiting_manage.confirm'))) {
21
+ onDelete(id);
22
+ }
23
+ };
24
+
25
+ const items = transiting.map(item => (
26
+ <Item key={ item.id }>
27
+ { item.country.name }
28
+
29
+ <ButtonDelete type="button" onClick={ () => onDeleteConfirm(item.country.id) }>
30
+ <BiTrash />
31
+ </ButtonDelete>
32
+ </Item>
33
+ ));
34
+
35
+ return (
36
+ <Container>
37
+ { items }
38
+ </Container>
39
+ );
40
+ };
41
+
42
+ export default Countries;
@@ -0,0 +1,93 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useParams, Navigate } from 'react-router-dom';
3
+ import { Meta, BackWithTitle, Viewer, Box } from '@autobusal/common';
4
+ import { usePage, useCountries } from '@autobusal/hooks';
5
+ import { success } from '@autobusal/utilities';
6
+ import Countries from './Countries';
7
+ import { filterCountries } from './utilities';
8
+ import { TransitingData } from '@autobusal/providers/types/routes';
9
+ import { GetTransiting, PostTransiting, DeleteTransiting } from './services';
10
+
11
+ interface Props {
12
+ url: string
13
+ t: TFunction<'common'>
14
+ }
15
+
16
+ const Manage = ({ url, t }: Props): JSX.Element => {
17
+ const params = useParams();
18
+
19
+ const id = Number(params.id);
20
+
21
+ url = url.replace('[id]', String(id));
22
+
23
+ usePage('routes');
24
+
25
+ const { data: CountriesData, isLoading } = useCountries('available');
26
+
27
+ const { data, refetch } = GetTransiting(id);
28
+
29
+ const { mutate: Update, isPending: isPendingSave } = PostTransiting(id);
30
+
31
+ const { mutate: Delete, isPending: isPendingDelete } = DeleteTransiting(id);
32
+
33
+ if (id === 0) {
34
+ return <Navigate to={ url } />;
35
+ }
36
+
37
+ if (isLoading) {
38
+ return <Box />;
39
+ }
40
+
41
+ const onSave = (data: TransitingData): void => {
42
+ Update(data, {
43
+ onSuccess: () => {
44
+ success(t('transiting_manage.messages.saved', { ns: 'common' }));
45
+
46
+ refetch();
47
+ }
48
+ });
49
+ };
50
+
51
+ const onDelete = (id: number): void => {
52
+ Delete(id, {
53
+ onSuccess: () => {
54
+ success(t('transiting_manage.messages.deleted', { ns: 'common' }));
55
+
56
+ refetch();
57
+ }
58
+ });
59
+ };
60
+
61
+ const title = t('transiting_manage.title', { name: data?.name, ns: 'common' });
62
+
63
+ return (
64
+ <Meta title={ title }>
65
+ <BackWithTitle title={ title } to={ url } t={ t } />
66
+
67
+ <Viewer
68
+ id={ id }
69
+ data={ [{
70
+ label: t('transiting_manage.transiting', { ns: 'common' }),
71
+ type: 'component',
72
+ name: 'transiting',
73
+ value: <Countries transiting={ data?.transiting ?? [] } t={ t } onDelete={ onDelete } />
74
+ }, {}, {
75
+ label: t('transiting_manage.countries', { ns: 'common' }),
76
+ name: 'country_id',
77
+ type: 'select',
78
+ values: filterCountries(data?.transiting ?? [], CountriesData),
79
+ value: 0,
80
+ rules: 'required|min:1'
81
+ }] }
82
+ pending={ isPendingSave || isPendingDelete }
83
+ t={ t }
84
+ actions={ [
85
+ 'add'
86
+ ]}
87
+ onSave={ onSave }
88
+ />
89
+ </Meta>
90
+ );
91
+ };
92
+
93
+ export default Manage;
@@ -0,0 +1,52 @@
1
+ import { UseMutationResult, UseSuspenseQueryResult, useMutation, useSuspenseQuery } from '@tanstack/react-query';
2
+ import { apiClient } from '@autobusal/providers';
3
+ import { RouteData, TransitingData } from '@autobusal/providers/types/routes';
4
+
5
+ export const GetTransiting = (id: number): UseSuspenseQueryResult<RouteData> => (
6
+ useSuspenseQuery({
7
+ queryKey: ['operator-transiting', { id }],
8
+ queryFn: async () => (
9
+ await apiClient
10
+ .get('/api/transiting/operator/browse', {
11
+ params: { id }
12
+ })
13
+ .then(response => (
14
+ response.data
15
+ ))
16
+ )
17
+ })
18
+ );
19
+
20
+ export const PostTransiting = (id: number): UseMutationResult<void, Error, TransitingData, unknown> => (
21
+ useMutation({
22
+ mutationKey: ['operator-transiting-save', { id }],
23
+ mutationFn: async (data: TransitingData) => (
24
+ await apiClient
25
+ .post('/api/transiting/operator/update', {
26
+ ...data,
27
+ id
28
+ })
29
+ .then(response => (
30
+ response.data
31
+ ))
32
+ )
33
+ })
34
+ );
35
+
36
+ export const DeleteTransiting = (id: number): UseMutationResult<void, Error, number, unknown> => (
37
+ useMutation({
38
+ mutationKey: ['operator-transiting-delete'],
39
+ mutationFn: async (countryId: number) => (
40
+ await apiClient
41
+ .delete('/api/transiting/operator/delete', {
42
+ params: {
43
+ id,
44
+ country_id: countryId
45
+ }
46
+ })
47
+ .then(response => (
48
+ response.data
49
+ ))
50
+ )
51
+ })
52
+ );
@@ -0,0 +1,28 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 5px;
7
+ `;
8
+
9
+ export const Item = styled.div`
10
+ display: flex;
11
+ justify-content: space-between;
12
+ align-items: center;
13
+ gap: 10px;
14
+ padding: 7px 10px;
15
+ font-weight: 700;
16
+ border: 1px solid ${ props => props.theme.background.neutral };
17
+ border-radius: ${ props => props.theme.borderRadius };
18
+ `;
19
+
20
+ export const ButtonDelete = styled.button`
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ width: 24px;
25
+ height: 24px;
26
+ color: ${ props => props.theme.font.error };
27
+ font-size: ${ props => props.theme.size.l };
28
+ `;
@@ -0,0 +1,11 @@
1
+ import { CountryData } from '@autobusal/providers/types/locations';
2
+ import { DropdownData } from '@autobusal/providers/types/other';
3
+ import { TransitingData } from '@autobusal/providers/types/routes';
4
+
5
+ export const filterCountries = (transiting: TransitingData[], countries?: CountryData[]): DropdownData[] => {
6
+ const ids = transiting.map(item => item.country.id);
7
+
8
+ const available = countries?.filter(item => !ids.includes(item.id));
9
+
10
+ return available ?? [];
11
+ };
@@ -0,0 +1,72 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useParams, Navigate } from 'react-router-dom';
3
+ import { Meta, BackWithTitle, Table, Row } from '@autobusal/common';
4
+ import { usePage } from '@autobusal/hooks';
5
+ import { GetUnavailableDates, DeleteUnavailable } from './services';
6
+
7
+ interface Props {
8
+ url: string
9
+ t: TFunction<'common'>
10
+ }
11
+
12
+ const Browse = ({ url, t }: Props): JSX.Element => {
13
+ const params = useParams();
14
+
15
+ const id = Number(params.id);
16
+
17
+ url = url.replace('[id]', String(id));
18
+
19
+ usePage('routes');
20
+
21
+ const { data, isLoading, isFetching, refetch } = GetUnavailableDates(id);
22
+
23
+ const { mutate: Delete } = DeleteUnavailable(id);
24
+
25
+ if (id === 0) {
26
+ return <Navigate to={ url } />;
27
+ }
28
+
29
+ const onDelete = (id: number): void => {
30
+ Delete(id, {
31
+ onSuccess: () => refetch()
32
+ });
33
+ };
34
+
35
+ const rows = data?.unavailable.map(item => (
36
+ <Row
37
+ key={ item.id }
38
+ id={ item.id }
39
+ data={ [
40
+ `${ item.start_inactive } - ${ item.end_inactive }`
41
+ ] }
42
+ />
43
+ ));
44
+
45
+ const title = t('unavailable.browse.title', { name: data?.name, ns: 'common' });
46
+
47
+ return (
48
+ <Meta title={ title }>
49
+ <BackWithTitle title={ title } to={ url } t={ t } />
50
+
51
+ <Table
52
+ url={ `/operator/routes/unavailable/${ id }` }
53
+ columns={ [{
54
+ name: t('unavailable.browse.date', { ns: 'common' }),
55
+ width: 90
56
+ }] }
57
+ rows={ rows }
58
+ loading={ isLoading }
59
+ fetching={ isFetching }
60
+ t={ t }
61
+ actions={ [
62
+ 'create', 'view', 'delete'
63
+ ] }
64
+ handlers={ {
65
+ delete: onDelete
66
+ } }
67
+ />
68
+ </Meta>
69
+ );
70
+ };
71
+
72
+ export default Browse;
@@ -0,0 +1,91 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useParams, Navigate, useNavigate } from 'react-router-dom';
3
+ import { Meta, BackWithTitle, Viewer } from '@autobusal/common';
4
+ import { usePage } from '@autobusal/hooks';
5
+ import { success } from '@autobusal/utilities';
6
+ import { UnavailableData } from '@autobusal/providers/types/routes';
7
+ import { GetUnavailable, PostUnavailable, DeleteUnavailable } 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
+ const routeId = Number(params.route_id);
19
+
20
+ url = url.replace('[routeId]', String(routeId));
21
+
22
+ usePage('routes');
23
+
24
+ const navigate = useNavigate();
25
+
26
+ const { data } = GetUnavailable(routeId, id);
27
+
28
+ const { mutate: Update, isPending: isPendingSave } = PostUnavailable(routeId, id);
29
+
30
+ const { mutate: Delete, isPending: isPendingDelete } = DeleteUnavailable(routeId);
31
+
32
+ if (routeId === 0) {
33
+ return <Navigate to={ url } />;
34
+ }
35
+
36
+ const onSave = (data: UnavailableData): void => {
37
+ Update(data, {
38
+ onSuccess: () => {
39
+ success(t('unavailable.manage.messages.saved', { ns: 'common' }));
40
+
41
+ navigate(url);
42
+ }
43
+ });
44
+ };
45
+
46
+ const onDelete = (): void => {
47
+ Delete(id, {
48
+ onSuccess: () => {
49
+ success(t('unavailable.manage.messages.deleted', { ns: 'common' }));
50
+
51
+ navigate(url);
52
+ }
53
+ });
54
+ };
55
+
56
+ const title = id > 0 ? t('unavailable.manage.title.update', { name: data?.name, ns: 'common' }) : t('unavailable.manage.title.new', { name: data?.name, ns: 'common' });
57
+
58
+ const unavailable = data?.unavailable !== undefined && data.unavailable.length > 0 ? data.unavailable[0] : undefined;
59
+
60
+ return (
61
+ <Meta title={ title }>
62
+ <BackWithTitle title={ title } to={ url } t={ t } />
63
+
64
+ <Viewer
65
+ id={ id }
66
+ data={ [{
67
+ label: t('unavailable.manage.start_inactive', { ns: 'common' }),
68
+ name: 'start_inactive',
69
+ type: 'picker',
70
+ value: unavailable?.start_inactive,
71
+ rules: 'required'
72
+ }, {
73
+ label: t('unavailable.manage.end_inactive', { ns: 'common' }),
74
+ name: 'end_inactive',
75
+ type: 'picker',
76
+ value: unavailable?.end_inactive,
77
+ rules: 'required'
78
+ }] }
79
+ pending={ isPendingSave || isPendingDelete }
80
+ t={ t }
81
+ actions={ [
82
+ 'save', 'delete'
83
+ ]}
84
+ onSave={ onSave }
85
+ onDelete={ onDelete }
86
+ />
87
+ </Meta>
88
+ );
89
+ };
90
+
91
+ export default Manage;
@@ -0,0 +1,72 @@
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 { UnavailableData } from '@autobusal/providers/types/routes';
5
+
6
+ export const GetUnavailableDates = (id: number): UseQueryResult<RouteData> => (
7
+ useQuery({
8
+ queryKey: ['operators-unavailable', { id }],
9
+ queryFn: async () => (
10
+ await apiClient
11
+ .get('/api/unavailable/operator/browse', {
12
+ params: { id }
13
+ })
14
+ .then(response => (
15
+ response.data
16
+ ))
17
+ )
18
+ })
19
+ );
20
+
21
+ export const GetUnavailable = (routeId: number, id: number): UseSuspenseQueryResult<RouteData> => (
22
+ useSuspenseQuery({
23
+ queryKey: ['operator-unavailable-manage', { routeId, id }],
24
+ queryFn: async () => (
25
+ await apiClient
26
+ .get('/api/unavailable/operator/get', {
27
+ params: {
28
+ route_id: routeId,
29
+ id
30
+ }
31
+ })
32
+ .then(response => (
33
+ response.data
34
+ ))
35
+ )
36
+ })
37
+ );
38
+
39
+ export const PostUnavailable = (routeId: number, id: number): UseMutationResult<void, Error, UnavailableData, unknown> => (
40
+ useMutation({
41
+ mutationKey: ['unavailable-operator-save', { routeId, id }],
42
+ mutationFn: async (data: UnavailableData) => (
43
+ await apiClient
44
+ .post('/api/unavailable/operator/update', {
45
+ ...data,
46
+ route_id: routeId,
47
+ id
48
+ })
49
+ .then(response => (
50
+ response.data
51
+ ))
52
+ )
53
+ })
54
+ );
55
+
56
+ export const DeleteUnavailable = (routeId: number): UseMutationResult<void, Error, number, unknown> => (
57
+ useMutation({
58
+ mutationKey: ['unavailable-operator-delete', { routeId }],
59
+ mutationFn: async (id: number) => (
60
+ await apiClient
61
+ .delete('/api/unavailable/operator/delete', {
62
+ params: {
63
+ route_id: routeId,
64
+ id
65
+ }
66
+ })
67
+ .then(response => (
68
+ response.data
69
+ ))
70
+ )
71
+ })
72
+ );
package/index.ts CHANGED
@@ -1,9 +1,15 @@
1
1
  import Browse from './Browse';
2
2
  import Manage from './Manage';
3
3
  import SchedulesManage from './Schedule/Manage';
4
+ import TransitingManage from './Transiting/Manage';
5
+ import UnavailableBrowse from './Unavailable/Browse';
6
+ import UnavailableManage from './Unavailable/Manage';
4
7
 
5
8
  export {
6
9
  Browse,
7
10
  Manage,
8
- SchedulesManage
11
+ SchedulesManage,
12
+ TransitingManage,
13
+ UnavailableBrowse,
14
+ UnavailableManage
9
15
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/operator-routes",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "main": "index.ts"
6
6
  }