@autobusal/admin-api-consumers 1.0.0

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/Browse.tsx ADDED
@@ -0,0 +1,93 @@
1
+ import { TFunction } from 'i18next';
2
+ import { useSearchParams } from 'react-router-dom';
3
+ import { Meta, Table, Row } from '@autobusal/common';
4
+ import { usePage, useBreadcrumbs } from '@autobusal/hooks';
5
+ import { DisplayStatus, getParams, success } from '@autobusal/utilities';
6
+ import { useGetApiConsumers, useDeleteApiConsumer } from './services';
7
+
8
+ interface Props {
9
+ url: string
10
+ t: TFunction<'common'>
11
+ }
12
+
13
+ const Browse = ({ url, t }: Props): JSX.Element => {
14
+ const [ searchParams ] = useSearchParams();
15
+
16
+ usePage('api_consumers');
17
+
18
+ useBreadcrumbs(t('admin_api_consumers.browse.title', { ns: 'common' }));
19
+
20
+ const { data, isLoading, isFetching, refetch } = useGetApiConsumers(getParams(searchParams, ['page', 'sort', 'order', 'q']));
21
+
22
+ const { mutate: Delete } = useDeleteApiConsumer();
23
+
24
+ const onDelete = (id: number): void => {
25
+ Delete(id, {
26
+ onSuccess: () => {
27
+ success(t('admin_api_consumers.manage.messages.deleted', { ns: 'common' }));
28
+
29
+ refetch();
30
+ }
31
+ });
32
+ };
33
+
34
+ const rows = data?.data.map(item => (
35
+ <Row
36
+ key={ item.id }
37
+ id={ item.id }
38
+ data={ [
39
+ item.company,
40
+ item.user.email,
41
+ item.operators.includes('all') ? t('admin_api_consumers.browse.all_operators', { ns: 'common' }) : String(item.operators.length),
42
+ item.external_providers.length > 0 ? item.external_providers.join(', ') : '-',
43
+ DisplayStatus(item.user.status, t)
44
+ ] }
45
+ />
46
+ ));
47
+
48
+ return (
49
+ <Meta title={ t('admin_api_consumers.browse.title', { ns: 'common' }) }>
50
+ <h1>{ t('admin_api_consumers.browse.title', { ns: 'common' }) }</h1>
51
+
52
+ <Table
53
+ url={ url }
54
+ columns={ [{
55
+ name: t('admin_api_consumers.browse.company', { ns: 'common' }),
56
+ width: 25,
57
+ slug: 'company',
58
+ type: 'az'
59
+ }, {
60
+ name: t('admin_api_consumers.browse.email', { ns: 'common' }),
61
+ width: 25
62
+ }, {
63
+ name: t('admin_api_consumers.browse.operators', { ns: 'common' }),
64
+ width: 18
65
+ }, {
66
+ name: t('admin_api_consumers.browse.external_providers', { ns: 'common' }),
67
+ width: 18
68
+ }, {
69
+ name: t('admin_api_consumers.browse.status', { ns: 'common' }),
70
+ width: 14
71
+ }] }
72
+ rows={ rows }
73
+ pages={ data }
74
+ sorting={ {
75
+ slug: 'company',
76
+ order: 'asc'
77
+ } }
78
+ search={ searchParams.get('q') }
79
+ loading={ isLoading }
80
+ fetching={ isFetching }
81
+ t={ t }
82
+ actions={ [
83
+ 'create', 'search', 'view', 'delete'
84
+ ] }
85
+ handlers={ {
86
+ delete: onDelete
87
+ } }
88
+ />
89
+ </Meta>
90
+ );
91
+ };
92
+
93
+ export default Browse;
package/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@autobusal/admin-api-consumers` are documented here.
4
+ This project adheres to [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
5
+ and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [1.0.0] - 2026-07-27
8
+
9
+ ### Added
10
+
11
+ - Initial release. Admin GUI for third-party API Consumers (agent-type
12
+ users authenticating with a Sanctum token against `/api/partners/*`),
13
+ replacing the artisan-only `make:user_api` command (obtapi
14
+ `App\Http\Controllers\ApiConsumers\AdminController`). Create with
15
+ one-time token reveal, edit company/status/operators allowlist/external-
16
+ providers allowlist/commission rates, enable-disable without touching
17
+ the token, revoke, and regenerate (old token invalidated, new one
18
+ revealed once). Deliberately relaxed validation vs the regular agents
19
+ admin - no nipt/license/address/mobile/subscription required, since an
20
+ API consumer has no storefront presence.
package/Manage.tsx ADDED
@@ -0,0 +1,178 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { useParams, useNavigate } from 'react-router-dom';
4
+ import { Meta, BackWithTitle, Viewer, Box } from '@autobusal/common';
5
+ import { usePage, useBreadcrumbs, useOperators } from '@autobusal/hooks';
6
+ import { GetStatus, getAllowed, success } from '@autobusal/utilities';
7
+ import { useGetApiConsumer, usePostApiConsumer, useDeleteApiConsumer, useGetProviders } from './services';
8
+ import TokenManager from './TokenManager';
9
+ import TokenRevealModal from './TokenRevealModal';
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
+ usePage('api_consumers');
22
+
23
+ const navigate = useNavigate();
24
+
25
+ const [ revealToken, setRevealToken ] = useState<string | null>(null);
26
+
27
+ const operators = useOperators();
28
+
29
+ const { data: providers, isLoading: isLoadingProviders } = useGetProviders();
30
+
31
+ const { data, isFetching } = useGetApiConsumer(id);
32
+
33
+ const title = id > 0 ? t('admin_api_consumers.manage.title.update', { company: data?.company, ns: 'common' }) : t('admin_api_consumers.manage.title.new', { ns: 'common' });
34
+
35
+ useBreadcrumbs(title, [{ name: t('admin_api_consumers.browse.title', { ns: 'common' }), url }]);
36
+
37
+ const { mutate: Update, isPending: isPendingSave } = usePostApiConsumer(id);
38
+
39
+ const { mutate: Delete, isPending: isPendingDelete } = useDeleteApiConsumer();
40
+
41
+ if (isLoadingProviders) {
42
+ return <Box />;
43
+ }
44
+
45
+ const onSave = (formData: Record<string, any>): void => {
46
+ Update(formData, {
47
+ onSuccess: (response) => {
48
+ success(t('admin_api_consumers.manage.messages.saved', { ns: 'common' }));
49
+
50
+ // one-time token reveal on create - hold the navigation until the
51
+ // admin has seen/copied it, since it can never be shown again
52
+ if (response.api_token) {
53
+ setRevealToken(response.api_token);
54
+
55
+ return;
56
+ }
57
+
58
+ navigate(url);
59
+ }
60
+ });
61
+ };
62
+
63
+ const onDelete = (): void => {
64
+ Delete(id, {
65
+ onSuccess: () => {
66
+ success(t('admin_api_consumers.manage.messages.deleted', { ns: 'common' }));
67
+
68
+ navigate(url);
69
+ }
70
+ });
71
+ };
72
+
73
+ return (
74
+ <Meta title={ title }>
75
+ <BackWithTitle title={ title } to={ url } t={ t } />
76
+
77
+ <Viewer
78
+ id={ id }
79
+ data={ [{
80
+ label: t('admin_api_consumers.manage.company', { ns: 'common' }),
81
+ name: 'company',
82
+ type: 'text',
83
+ value: data?.company,
84
+ rules: 'required|min_length:2|max_length:255'
85
+ }, {}, {
86
+ label: t('admin_api_consumers.manage.email', { ns: 'common' }),
87
+ name: 'email',
88
+ type: 'email',
89
+ value: data?.user.email,
90
+ rules: id === 0 ? 'required' : undefined
91
+ }, {
92
+ label: t('admin_api_consumers.manage.password', { ns: 'common' }),
93
+ name: 'password',
94
+ type: 'password',
95
+ rules: id === 0 ? 'required|min_length:6' : undefined
96
+ }, {}, {
97
+ label: t('admin_api_consumers.manage.operators', { ns: 'common' }),
98
+ name: 'operators',
99
+ type: 'checkbox-list-all',
100
+ selected: data?.operators,
101
+ values: operators
102
+ }, {
103
+ label: t('admin_api_consumers.manage.external_providers', { ns: 'common' }),
104
+ name: 'external_providers',
105
+ type: 'checkbox-list-all',
106
+ selected: data?.external_providers,
107
+ values: providers
108
+ }, {}, {
109
+ label: t('admin_api_consumers.manage.departure', { ns: 'common' }),
110
+ name: 'departure',
111
+ type: 'text',
112
+ value: data?.user.comissions?.departure_edit
113
+ }, {
114
+ label: t('admin_api_consumers.manage.departure_self', { ns: 'common' }),
115
+ name: 'departure_self',
116
+ type: 'text',
117
+ value: data?.user.comissions?.departure_self_edit
118
+ }, {}, {
119
+ label: t('admin_api_consumers.manage.return', { ns: 'common' }),
120
+ name: 'return',
121
+ type: 'text',
122
+ value: data?.user.comissions?.return_edit
123
+ }, {
124
+ label: t('admin_api_consumers.manage.return_self', { ns: 'common' }),
125
+ name: 'return_self',
126
+ type: 'text',
127
+ value: data?.user.comissions?.return_self_edit
128
+ }, {}, {
129
+ label: t('admin_api_consumers.manage.unique', { ns: 'common' }),
130
+ name: 'unique',
131
+ type: 'select',
132
+ value: data?.user.comissions?.unique ?? 0,
133
+ values: getAllowed(t)
134
+ }, {
135
+ label: t('admin_api_consumers.manage.status', { ns: 'common' }),
136
+ name: 'status',
137
+ type: 'select',
138
+ value: data?.user.status ?? 1,
139
+ values: GetStatus(t)
140
+ }, {}, ...(id > 0 ? [{
141
+ label: t('admin_api_consumers.manage.token', { ns: 'common' }),
142
+ name: 'token_manager',
143
+ type: 'component' as const,
144
+ value: (
145
+ <TokenManager
146
+ id={ id }
147
+ hasToken={ data?.user.api?.has_token ?? false }
148
+ enabled={ data?.user.api?.api ?? 0 }
149
+ t={ t }
150
+ />
151
+ )
152
+ }] : [])] }
153
+ fetching={ isFetching }
154
+ pending={ isPendingSave || isPendingDelete }
155
+ t={ t }
156
+ actions={
157
+ id > 0 ? ['save', 'delete'] : ['save']
158
+ }
159
+ onSave={ onSave }
160
+ onDelete={ onDelete }
161
+ />
162
+
163
+ { revealToken && (
164
+ <TokenRevealModal
165
+ token={ revealToken }
166
+ t={ t }
167
+ onClose={ () => {
168
+ setRevealToken(null);
169
+
170
+ navigate(url);
171
+ } }
172
+ />
173
+ ) }
174
+ </Meta>
175
+ );
176
+ };
177
+
178
+ export default Manage;
@@ -0,0 +1,105 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { FiRefreshCw, FiSlash } from 'react-icons/fi';
4
+ import { Button } from '@autobusal/common';
5
+ import { success } from '@autobusal/utilities';
6
+ import { TokenStatus, TokenActions } from './styles';
7
+ import TokenRevealModal from './TokenRevealModal';
8
+ import { useToggleApiConsumer, useRevokeApiConsumerToken, useRegenerateApiConsumerToken } from './services';
9
+
10
+ interface Props {
11
+ id: number
12
+ hasToken: boolean
13
+ enabled: number
14
+ t: TFunction<'common'>
15
+ }
16
+
17
+ // Edited: Ferjolt Ozuni - Date: 2026-07-27
18
+ // Embedded widget (same convention as ApiDetails/IpLogs in the shared
19
+ // agents-manage form) for the token lifecycle - kept separate from the
20
+ // main Viewer save action since these are immediate, independent
21
+ // operations (toggling/revoking/regenerating shouldn't require also
22
+ // saving the rest of the form).
23
+ const TokenManager = ({ id, hasToken, enabled, t }: Props): JSX.Element => {
24
+ const [ reveal, setReveal ] = useState<string | null>(null);
25
+
26
+ const { mutate: Toggle, isPending: isPendingToggle } = useToggleApiConsumer();
27
+ const { mutate: Revoke, isPending: isPendingRevoke } = useRevokeApiConsumerToken();
28
+ const { mutate: Regenerate, isPending: isPendingRegenerate } = useRegenerateApiConsumerToken();
29
+
30
+ const onToggle = (): void => {
31
+ Toggle({ id, api: enabled === 1 ? 0 : 1 }, {
32
+ onSuccess: () => success(t('admin_api_consumers.token.messages.updated', { ns: 'common' }))
33
+ });
34
+ };
35
+
36
+ const onRevoke = (): void => {
37
+ if (!window.confirm(t('admin_api_consumers.token.confirm_revoke', { ns: 'common' }))) {
38
+ return;
39
+ }
40
+
41
+ Revoke(id, {
42
+ onSuccess: () => success(t('admin_api_consumers.token.messages.revoked', { ns: 'common' }))
43
+ });
44
+ };
45
+
46
+ const onRegenerate = (): void => {
47
+ if (hasToken && !window.confirm(t('admin_api_consumers.token.confirm_regenerate', { ns: 'common' }))) {
48
+ return;
49
+ }
50
+
51
+ Regenerate(id, {
52
+ onSuccess: (data) => setReveal(data.api_token)
53
+ });
54
+ };
55
+
56
+ return (
57
+ <>
58
+ <TokenStatus>
59
+ { hasToken
60
+ ? t('admin_api_consumers.token.has_token', { ns: 'common' })
61
+ : t('admin_api_consumers.token.no_token', { ns: 'common' }) }
62
+
63
+ <Button
64
+ type="button"
65
+ size="small"
66
+ subtype={ enabled === 1 ? 'delete' : undefined }
67
+ noMargin
68
+ loading={ isPendingToggle }
69
+ text={ t(enabled === 1 ? 'admin_api_consumers.token.disable' : 'admin_api_consumers.token.enable', { ns: 'common' }) }
70
+ onClick={ onToggle }
71
+ />
72
+ </TokenStatus>
73
+
74
+ <TokenActions>
75
+ <Button
76
+ type="button"
77
+ size="small"
78
+ subtype="secondary"
79
+ noMargin
80
+ loading={ isPendingRegenerate }
81
+ text={ <><FiRefreshCw /> { t('admin_api_consumers.token.regenerate', { ns: 'common' }) }</> }
82
+ onClick={ onRegenerate }
83
+ />
84
+
85
+ { hasToken && (
86
+ <Button
87
+ type="button"
88
+ size="small"
89
+ subtype="delete"
90
+ noMargin
91
+ loading={ isPendingRevoke }
92
+ text={ <><FiSlash /> { t('admin_api_consumers.token.revoke', { ns: 'common' }) }</> }
93
+ onClick={ onRevoke }
94
+ />
95
+ ) }
96
+ </TokenActions>
97
+
98
+ { reveal && (
99
+ <TokenRevealModal token={ reveal } t={ t } onClose={ () => setReveal(null) } />
100
+ ) }
101
+ </>
102
+ );
103
+ };
104
+
105
+ export default TokenManager;
@@ -0,0 +1,67 @@
1
+ import { useState } from 'react';
2
+ import { TFunction } from 'i18next';
3
+ import { FiCopy, FiCheck } from 'react-icons/fi';
4
+ import { Modal, Button } from '@autobusal/common';
5
+ import { TokenBox, TokenValue } from './styles';
6
+
7
+ interface Props {
8
+ token: string
9
+ t: TFunction<'common'>
10
+ onClose: () => void
11
+ }
12
+
13
+ // Edited: Ferjolt Ozuni - Date: 2026-07-27
14
+ // One-time token reveal - nothing in this codebase re-displays a Sanctum
15
+ // token after creation (obtapi never re-selects `users_api.token`), so
16
+ // this is the ONLY place a consumer's token is ever shown. Closing this
17
+ // modal without copying it means it's gone for good (regenerate is the
18
+ // only recovery).
19
+ const TokenRevealModal = ({ token, t, onClose }: Props): JSX.Element => {
20
+ const [ copied, setCopied ] = useState<boolean>(false);
21
+
22
+ const onCopy = (): void => {
23
+ navigator.clipboard.writeText(token).then(() => {
24
+ setCopied(true);
25
+ });
26
+ };
27
+
28
+ return (
29
+ <Modal
30
+ width={ 600 }
31
+ title={ t('admin_api_consumers.token.reveal.title', { ns: 'common' }) }
32
+ content={
33
+ <>
34
+ <p>{ t('admin_api_consumers.token.reveal.notice', { ns: 'common' }) }</p>
35
+
36
+ <TokenBox>
37
+ <TokenValue>{ token }</TokenValue>
38
+
39
+ <Button
40
+ type="button"
41
+ size="small"
42
+ subtype="secondary"
43
+ noMargin
44
+ text={
45
+ <>
46
+ { copied ? <FiCheck /> : <FiCopy /> }
47
+ { t(copied ? 'admin_api_consumers.token.reveal.copied' : 'admin_api_consumers.token.reveal.copy', { ns: 'common' }) }
48
+ </>
49
+ }
50
+ onClick={ onCopy }
51
+ />
52
+ </TokenBox>
53
+
54
+ <Button
55
+ type="button"
56
+ size="medium"
57
+ text={ t('admin_api_consumers.token.reveal.done', { ns: 'common' }) }
58
+ onClick={ onClose }
59
+ />
60
+ </>
61
+ }
62
+ onClose={ onClose }
63
+ />
64
+ );
65
+ };
66
+
67
+ export default TokenRevealModal;
package/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ import Browse from './Browse';
2
+ import Manage from './Manage';
3
+
4
+ export {
5
+ Browse,
6
+ Manage
7
+ };
package/package.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "@autobusal/admin-api-consumers",
3
+ "version": "1.0.0",
4
+ "author": "Ferjolt Ozuni",
5
+ "type": "module",
6
+ "main": "index.ts"
7
+ }
package/services.ts ADDED
@@ -0,0 +1,146 @@
1
+ import { UseMutationResult, UseQueryResult, UseSuspenseQueryResult, useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query';
2
+ import { apiClient } from '@autobusal/providers';
3
+ import { PaginationData } from '@autobusal/providers/types/pagination';
4
+ import { TableParamsData } from '@autobusal/providers/types/other';
5
+ import { DropdownData } from '@autobusal/providers/types/other';
6
+ import { ApiConsumerData } from './types';
7
+
8
+ export const useGetApiConsumers = (params: TableParamsData): UseQueryResult<PaginationData<ApiConsumerData>> => (
9
+ useQuery({
10
+ queryKey: ['admin-api-consumers', params],
11
+ queryFn: async () => (
12
+ await apiClient
13
+ .get('/api/api_consumers/admin/browse', { params })
14
+ .then(response => (
15
+ response.data
16
+ ))
17
+ )
18
+ })
19
+ );
20
+
21
+ export const useGetApiConsumer = (id: number): UseSuspenseQueryResult<ApiConsumerData | null> => (
22
+ useSuspenseQuery({
23
+ queryKey: ['admin-api-consumers-manage', { id }],
24
+ queryFn: async () => {
25
+ if (id === 0) {
26
+ return null;
27
+ }
28
+
29
+ return await apiClient
30
+ .get('/api/api_consumers/admin/get', {
31
+ params: { id }
32
+ })
33
+ .then(response => (
34
+ response.data
35
+ ));
36
+ }
37
+ })
38
+ );
39
+
40
+ // the source for the external_providers allowlist checkbox list - every
41
+ // provider slug the app knows how to talk to (Libraries\External\Registry::available())
42
+ export const useGetProviders = (): UseQueryResult<DropdownData[]> => (
43
+ useQuery({
44
+ queryKey: ['admin-api-consumers-providers'],
45
+ queryFn: async () => (
46
+ await apiClient
47
+ .get('/api/external/admin/providers')
48
+ .then(response => (
49
+ response.data.map((item: { id: string, name: string }) => ({ id: item.id, name: item.name }))
50
+ ))
51
+ )
52
+ })
53
+ );
54
+
55
+ // Edited: Ferjolt Ozuni - Date: 2026-07-27
56
+ // The backend returns `api_token`, not `token` - magus's BFF proxy
57
+ // (public/bff/index.php) treats ANY top-level `token` key on a
58
+ // /bff/api/... response as a fresh session auth token to store server-side
59
+ // and strip from the response, with no notion of whose token it is. A
60
+ // plain `token` here would silently hijack the ADMIN'S OWN session onto
61
+ // the newly-created API consumer's identity (confirmed live during
62
+ // testing). Do not rename this back to `token` without fixing the BFF.
63
+ export const usePostApiConsumer = (id: number): UseMutationResult<{ api_token: string | null }, Error, Record<string, any>, unknown> => (
64
+ useMutation({
65
+ mutationKey: ['admin-api-consumers-save', { id }],
66
+ mutationFn: async (data: Record<string, any>) => {
67
+ const formData = new FormData();
68
+
69
+ if (id > 0) {
70
+ formData.append('id', String(id));
71
+ }
72
+
73
+ Object.keys(data).map(name => {
74
+ if (name === 'operators' || name === 'external_providers') {
75
+ formData.append(name, JSON.stringify(data[name]));
76
+ } else if (data[name] !== undefined && data[name] !== null) {
77
+ formData.append(name, String(data[name]));
78
+ }
79
+ });
80
+
81
+ return await apiClient
82
+ .post('/api/api_consumers/admin/update', formData, {
83
+ headers: {
84
+ 'Content-Type': 'multipart/form-data'
85
+ }
86
+ })
87
+ .then(response => (
88
+ response.data
89
+ ));
90
+ }
91
+ })
92
+ );
93
+
94
+ export const useDeleteApiConsumer = (): UseMutationResult<void, Error, number, unknown> => (
95
+ useMutation({
96
+ mutationKey: ['admin-api-consumers-delete'],
97
+ mutationFn: async (id: number) => (
98
+ await apiClient
99
+ .delete('/api/api_consumers/admin/delete', {
100
+ params: { id }
101
+ })
102
+ .then(response => (
103
+ response.data
104
+ ))
105
+ )
106
+ })
107
+ );
108
+
109
+ export const useToggleApiConsumer = (): UseMutationResult<void, Error, { id: number, api: number }, unknown> => (
110
+ useMutation({
111
+ mutationKey: ['admin-api-consumers-toggle'],
112
+ mutationFn: async ({ id, api }: { id: number, api: number }) => (
113
+ await apiClient
114
+ .post('/api/api_consumers/admin/toggle', { id, api })
115
+ .then(response => (
116
+ response.data
117
+ ))
118
+ )
119
+ })
120
+ );
121
+
122
+ export const useRevokeApiConsumerToken = (): UseMutationResult<void, Error, number, unknown> => (
123
+ useMutation({
124
+ mutationKey: ['admin-api-consumers-revoke'],
125
+ mutationFn: async (id: number) => (
126
+ await apiClient
127
+ .post('/api/api_consumers/admin/revoke', { id })
128
+ .then(response => (
129
+ response.data
130
+ ))
131
+ )
132
+ })
133
+ );
134
+
135
+ export const useRegenerateApiConsumerToken = (): UseMutationResult<{ api_token: string }, Error, number, unknown> => (
136
+ useMutation({
137
+ mutationKey: ['admin-api-consumers-regenerate'],
138
+ mutationFn: async (id: number) => (
139
+ await apiClient
140
+ .post('/api/api_consumers/admin/regenerate', { id })
141
+ .then(response => (
142
+ response.data
143
+ ))
144
+ )
145
+ })
146
+ );
package/styles.ts ADDED
@@ -0,0 +1,31 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const TokenBox = styled.div`
4
+ display: flex;
5
+ align-items: center;
6
+ gap: 10px;
7
+ margin: 15px 0;
8
+ padding: 12px 15px;
9
+ background: ${ props => props.theme.primary.neutral };
10
+ border-radius: 8px;
11
+ `;
12
+
13
+ export const TokenValue = styled.code`
14
+ flex: 1;
15
+ font-family: monospace;
16
+ font-size: ${ props => props.theme.size.sm };
17
+ word-break: break-all;
18
+ color: ${ props => props.theme.font.normal };
19
+ `;
20
+
21
+ export const TokenStatus = styled.div`
22
+ display: flex;
23
+ align-items: center;
24
+ gap: 10px;
25
+ margin-bottom: 10px;
26
+ `;
27
+
28
+ export const TokenActions = styled.div`
29
+ display: flex;
30
+ gap: 10px;
31
+ `;
package/types.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { ComissionData } from '@autobusal/providers/types/users';
2
+
3
+ export interface ApiConsumerData {
4
+ id: number
5
+ company: string
6
+ operators: (number | string)[]
7
+ external_providers: (number | string)[]
8
+ is_api_consumer: boolean
9
+ user: {
10
+ id: number
11
+ email: string
12
+ status: number
13
+ comissions?: ComissionData
14
+ api?: {
15
+ api: number
16
+ has_token: boolean
17
+ }
18
+ }
19
+ }