uibee 3.1.1 → 3.1.3
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/dist/src/components/index.d.ts +59 -27
- package/dist/src/components/index.js +825 -339
- package/dist/style.css +283 -67
- package/package.json +1 -1
- package/src/components/buttons/button.tsx +6 -3
- package/src/components/index.ts +2 -17
- package/src/components/navbar/navbar.tsx +0 -5
- package/src/components/navbar/navbarDropdown.tsx +0 -2
- package/src/components/navbar/navbarItem.tsx +0 -2
- package/src/components/table/body.tsx +260 -153
- package/src/components/table/constants.ts +53 -0
- package/src/components/table/empty.tsx +31 -0
- package/src/components/table/format.ts +29 -22
- package/src/components/table/header.tsx +115 -70
- package/src/components/table/menu.tsx +43 -27
- package/src/components/table/pagination.tsx +162 -136
- package/src/components/table/skeleton.tsx +56 -0
- package/src/components/table/table.tsx +261 -34
- package/src/components/table/types.ts +94 -0
- package/src/components/table/utils.ts +12 -0
- package/src/components/toggle/theme.tsx +0 -3
- package/src/globals.css +11 -0
- package/src/utils/auth/callback.ts +0 -2
- package/src/utils/index.ts +0 -1
|
@@ -1,44 +1,271 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { Suspense, useState, useMemo } from 'react'
|
|
4
|
+
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
|
|
5
|
+
import type { TableProps, TableShellProps, TableVariant, Density, SortState, Column } from './types'
|
|
4
6
|
import Header from './header'
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
idKey
|
|
14
|
-
|
|
7
|
+
import Body from './body'
|
|
8
|
+
import Skeleton from './skeleton'
|
|
9
|
+
import Empty from './empty'
|
|
10
|
+
import Pagination from './pagination'
|
|
11
|
+
import { resolveId } from './utils'
|
|
12
|
+
import { VARIANT_CONTAINER } from './constants'
|
|
13
|
+
|
|
14
|
+
function TableShell<T extends Record<string, unknown>>({
|
|
15
|
+
data, columns, idKey, variant, density, striped, loading, loadingRows,
|
|
16
|
+
emptyState, redirectPath, onRowClick, renderExpandedRow,
|
|
17
|
+
selectable, selectedIds, onSelectionChange,
|
|
18
|
+
sort, onSort, page, onPageChange, totalRows, pageSize, hidePagination,
|
|
19
|
+
menuItems, className,
|
|
20
|
+
}: TableShellProps<T>) {
|
|
21
|
+
const allIds = data.map(row =>
|
|
22
|
+
resolveId(row, idKey as string | undefined, columns as Column<Record<string, unknown>>[])
|
|
23
|
+
)
|
|
24
|
+
const allIdsSet = useMemo(() => new Set(allIds), [allIds])
|
|
25
|
+
|
|
26
|
+
const allSelected = allIds.length > 0 && allIds.every(id => selectedIds.includes(id))
|
|
27
|
+
const someSelected = !allSelected && allIds.some(id => selectedIds.includes(id))
|
|
15
28
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
function handleSelectAll() {
|
|
30
|
+
if (allSelected) {
|
|
31
|
+
onSelectionChange(selectedIds.filter(id => !allIdsSet.has(id)))
|
|
32
|
+
} else {
|
|
33
|
+
onSelectionChange([...new Set([...selectedIds, ...allIds])])
|
|
34
|
+
}
|
|
19
35
|
}
|
|
20
36
|
|
|
37
|
+
const isEmpty = !loading && data.length === 0
|
|
38
|
+
const showPagination = !hidePagination && pageSize > 0 && totalRows > 0
|
|
39
|
+
|
|
40
|
+
const hasMenu = Boolean(menuItems)
|
|
41
|
+
const hasSelect = Boolean(selectable)
|
|
42
|
+
const hasExpand = Boolean(renderExpandedRow)
|
|
43
|
+
|
|
44
|
+
const paginationPad = variant === 'original' ? 'px-4 pb-4 pt-3' : 'pt-4'
|
|
45
|
+
|
|
21
46
|
return (
|
|
22
|
-
<div className={
|
|
23
|
-
flex-1
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
<div className={['flex flex-col min-h-0 w-full', VARIANT_CONTAINER[variant], className].filter(Boolean).join(' ')}>
|
|
48
|
+
<div className='flex-1 min-h-0 overflow-x-auto'>
|
|
49
|
+
<table className='min-w-full w-max flex flex-col flex-1 min-h-0 divide-y divide-login-600/20'>
|
|
50
|
+
<Header
|
|
51
|
+
columns={columns}
|
|
52
|
+
sort={sort}
|
|
53
|
+
onSort={onSort}
|
|
54
|
+
hasMenu={hasMenu}
|
|
55
|
+
hasSelect={hasSelect}
|
|
56
|
+
hasExpand={hasExpand}
|
|
57
|
+
allSelected={allSelected}
|
|
58
|
+
someSelected={someSelected}
|
|
59
|
+
onSelectAll={handleSelectAll}
|
|
60
|
+
variant={variant}
|
|
61
|
+
density={density}
|
|
62
|
+
/>
|
|
63
|
+
{loading ? (
|
|
64
|
+
<Skeleton
|
|
65
|
+
columns={columns}
|
|
66
|
+
rows={loadingRows}
|
|
67
|
+
variant={variant}
|
|
68
|
+
density={density}
|
|
69
|
+
hasMenu={hasMenu}
|
|
70
|
+
hasSelect={hasSelect}
|
|
71
|
+
/>
|
|
72
|
+
) : isEmpty ? (
|
|
73
|
+
<Empty emptyState={emptyState} />
|
|
74
|
+
) : (
|
|
75
|
+
<Body
|
|
76
|
+
data={data}
|
|
77
|
+
columns={columns}
|
|
78
|
+
idKey={idKey}
|
|
79
|
+
variant={variant}
|
|
80
|
+
density={density}
|
|
81
|
+
striped={striped}
|
|
82
|
+
redirectPath={redirectPath}
|
|
83
|
+
onRowClick={onRowClick}
|
|
84
|
+
renderExpandedRow={renderExpandedRow}
|
|
85
|
+
selectable={selectable}
|
|
86
|
+
selectedIds={selectedIds}
|
|
87
|
+
onSelectionChange={onSelectionChange}
|
|
88
|
+
menuItems={menuItems}
|
|
89
|
+
/>
|
|
90
|
+
)}
|
|
91
|
+
</table>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{showPagination && (
|
|
95
|
+
<div className={paginationPad}>
|
|
96
|
+
<Pagination
|
|
97
|
+
page={page}
|
|
98
|
+
totalRows={totalRows}
|
|
99
|
+
pageSize={pageSize}
|
|
100
|
+
onPageChange={onPageChange}
|
|
101
|
+
variant={variant}
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
42
105
|
</div>
|
|
43
106
|
)
|
|
44
107
|
}
|
|
108
|
+
|
|
109
|
+
// useInternalSelection: falls back to internal state when caller omits selectedIds or onSelectionChange.
|
|
110
|
+
function useInternalSelection<T extends Record<string, unknown>>(
|
|
111
|
+
props: Pick<TableProps<T>, 'selectedIds' | 'onSelectionChange'>
|
|
112
|
+
) {
|
|
113
|
+
const [internal, setInternal] = useState<string[]>([])
|
|
114
|
+
return {
|
|
115
|
+
selectedIds: props.selectedIds ?? internal,
|
|
116
|
+
onSelectionChange: props.onSelectionChange ?? setInternal,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function applyDefaults<T extends Record<string, unknown>>(props: TableProps<T>): {
|
|
121
|
+
variant: TableVariant
|
|
122
|
+
density: Density
|
|
123
|
+
selectable: boolean
|
|
124
|
+
loading: boolean
|
|
125
|
+
loadingRows: number
|
|
126
|
+
striped: boolean
|
|
127
|
+
hidePagination: boolean
|
|
128
|
+
pageSize: number
|
|
129
|
+
} {
|
|
130
|
+
return {
|
|
131
|
+
variant: props.variant ?? 'original',
|
|
132
|
+
density: props.density ?? 'comfortable',
|
|
133
|
+
selectable: props.selectable ?? false,
|
|
134
|
+
loading: props.loading ?? false,
|
|
135
|
+
loadingRows: props.loadingRows ?? (props.pageSize ?? 5),
|
|
136
|
+
striped: props.striped ?? false,
|
|
137
|
+
hidePagination: props.hidePagination ?? false,
|
|
138
|
+
pageSize: props.pageSize ?? 0,
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function TableLocalState<T extends Record<string, unknown>>(props: TableProps<T>) {
|
|
143
|
+
const defaults = applyDefaults(props)
|
|
144
|
+
const selection = useInternalSelection(props)
|
|
145
|
+
const [sort, setSort] = useState<SortState | undefined>(undefined)
|
|
146
|
+
const [page, setPage] = useState(1)
|
|
147
|
+
|
|
148
|
+
const ps = defaults.pageSize
|
|
149
|
+
const allRows = props.data.length
|
|
150
|
+
|
|
151
|
+
const sorted = useMemo(() => {
|
|
152
|
+
if (!sort) return props.data
|
|
153
|
+
return [...props.data].sort((a, b) => {
|
|
154
|
+
const av = a[sort.column]
|
|
155
|
+
const bv = b[sort.column]
|
|
156
|
+
const cmp = String(av ?? '').localeCompare(String(bv ?? ''), undefined, { numeric: true, sensitivity: 'base' })
|
|
157
|
+
return sort.order === 'asc' ? cmp : -cmp
|
|
158
|
+
})
|
|
159
|
+
}, [props.data, sort])
|
|
160
|
+
|
|
161
|
+
const displayData = ps > 0 ? sorted.slice((page - 1) * ps, page * ps) : sorted
|
|
162
|
+
|
|
163
|
+
function handleSort(newSort: SortState) {
|
|
164
|
+
setSort(newSort)
|
|
165
|
+
setPage(1)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<TableShell
|
|
170
|
+
{...props}
|
|
171
|
+
{...defaults}
|
|
172
|
+
{...selection}
|
|
173
|
+
data={displayData}
|
|
174
|
+
sort={sort}
|
|
175
|
+
onSort={handleSort}
|
|
176
|
+
page={page}
|
|
177
|
+
onPageChange={setPage}
|
|
178
|
+
totalRows={ps > 0 ? allRows : (props.totalRows ?? allRows)}
|
|
179
|
+
/>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function TableURLState<T extends Record<string, unknown>>(props: TableProps<T>) {
|
|
184
|
+
const defaults = applyDefaults(props)
|
|
185
|
+
const selection = useInternalSelection(props)
|
|
186
|
+
const router = useRouter()
|
|
187
|
+
const pathname = usePathname()
|
|
188
|
+
const searchParams = useSearchParams()
|
|
189
|
+
|
|
190
|
+
const urlColumn = searchParams.get('column') ?? ''
|
|
191
|
+
const urlOrder = (searchParams.get('order') ?? 'asc') as 'asc' | 'desc'
|
|
192
|
+
const urlPage = Math.max(1, parseInt(searchParams.get('page') ?? '1', 10) || 1)
|
|
193
|
+
const sort: SortState | undefined = urlColumn ? { column: urlColumn, order: urlOrder } : undefined
|
|
194
|
+
|
|
195
|
+
function handleSort(newSort: SortState) {
|
|
196
|
+
const p = new URLSearchParams(searchParams.toString())
|
|
197
|
+
p.set('column', newSort.column)
|
|
198
|
+
p.set('order', newSort.order)
|
|
199
|
+
p.set('page', '1')
|
|
200
|
+
router.replace(`${pathname}?${p.toString()}`)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function handlePageChange(newPage: number) {
|
|
204
|
+
const p = new URLSearchParams(searchParams.toString())
|
|
205
|
+
p.set('page', String(newPage))
|
|
206
|
+
router.replace(`${pathname}?${p.toString()}`)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return (
|
|
210
|
+
<TableShell
|
|
211
|
+
{...props}
|
|
212
|
+
{...defaults}
|
|
213
|
+
{...selection}
|
|
214
|
+
sort={sort}
|
|
215
|
+
onSort={handleSort}
|
|
216
|
+
page={urlPage}
|
|
217
|
+
onPageChange={handlePageChange}
|
|
218
|
+
totalRows={props.totalRows ?? props.data.length}
|
|
219
|
+
/>
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function TableControlled<T extends Record<string, unknown>>(props: TableProps<T>) {
|
|
224
|
+
const defaults = applyDefaults(props)
|
|
225
|
+
const selection = useInternalSelection(props)
|
|
226
|
+
return (
|
|
227
|
+
<TableShell
|
|
228
|
+
{...props}
|
|
229
|
+
{...defaults}
|
|
230
|
+
{...selection}
|
|
231
|
+
sort={props.sort}
|
|
232
|
+
onSort={props.onSort!}
|
|
233
|
+
page={props.page ?? 1}
|
|
234
|
+
onPageChange={props.onPageChange ?? (() => {})}
|
|
235
|
+
totalRows={props.totalRows ?? props.data.length}
|
|
236
|
+
/>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function Table<T extends Record<string, unknown> = Record<string, unknown>>(props: TableProps<T>) {
|
|
241
|
+
if (props.sort !== undefined || props.onSort !== undefined) {
|
|
242
|
+
return <TableControlled {...props} />
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (props.urlState) {
|
|
246
|
+
const defaults = applyDefaults(props)
|
|
247
|
+
const fallback = (
|
|
248
|
+
<TableShell
|
|
249
|
+
{...props}
|
|
250
|
+
{...defaults}
|
|
251
|
+
selectedIds={props.selectedIds ?? []}
|
|
252
|
+
onSelectionChange={props.onSelectionChange ?? (() => {})}
|
|
253
|
+
sort={undefined}
|
|
254
|
+
onSort={() => {}}
|
|
255
|
+
page={1}
|
|
256
|
+
onPageChange={() => {}}
|
|
257
|
+
totalRows={props.totalRows ?? props.data.length}
|
|
258
|
+
/>
|
|
259
|
+
)
|
|
260
|
+
return (
|
|
261
|
+
<Suspense fallback={fallback}>
|
|
262
|
+
<TableURLState {...props} />
|
|
263
|
+
</Suspense>
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return <TableLocalState {...props} />
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export { MenuButton } from './menu'
|
|
271
|
+
export type { TableProps, Column, SortState, TableVariant, Density, TableColor } from './types'
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
export type TableColor = 'green' | 'yellow' | 'red' | 'blue' | 'gray' | 'orange' | 'purple'
|
|
4
|
+
|
|
5
|
+
export type Column<T extends Record<string, unknown> = Record<string, unknown>> = {
|
|
6
|
+
key: keyof T & string
|
|
7
|
+
label?: string
|
|
8
|
+
sortable?: boolean
|
|
9
|
+
width?: string
|
|
10
|
+
align?: 'left' | 'center' | 'right'
|
|
11
|
+
highlight?: Record<string, TableColor>
|
|
12
|
+
render?: (value: unknown, row: T) => ReactNode
|
|
13
|
+
truncate?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type SortState = {
|
|
17
|
+
column: string
|
|
18
|
+
order: 'asc' | 'desc'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type Density = 'compact' | 'comfortable' | 'spacious'
|
|
22
|
+
export type TableVariant = 'original' | 'modern'
|
|
23
|
+
|
|
24
|
+
export type TableProps<T extends Record<string, unknown> = Record<string, unknown>> = {
|
|
25
|
+
data: T[]
|
|
26
|
+
columns: Column<T>[]
|
|
27
|
+
|
|
28
|
+
idKey?: keyof T & string
|
|
29
|
+
|
|
30
|
+
variant?: TableVariant
|
|
31
|
+
density?: Density
|
|
32
|
+
striped?: boolean
|
|
33
|
+
className?: string
|
|
34
|
+
|
|
35
|
+
loading?: boolean
|
|
36
|
+
loadingRows?: number
|
|
37
|
+
emptyState?: ReactNode
|
|
38
|
+
|
|
39
|
+
redirectPath?: string | { path: string; key?: string }
|
|
40
|
+
onRowClick?: (row: T, id: string) => void
|
|
41
|
+
|
|
42
|
+
renderExpandedRow?: (row: T) => ReactNode
|
|
43
|
+
|
|
44
|
+
selectable?: boolean
|
|
45
|
+
selectedIds?: string[]
|
|
46
|
+
onSelectionChange?: (ids: string[]) => void
|
|
47
|
+
|
|
48
|
+
// Controlled: provide sort + onSort (table does not manage sort state)
|
|
49
|
+
// URL: provide urlState={true} (syncs ?column=&order= params, Next.js only)
|
|
50
|
+
// Local: neither; manages sort state internally and sorts client-side
|
|
51
|
+
urlState?: boolean
|
|
52
|
+
sort?: SortState
|
|
53
|
+
onSort?: (sort: SortState) => void
|
|
54
|
+
|
|
55
|
+
// URL: totalRows from server, pageSize; table pushes ?page= to URL
|
|
56
|
+
// Local: paginates data internally; totalRows inferred from data.length
|
|
57
|
+
// Controlled: provide page + onPageChange + totalRows
|
|
58
|
+
pageSize?: number
|
|
59
|
+
totalRows?: number
|
|
60
|
+
page?: number
|
|
61
|
+
onPageChange?: (page: number) => void
|
|
62
|
+
hidePagination?: boolean
|
|
63
|
+
|
|
64
|
+
menuItems?: (row: T, id: string) => ReactNode
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type TableShellProps<T extends Record<string, unknown>> = {
|
|
68
|
+
data: T[]
|
|
69
|
+
columns: Column<T>[]
|
|
70
|
+
idKey?: keyof T & string
|
|
71
|
+
variant: TableVariant
|
|
72
|
+
density: Density
|
|
73
|
+
striped: boolean
|
|
74
|
+
loading: boolean
|
|
75
|
+
loadingRows: number
|
|
76
|
+
emptyState?: ReactNode
|
|
77
|
+
redirectPath?: string | { path: string; key?: string }
|
|
78
|
+
onRowClick?: (row: T, id: string) => void
|
|
79
|
+
renderExpandedRow?: (row: T) => ReactNode
|
|
80
|
+
selectable: boolean
|
|
81
|
+
selectedIds: string[]
|
|
82
|
+
onSelectionChange: (ids: string[]) => void
|
|
83
|
+
sort?: SortState
|
|
84
|
+
onSort: (sort: SortState) => void
|
|
85
|
+
page: number
|
|
86
|
+
onPageChange: (page: number) => void
|
|
87
|
+
totalRows: number
|
|
88
|
+
pageSize: number
|
|
89
|
+
hidePagination: boolean
|
|
90
|
+
menuItems?: (row: T, id: string) => ReactNode
|
|
91
|
+
className?: string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type MenuAnchor = { top: number; right: number }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Column } from './types'
|
|
2
|
+
|
|
3
|
+
export function resolveId<T extends Record<string, unknown>>(
|
|
4
|
+
row: T,
|
|
5
|
+
idKey: string | undefined,
|
|
6
|
+
columns: Column<T>[],
|
|
7
|
+
): string {
|
|
8
|
+
if (idKey && row[idKey] !== undefined) return String(row[idKey])
|
|
9
|
+
if (row['id'] !== undefined) return String(row['id'])
|
|
10
|
+
const firstKey = columns[0]?.key ?? Object.keys(row)[0]
|
|
11
|
+
return String(row[firstKey] ?? '')
|
|
12
|
+
}
|
|
@@ -51,7 +51,6 @@ function ThemeIcon({ theme }: { theme: 'dark' | 'light' }) {
|
|
|
51
51
|
viewBox='0 0 100 100'
|
|
52
52
|
xmlns='http://www.w3.org/2000/svg'
|
|
53
53
|
>
|
|
54
|
-
{/* Sun */}
|
|
55
54
|
<defs>
|
|
56
55
|
<mask id='theme-toggle_clip-path'>
|
|
57
56
|
<rect x='0' y='0' width='100' height='100' fill='white' />
|
|
@@ -65,7 +64,6 @@ function ThemeIcon({ theme }: { theme: 'dark' | 'light' }) {
|
|
|
65
64
|
/>
|
|
66
65
|
</mask>
|
|
67
66
|
</defs>
|
|
68
|
-
{/* Moon */}
|
|
69
67
|
<circle
|
|
70
68
|
className={`origin-center transition-all duration-400 ${
|
|
71
69
|
theme === 'light'
|
|
@@ -77,7 +75,6 @@ function ThemeIcon({ theme }: { theme: 'dark' | 'light' }) {
|
|
|
77
75
|
cy='50'
|
|
78
76
|
r='23'
|
|
79
77
|
/>
|
|
80
|
-
{/* Sunrays */}
|
|
81
78
|
<rect
|
|
82
79
|
className={sunrayClass}
|
|
83
80
|
x='86'
|
package/src/globals.css
CHANGED
|
@@ -147,6 +147,17 @@ pre code.hljs {
|
|
|
147
147
|
padding: 0;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
@keyframes shimmer {
|
|
151
|
+
0% { background-position: -200% 0; }
|
|
152
|
+
100% { background-position: 200% 0; }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@utility animate-shimmer {
|
|
156
|
+
background: linear-gradient(90deg, var(--color-login-600) 25%, var(--color-login-500) 50%, var(--color-login-600) 75%);
|
|
157
|
+
background-size: 200% 100%;
|
|
158
|
+
animation: shimmer 1.6s ease-in-out infinite;
|
|
159
|
+
}
|
|
160
|
+
|
|
150
161
|
@keyframes jump {
|
|
151
162
|
40% {
|
|
152
163
|
transform: translateY(-0.3rem);
|
|
@@ -32,7 +32,6 @@ export default async function authCallback({
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
try {
|
|
35
|
-
// Exchanges callback code for access token
|
|
36
35
|
const tokenResponse = await fetch(tokenURL, {
|
|
37
36
|
method: 'POST',
|
|
38
37
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
@@ -56,7 +55,6 @@ export default async function authCallback({
|
|
|
56
55
|
|
|
57
56
|
const token = JSON.parse(tokenResponseBody)
|
|
58
57
|
|
|
59
|
-
// Fetches user info using access token
|
|
60
58
|
const userInfoResponse = await fetch(userInfoURL, {
|
|
61
59
|
headers: { Authorization: `Bearer ${token.access_token}` }
|
|
62
60
|
})
|
package/src/utils/index.ts
CHANGED