@autobusal/common 0.0.39 → 0.0.41

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.
Files changed (65) hide show
  1. package/ApiDetails/ApiDetails.tsx +50 -0
  2. package/ApiDetails/Content.tsx +44 -0
  3. package/ApiDetails/Devpos.tsx +139 -0
  4. package/ApiDetails/services.ts +38 -0
  5. package/ApiDetails/types.ts +13 -0
  6. package/Autocomplete/Autocomplete.tsx +1 -1
  7. package/Avatar.tsx +28 -0
  8. package/BackTo.tsx +28 -4
  9. package/Calendar/Calendar.tsx +1 -1
  10. package/ContactInfo/ContactInfo.tsx +40 -0
  11. package/ContactInfo/styles.ts +33 -0
  12. package/File/File.tsx +88 -0
  13. package/File/styles.ts +23 -0
  14. package/IpLogs/IpLogs.tsx +47 -0
  15. package/IpLogs/View.tsx +48 -0
  16. package/IpLogs/services.ts +27 -0
  17. package/IpLogs/styles.ts +10 -0
  18. package/Loading/Loading.tsx +29 -14
  19. package/Loading/styles.ts +9 -0
  20. package/Modal/Modal.tsx +3 -2
  21. package/Pagination/Pagination.tsx +2 -1
  22. package/Passengers/Passengers.tsx +1 -1
  23. package/Password/Password.tsx +4 -2
  24. package/Report/Report.tsx +39 -0
  25. package/Report/Send.tsx +55 -0
  26. package/Report/services.ts +18 -0
  27. package/Report/styles.ts +31 -0
  28. package/Seats/ChooseSeat.tsx +1 -1
  29. package/Seats/Preview.tsx +2 -2
  30. package/Seats/styles.ts +1 -43
  31. package/Table/Actions/Actions.tsx +40 -0
  32. package/Table/Actions/Get.tsx +49 -0
  33. package/Table/Actions/Icon.tsx +54 -0
  34. package/Table/Actions/styles.ts +22 -0
  35. package/Table/Header/Header.tsx +46 -0
  36. package/Table/Header/Sort.tsx +33 -0
  37. package/Table/Header/styles.ts +48 -0
  38. package/Table/Paginate.tsx +34 -0
  39. package/Table/Row.tsx +20 -0
  40. package/Table/Rows/Loading.tsx +22 -0
  41. package/Table/Rows/NotFound.tsx +22 -0
  42. package/Table/Rows/Rows.tsx +62 -0
  43. package/Table/Rows/styles.ts +31 -0
  44. package/Table/Table.tsx +74 -0
  45. package/Table/Top/Search.tsx +36 -0
  46. package/Table/Top/Top.tsx +44 -0
  47. package/Table/Top/styles.ts +32 -0
  48. package/Table/browseUrl.ts +21 -0
  49. package/Table/styles.ts +28 -0
  50. package/Table/types.ts +11 -0
  51. package/Viewer/Actions.tsx +106 -0
  52. package/Viewer/Data.tsx +124 -0
  53. package/Viewer/Item.tsx +35 -0
  54. package/Viewer/Items/CheckboxList.tsx +53 -0
  55. package/Viewer/Items/DatePicker.tsx +70 -0
  56. package/Viewer/Items/Dropdown.tsx +45 -0
  57. package/Viewer/Items/Linked.tsx +27 -0
  58. package/Viewer/Items/TextareaHtml.tsx +56 -0
  59. package/Viewer/Items/styles.ts +73 -0
  60. package/Viewer/Viewer.tsx +71 -0
  61. package/Viewer/styles.ts +58 -0
  62. package/Viewer/types.ts +22 -0
  63. package/index.ts +21 -3
  64. package/package.json +1 -1
  65. package/Pagination/types.ts +0 -12
@@ -0,0 +1,50 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { IoKeySharp } from 'react-icons/io5';
4
+ import { Button, Modal } from '@autobusal/common';
5
+ import Content from './Content';
6
+
7
+ interface Props {
8
+ id?: number
9
+ type: 'devpos'
10
+ t: TFunction<'common'>
11
+ }
12
+
13
+ const ApiDetails = ({ id, type, t }: Props): JSX.Element => {
14
+ const [ show, setShow ] = useState<boolean>(false);
15
+
16
+ if (id === undefined) {
17
+ return <>-</>;
18
+ }
19
+
20
+ return (
21
+ <>
22
+ <Button
23
+ type="button"
24
+ subtype="secondary"
25
+ size="small"
26
+ text={ (
27
+ <>
28
+ <IoKeySharp />
29
+ { t('api_details.manage', { ns: 'common' }) }
30
+ </>
31
+ ) }
32
+ noMargin
33
+ onClick={ () => setShow(true) }
34
+ />
35
+
36
+ { show && (
37
+ <Modal
38
+ width={ 700 }
39
+ title={ t('api_details.title', { ns: 'common', title: type.toUpperCase() }) }
40
+ content={
41
+ <Content id={ id } type={ type } t={ t } />
42
+ }
43
+ onClose={ () => setShow(false) }
44
+ />
45
+ ) }
46
+ </>
47
+ );
48
+ };
49
+
50
+ export default ApiDetails;
@@ -0,0 +1,44 @@
1
+ import { TFunction } from 'i18next';
2
+ import { Paragraph } from '@autobusal/common';
3
+ import DevPos from './Devpos';
4
+ import { GetSettings, PostSettings } from './services';
5
+
6
+ interface Props {
7
+ id: number
8
+ type: 'devpos'
9
+ t: TFunction<'common'>
10
+ }
11
+
12
+ const Content = ({ id, type, t }: Props): JSX.Element => {
13
+ const { data, isFetching } = GetSettings(id, type);
14
+
15
+ const { mutate: SaveSettings, isPending } = PostSettings(id, type);
16
+
17
+ if (isFetching) {
18
+ return <Paragraph count={ 3 } />;
19
+ }
20
+
21
+ if (typeof data === 'string') {
22
+ return (
23
+ <div>{ t('api_details.unavailable', { ns: 'common' }) }</div>
24
+ );
25
+ }
26
+
27
+ const onSave = (data: any) => {
28
+ SaveSettings(data);
29
+ };
30
+
31
+ switch (type) {
32
+ case 'devpos':
33
+ return (
34
+ <DevPos
35
+ data={ data }
36
+ loading={ isPending }
37
+ t={ t }
38
+ onSave={ onSave }
39
+ />
40
+ );
41
+ }
42
+ };
43
+
44
+ export default Content;
@@ -0,0 +1,139 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useForm } from 'react-hook-form';
3
+ import { Button } from '@autobusal/common';
4
+ import { display, validate } from '@autobusal/utilities/form';
5
+ import { ApiDetailsData } from '@modules/Providers/types/users';
6
+ import { DevPosForm } from './types';
7
+
8
+ interface Props {
9
+ data?: ApiDetailsData
10
+ loading: boolean
11
+ t: TFunction<'common'>
12
+ onSave: (data: any) => void
13
+ }
14
+
15
+ const DevPos = ({ data, loading, t, onSave }: Props): JSX.Element => {
16
+ const { register, handleSubmit, formState: { errors } } = useForm<DevPosForm>();
17
+
18
+ const onClick = (): void => {
19
+ handleSubmit(onSave)();
20
+ };
21
+
22
+ const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
23
+ if (event.key === 'Enter') {
24
+ event.preventDefault();
25
+ onClick();
26
+ }
27
+ };
28
+
29
+ return (
30
+ <>
31
+ <div className="column">
32
+ <div className="row">
33
+ { t('api_details.devpos.business_code', { ns: 'common' }) }
34
+
35
+ <input type="text" defaultValue={ data?.business_code } { ...register('business_code', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
36
+
37
+ { display(errors.business_code) }
38
+ </div>
39
+
40
+ <div className="row">
41
+ { t('api_details.devpos.operator_code', { ns: 'common' }) }
42
+
43
+ <input type="text" defaultValue={ data?.operator_code } { ...register('operator_code', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
44
+
45
+ { display(errors.operator_code) }
46
+ </div>
47
+ </div>
48
+
49
+ <div className="column">
50
+ <div className="row">
51
+ { t('api_details.devpos.nuis', { ns: 'common' }) }
52
+
53
+ <input type="text" defaultValue={ data?.nuis } { ...register('nuis', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
54
+
55
+ { display(errors.nuis) }
56
+ </div>
57
+
58
+ <div className="row">
59
+ { t('api_details.devpos.fiscalization_number', { ns: 'common' }) }
60
+
61
+ <input type="text" defaultValue={ data?.fiscalization_number } { ...register('fiscalization_number', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
62
+
63
+ { display(errors.fiscalization_number) }
64
+ </div>
65
+ </div>
66
+
67
+ <div className="column">
68
+ <div className="row">
69
+ { t('api_details.devpos.username', { ns: 'common' }) }
70
+
71
+ <input type="text" defaultValue={ data?.username } { ...register('username', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
72
+
73
+ { display(errors.username) }
74
+ </div>
75
+
76
+ <div className="row">
77
+ { t('api_details.devpos.password', { ns: 'common' }) }
78
+
79
+ <input type="text" defaultValue={ data?.password } { ...register('password', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
80
+
81
+ { display(errors.password) }
82
+ </div>
83
+ </div>
84
+
85
+ <div className="row">
86
+ { t('api_details.devpos.bank_name', { ns: 'common' }) }
87
+
88
+ <input type="text" defaultValue={ data?.bank_name } { ...register('bank_name', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
89
+
90
+ { display(errors.bank_name) }
91
+ </div>
92
+
93
+ <div className="column">
94
+ <div className="row">
95
+ { t('api_details.devpos.bank_swift', { ns: 'common' }) }
96
+
97
+ <input type="text" defaultValue={ data?.bank_swift } { ...register('bank_swift', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
98
+
99
+ { display(errors.bank_swift) }
100
+ </div>
101
+
102
+ <div className="row">
103
+ { t('api_details.devpos.bank_account', { ns: 'common' }) }
104
+
105
+ <input type="text" defaultValue={ data?.bank_account } { ...register('bank_account', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
106
+
107
+ { display(errors.bank_account) }
108
+ </div>
109
+ </div>
110
+
111
+ <div className="column">
112
+ <div className="row">
113
+ { t('api_details.devpos.bank_address', { ns: 'common' }) }
114
+
115
+ <input type="text" defaultValue={ data?.bank_address } { ...register('bank_address', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
116
+
117
+ { display(errors.bank_address) }
118
+ </div>
119
+
120
+ <div className="row">
121
+ { t('api_details.devpos.bank_city', { ns: 'common' }) }
122
+
123
+ <input type="text" defaultValue={ data?.bank_city } { ...register('bank_city', validate('required|min_length:2', t)) } onKeyDown={ onKeyDown } />
124
+
125
+ { display(errors.bank_city) }
126
+ </div>
127
+ </div>
128
+
129
+ <Button
130
+ type="button"
131
+ loading={ loading }
132
+ text={ t('api_details.save', { ns: 'common' }) }
133
+ onClick={ onClick }
134
+ />
135
+ </>
136
+ );
137
+ };
138
+
139
+ export default DevPos;
@@ -0,0 +1,38 @@
1
+ import { useQuery, UseQueryResult, useMutation, UseMutationResult } from '@tanstack/react-query';
2
+ import { apiClient } from '@autobusal/providers';
3
+ import { ApiDetailsData } from '@modules/Providers/types/users';
4
+
5
+ export const GetSettings = (id: number, type: string): UseQueryResult<ApiDetailsData | string> => (
6
+ useQuery({
7
+ queryKey: ['apidetails-get-settings', { id, type }],
8
+ queryFn: async () => (
9
+ await apiClient
10
+ .get('/api/api_details/admin/get', {
11
+ params: {
12
+ id,
13
+ type
14
+ }
15
+ })
16
+ .then(response => (
17
+ response.data
18
+ ))
19
+ )
20
+ })
21
+ );
22
+
23
+ export const PostSettings = (id: number, type: string): UseMutationResult<void> => (
24
+ useMutation({
25
+ mutationKey: ['apidetails-update-settings'],
26
+ mutationFn: async (data: any) => (
27
+ await apiClient
28
+ .post('/api/api_details/admin/update', {
29
+ ...data,
30
+ id,
31
+ type
32
+ })
33
+ .then(response => (
34
+ response.data
35
+ ))
36
+ )
37
+ })
38
+ );
@@ -0,0 +1,13 @@
1
+ export interface DevPosForm {
2
+ business_code: string
3
+ operator_code: string
4
+ nuis: string
5
+ fiscalization_number: string
6
+ username: string
7
+ password: string
8
+ bank_name: string
9
+ bank_swift: string
10
+ bank_account: string
11
+ bank_address: string
12
+ bank_city: string
13
+ }
@@ -27,7 +27,7 @@ const Autocomplete = ({ name, defaultValue, data, validation, t, refs, onUpdate
27
27
  const [ selected, setSelected ] = useState<number>(-1);
28
28
  const [ value, setValue ] = useState<string>(defaultValue);
29
29
 
30
- const ref = useRef(null);
30
+ const ref = useRef<HTMLDivElement>(null);
31
31
 
32
32
  useOutside(ref, () => setShow(false));
33
33
 
package/Avatar.tsx ADDED
@@ -0,0 +1,28 @@
1
+ import styled from 'styled-components';
2
+ import { OperatorData } from '@modules/Providers/types/operators';
3
+ import { AgentData } from '@modules/Providers/types/agents';
4
+
5
+ interface Props {
6
+ display?: OperatorData | AgentData
7
+ }
8
+
9
+ const Avatar = ({ display }: Props): JSX.Element => (
10
+ <Container>
11
+ { display?.logo_url !== '' && <img src={ display?.logo_url } />}
12
+ { display?.company }
13
+ </Container>
14
+ );
15
+
16
+ const Container = styled.div`
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 10px;
20
+
21
+ & > img {
22
+ display: block;
23
+ width: 80px;
24
+ border-radius: ${ props => props.theme.borderRadius };
25
+ }
26
+ `;
27
+
28
+ export default Avatar;
package/BackTo.tsx CHANGED
@@ -15,21 +15,45 @@ const LinkStyled = styled(Link)`
15
15
  padding: 4px 12px;
16
16
  font-size: calc(${ props => props.theme.size.info } - 1px);
17
17
  text-transform: uppercase;
18
- background: ${ props => props.theme.neutral };
18
+ background: ${ props => props.theme.foreground.normal };
19
19
  border-radius: ${ props => props.theme.borderRadius };
20
+ box-shadow: ${ props => props.theme.boxShadow };
20
21
  transition: all 0.3s ease;
21
22
 
22
23
  &:hover {
24
+ opacity: .8;
23
25
  text-decoration: none;
24
- background: ${ props => props.theme.primaryTransparent };
25
26
  }
26
27
  `;
27
28
 
28
- const BackTo = ({ to, t }: Props): JSX.Element => (
29
+ export const BackTo = ({ to, t }: Props): JSX.Element => (
29
30
  <LinkStyled to={ to }>
30
31
  <BiChevronLeftCircle />
31
32
  { t('back', { ns: 'common' }) }
32
33
  </LinkStyled>
33
34
  );
34
35
 
35
- export default BackTo;
36
+ interface TitleProps {
37
+ title: string
38
+ to: string
39
+ t: TFunction<'common'>
40
+ }
41
+
42
+ const ContainerTitle = styled.div`
43
+ display: flex;
44
+ gap: 15px;
45
+ align-items: center;
46
+ margin-bottom: 20px;
47
+
48
+ & > h1 {
49
+ margin-bottom: 0;
50
+ }
51
+ `;
52
+
53
+ export const BackWithTitle = ({ title, to, t }: TitleProps): JSX.Element => (
54
+ <ContainerTitle>
55
+ <BackTo to={ to } t={ t } />
56
+
57
+ <h1>{ title }</h1>
58
+ </ContainerTitle>
59
+ );
@@ -21,7 +21,7 @@ const Calendar = ({ type, name, defaultValue, t, validation, refs, onUpdate }: P
21
21
  const [ prepared, setPrepared ] = useState<string>(defaultValue ?? prepareDate(new Date()));
22
22
  const [ selected, setSelected ] = useState<string>(prepared);
23
23
 
24
- const ref = useRef(null);
24
+ const ref = useRef<HTMLDivElement>(null);
25
25
 
26
26
  useOutside(ref, () => setShow(false));
27
27
 
@@ -0,0 +1,40 @@
1
+ import { TFunction } from 'i18next';
2
+ import { BiTransfer } from 'react-icons/bi';
3
+ import { RiMoneyEuroCircleFill, RiPhoneLine } from 'react-icons/ri';
4
+ import { Container, Funds, LinkMore } from './styles';
5
+
6
+ interface Props {
7
+ item: any
8
+ t: TFunction<'common'>
9
+ }
10
+
11
+ const ContactInfo = ({ item, t }: Props): JSX.Element => {
12
+ const onClick = (event: React.MouseEvent<HTMLAnchorElement>): void => {
13
+ event.stopPropagation();
14
+ };
15
+
16
+ return (
17
+ <Container>
18
+ { item.funds_display && <Funds>{ item.funds_display }</Funds> }
19
+
20
+ { item.mobile && (
21
+ <LinkMore to={ `tel:${ item.mobile }` } onClick={ (event) => onClick(event) }>
22
+ <RiPhoneLine />
23
+ { item.mobile }
24
+ </LinkMore>
25
+ ) }
26
+
27
+ <LinkMore to={ `/admin/funds/manage/${ item.user.id }` } onClick={ (event) => onClick(event) }>
28
+ <RiMoneyEuroCircleFill />
29
+ { t('contact_info.add_funds', { ns: 'common' }) }
30
+ </LinkMore>
31
+
32
+ <LinkMore to={ `/account/transactions?id=${ item.user.id }` } onClick={ (event) => onClick(event) }>
33
+ <BiTransfer />
34
+ { t('contact_info.view_transactions', { ns: 'common' }) }
35
+ </LinkMore>
36
+ </Container>
37
+ );
38
+ };
39
+
40
+ export default ContactInfo;
@@ -0,0 +1,33 @@
1
+ import styled from 'styled-components';
2
+ import { Link } from 'react-router-dom';
3
+
4
+ export const Container = styled.div`
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: 5px;
8
+ `;
9
+
10
+ export const Funds = styled.div`
11
+ font-weight: 700;
12
+ color: ${ props => props.theme.font.info };
13
+ `;
14
+
15
+ export const LinkMore = styled(Link)`
16
+ align-self: center;
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ gap: 5px;
21
+ padding: 2px 5px;
22
+ font-weight: 700;
23
+ font-size: ${ props => props.theme.size.xs };
24
+ border: 1px solid ${ props => props.theme.primary.normal };
25
+ border-radius: ${ props => props.theme.borderRadius };
26
+ transition: all 0.3s ease;
27
+
28
+ &:hover {
29
+ text-decoration: none;
30
+ color: ${ props => props.theme.primary.contrast };
31
+ background: ${ props => props.theme.primary.normal };
32
+ }
33
+ `;
package/File/File.tsx ADDED
@@ -0,0 +1,88 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useState, useRef } from 'react';
3
+ import { UseFormRegister } from 'react-hook-form';
4
+ import { HiOutlineCloudUpload, HiCheck } from 'react-icons/hi';
5
+ import { Modal } from '@autobusal/common';
6
+ import { validate } from '@autobusal/utilities';
7
+ import { Button } from '../Button/Button';
8
+ import { Container, ImgView, ImgPreview } from './styles';
9
+
10
+ interface Props {
11
+ name: string
12
+ value?: string
13
+ validation?: string
14
+ multiple?: boolean
15
+ t: TFunction<'comon'>
16
+ refs: UseFormRegister<any>
17
+ }
18
+
19
+ const File = ({ name, value, validation, multiple, t, refs }: Props): JSX.Element => {
20
+ const [ uploaded, setUploaded ] = useState<boolean>(false);
21
+ const [ preview, setPreview ] = useState<boolean>(false);
22
+
23
+ const inputRef = useRef<HTMLInputElement | null>(null);
24
+
25
+ const rules = validate(String(validation), t);
26
+
27
+ const onChange = (): void => {
28
+ setUploaded(true);
29
+ };
30
+
31
+ // we listen for the change
32
+ rules.onChange = onChange;
33
+
34
+ const { ref, ...rest } = refs(name, rules);
35
+
36
+ const onClick = (): void => {
37
+ if (inputRef.current !== null) {
38
+ inputRef.current.click();
39
+ }
40
+ };
41
+
42
+ const type = multiple ? 'multiple' : 'single';
43
+
44
+ return (
45
+ <>
46
+ <Container>
47
+ <input
48
+ { ...rest }
49
+ type="file"
50
+ name={ name }
51
+ multiple={ multiple }
52
+ style={{ display: 'none' }}
53
+ ref={ (e) => {
54
+ ref(e);
55
+ inputRef.current = e;
56
+ } }
57
+ />
58
+
59
+ <Button
60
+ type="button"
61
+ size="small"
62
+ text={
63
+ uploaded
64
+ ? <><HiCheck /> { t(`file.${ type }.done`, { ns: 'common' }) }</>
65
+ : <><HiOutlineCloudUpload /> { t(`file.${ type }.ready`, { ns: 'common' }) }</>
66
+ }
67
+ noMargin
68
+ onClick={ onClick }
69
+ />
70
+
71
+ { value && <ImgView src={ value } onClick={ () => setPreview(true) } /> }
72
+ </Container>
73
+
74
+ { preview && (
75
+ <Modal
76
+ width={ 500 }
77
+ title={ t('file.preview', { ns: 'common' }) }
78
+ content={ (
79
+ <ImgPreview src={ value } />
80
+ ) }
81
+ onClose={ () => setPreview(false) }
82
+ />
83
+ ) }
84
+ </>
85
+ );
86
+ };
87
+
88
+ export default File;
package/File/styles.ts ADDED
@@ -0,0 +1,23 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: space-between;
7
+ gap: 10px;
8
+ height: 38px;
9
+ `;
10
+
11
+ export const ImgView = styled.img`
12
+ display: block;
13
+ height: 38px;
14
+ padding: 4px;
15
+ border: 1px solid ${ props => props.theme.background.neutral };
16
+ border-radius: ${ props => props.theme.borderRadius };
17
+ cursor: pointer;
18
+ `;
19
+
20
+ export const ImgPreview = styled.img`
21
+ display: block;
22
+ width: 100%;
23
+ `;
@@ -0,0 +1,47 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useState } from 'react';
3
+ import { AiOutlineLogin } from 'react-icons/ai';
4
+ import { Button } from '@autobusal/common';
5
+ import View from './View';
6
+ import { NotAvailable } from './styles';
7
+
8
+ interface Props {
9
+ id: number
10
+ page: number
11
+ type: 'admins' | 'financers' | 'operators' | 'visitors'
12
+ t: TFunction<'common'>
13
+ }
14
+
15
+ const IpLogs = ({ id, page, type, t }: Props): (JSX.Element | string) => {
16
+ const [ show, setShow ] = useState<boolean>(false);
17
+
18
+ if (id == 0) {
19
+ return (
20
+ <NotAvailable>
21
+ { t('ip_logs.not_available', { ns: 'common' }) }
22
+ </NotAvailable>
23
+ );
24
+ }
25
+
26
+ return (
27
+ <>
28
+ <Button
29
+ type="button"
30
+ subtype="secondary"
31
+ size="small"
32
+ text={ (
33
+ <>
34
+ <AiOutlineLogin />
35
+ { t('ip_logs.view', { ns: 'common' }) }
36
+ </>
37
+ ) }
38
+ noMargin
39
+ onClick={ () => setShow(true) }
40
+ />
41
+
42
+ { show && <View id={ id } page={ page } type={ type } t={ t } /> }
43
+ </>
44
+ );
45
+ };
46
+
47
+ export default IpLogs;
@@ -0,0 +1,48 @@
1
+ import { TFunction } from 'i18next';
2
+ import Table from '@modules/Common/Table/Table';
3
+ import Row from '@modules/Common/Table/Row';
4
+ import { Container } from './styles';
5
+ import { GetLogs } from './services';
6
+
7
+ interface Props {
8
+ id: number
9
+ page: number
10
+ type: 'admins' | 'financers'
11
+ t: TFunction<'common'>
12
+ }
13
+
14
+ const View = ({ id, page, type, t }: Props): JSX.Element => {
15
+ const { data, isFetching } = GetLogs(id, type, page);
16
+
17
+ const rows = data?.data.map(item => (
18
+ <Row
19
+ key={ item.id }
20
+ id={ item.id }
21
+ data={ [
22
+ item.ip,
23
+ item.created_at
24
+ ] }
25
+ />
26
+ ));
27
+
28
+ return (
29
+ <Container>
30
+ <Table
31
+ url={ `/admin/${ type }/manage/${ id }` }
32
+ columns={ [{
33
+ name: t('ip_logs.ip', { ns: 'common' }),
34
+ width: 80
35
+ }, {
36
+ name: t('ip_logs.date', { ns: 'common' }),
37
+ width: 20
38
+ }] }
39
+ rows={ rows }
40
+ pages={ data }
41
+ loading={ isFetching }
42
+ t={ t }
43
+ />
44
+ </Container>
45
+ );
46
+ };
47
+
48
+ export default View;