nitro-web 0.0.168 → 0.0.170
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/client/app.tsx +12 -15
- package/client/index.ts +3 -2
- package/components/auth/auth.api.js +5 -1
- package/components/partials/element/button.tsx +20 -15
- package/components/partials/element/loading.tsx +25 -0
- package/components/partials/element/table.tsx +38 -13
- package/components/partials/styleguide.tsx +25 -1
- package/package.json +1 -1
- package/server/models/user.js +7 -4
- package/server/router.js +1 -0
- package/types/components/auth/auth.api.d.ts.map +1 -1
- package/types/server/models/user.d.ts +32 -24
- package/types/server/models/user.d.ts.map +1 -1
- package/types/server/router.d.ts.map +1 -1
- package/types.ts +1 -0
package/client/app.tsx
CHANGED
|
@@ -19,7 +19,7 @@ type Settings = {
|
|
|
19
19
|
// beforeStoreUpdate: (prevStore: Store | null, newData: Store) => Store
|
|
20
20
|
isStatic?: boolean
|
|
21
21
|
layouts: React.FC<LayoutProps>[]
|
|
22
|
-
|
|
22
|
+
allMiddleware: Record<string, (route: unknown, store: Store) => undefined | { redirect: string }>
|
|
23
23
|
name: string
|
|
24
24
|
titleSeparator?: string
|
|
25
25
|
}
|
|
@@ -52,7 +52,7 @@ export async function setupApp(config: Config, storeContainer: StoreContainer, l
|
|
|
52
52
|
beforeApp: config.beforeApp || beforeApp,
|
|
53
53
|
isStatic: config.isStatic,
|
|
54
54
|
layouts: layouts,
|
|
55
|
-
|
|
55
|
+
allMiddleware: Object.assign(middleware, config.middleware || {}),
|
|
56
56
|
name: config.name,
|
|
57
57
|
titleSeparator: config.titleSeparator,
|
|
58
58
|
}
|
|
@@ -165,9 +165,9 @@ function getRouter({ settings, config }: { settings: Settings, config: Config })
|
|
|
165
165
|
const layoutNum = (parseInt(String(route.meta?.layout || '1')) || 1) - 1
|
|
166
166
|
|
|
167
167
|
// get the routes middleware
|
|
168
|
-
const
|
|
168
|
+
const routeMiddleware = toArray(route[routePath]).filter((policyNameOrTrue) => {
|
|
169
169
|
if (policyNameOrTrue === true) return // ignore true
|
|
170
|
-
else if (policyNameOrTrue in settings.
|
|
170
|
+
else if (policyNameOrTrue in settings.allMiddleware) return true
|
|
171
171
|
else console.error(`No middleware named '${policyNameOrTrue}' defined under config.middleware, skipping..`)
|
|
172
172
|
})
|
|
173
173
|
|
|
@@ -180,7 +180,7 @@ function getRouter({ settings, config }: { settings: Settings, config: Config })
|
|
|
180
180
|
layout: layoutNum,
|
|
181
181
|
title: `${route.meta?.title ? `${route.meta.title}${settings.titleSeparator || ' - '}` : ''}${settings.name}`,
|
|
182
182
|
},
|
|
183
|
-
middleware:
|
|
183
|
+
middleware: routeMiddleware as string[],
|
|
184
184
|
name: componentName,
|
|
185
185
|
path: routePath,
|
|
186
186
|
redirect: route.redirect,
|
|
@@ -218,7 +218,7 @@ function getRouter({ settings, config }: { settings: Settings, config: Config })
|
|
|
218
218
|
await setTimeoutPromise(() => {}, 0)
|
|
219
219
|
}
|
|
220
220
|
for (const key of route.middleware) {
|
|
221
|
-
const error = settings.
|
|
221
|
+
const error = settings.allMiddleware[key](route, exposedStoreData || {})
|
|
222
222
|
// Note: the redirect uses the new pathname for query string values, e.g. '?example=value'. We also can't use the
|
|
223
223
|
// current pathname, as this doesn't exist on page refresh.
|
|
224
224
|
if (error && error.redirect) {
|
|
@@ -317,22 +317,19 @@ async function beforeApp(config: Config) {
|
|
|
317
317
|
return { ...storeData, apiAvailable }
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
const
|
|
321
|
-
//
|
|
320
|
+
export const middleware = {
|
|
321
|
+
// Default middleware that can referenced from component routes
|
|
322
322
|
isAdmin: (route: unknown, store: { user?: { type?: string, isAdmin?: boolean } }) => {
|
|
323
|
-
|
|
324
|
-
if (user
|
|
325
|
-
else if (user?.type && user?.type !== 'visitor') return { redirect: '/signin?unauth' }
|
|
323
|
+
if (store.user?.type?.match(/admin/) || store.user?.isAdmin) return
|
|
324
|
+
else if (store.user) return { redirect: '/signin?unauth' }
|
|
326
325
|
else return { redirect: '/signin?signin' }
|
|
327
326
|
},
|
|
328
327
|
isSubscribed: (route: unknown, store: { user?: { company?: { currentSubscription?: string } } }) => {
|
|
329
|
-
|
|
330
|
-
if (!user?.company?.currentSubscription) return
|
|
328
|
+
if (store.user?.company?.currentSubscription) return
|
|
331
329
|
else return { redirect: '/plans/subscribe' }
|
|
332
330
|
},
|
|
333
331
|
isUser: (route: unknown, store: { user?: { type?: string } }) => {
|
|
334
|
-
|
|
335
|
-
if (user?.type !== 'visitor') return
|
|
332
|
+
if (store.user) return
|
|
336
333
|
else return { redirect: '/signin?signin' }
|
|
337
334
|
},
|
|
338
335
|
}
|
package/client/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ export * as util from 'nitro-web/util'
|
|
|
9
9
|
export * from '../types'
|
|
10
10
|
|
|
11
11
|
// Main app functions
|
|
12
|
-
export { setupApp, updateJwt } from './app'
|
|
12
|
+
export { setupApp, updateJwt, middleware } from './app'
|
|
13
13
|
export { createStore, exposedStoreData, preloadedStoreData, setStoreWrapper } from './store'
|
|
14
14
|
|
|
15
15
|
// Component Pages
|
|
@@ -23,7 +23,7 @@ export { Styleguide } from '../components/partials/styleguide'
|
|
|
23
23
|
// Component Elements
|
|
24
24
|
export { Accordion } from '../components/partials/element/accordion'
|
|
25
25
|
export { Avatar } from '../components/partials/element/avatar'
|
|
26
|
-
export { Button } from '../components/partials/element/button'
|
|
26
|
+
export { Button, Spinner } from '../components/partials/element/button'
|
|
27
27
|
export { Calendar, type CalendarProps } from '../components/partials/element/calendar'
|
|
28
28
|
export { Dropdown, type DropdownProps, type DropdownOption } from '../components/partials/element/dropdown'
|
|
29
29
|
export { Filters, type FilterType, usePushChangesToPath } from '../components/partials/element/filters'
|
|
@@ -36,6 +36,7 @@ export { TimePicker, type TimePickerProps } from '../components/partials/element
|
|
|
36
36
|
export { Tooltip } from '../components/partials/element/tooltip'
|
|
37
37
|
export { Topbar } from '../components/partials/element/topbar'
|
|
38
38
|
export { Table, type TableColumn, type TableProps, type TableRow, type TableRowType } from '../components/partials/element/table'
|
|
39
|
+
export { LoadingWithDots, LoadingOverlay } from '../components/partials/element/loading'
|
|
39
40
|
|
|
40
41
|
// Component Form Elements
|
|
41
42
|
export { Checkbox } from '../components/partials/form/checkbox'
|
|
@@ -420,10 +420,14 @@ export async function sendToken({ type = 'reset', user, beforeUpdate, beforeSend
|
|
|
420
420
|
if (!user?.firstName) throw new Error('user.firstName is required')
|
|
421
421
|
const token = await tokenCreate(user._id)
|
|
422
422
|
|
|
423
|
+
// get the data
|
|
424
|
+
const data = beforeUpdate ? beforeUpdate({ [type + 'Token']: token }) : { [type + 'Token']: token }
|
|
425
|
+
if (type === 'invite') data.isInvited = true
|
|
426
|
+
|
|
423
427
|
// Update the user with the token
|
|
424
428
|
const result = await db.user.update({
|
|
425
429
|
query: { _id: user._id },
|
|
426
|
-
data:
|
|
430
|
+
data: data,
|
|
427
431
|
blacklist: ['-' + type + 'Token'],
|
|
428
432
|
})
|
|
429
433
|
|
|
@@ -41,16 +41,16 @@ export function Button({
|
|
|
41
41
|
|
|
42
42
|
// Button colors, you can use custom colors by using className instead
|
|
43
43
|
const colors = {
|
|
44
|
-
'primary': 'bg-primary hover:bg-primary-hover ring-transparent text-white [&>.
|
|
45
|
-
'secondary': 'bg-secondary hover:bg-secondary-hover ring-transparent text-white [&>.
|
|
46
|
-
'black': 'bg-black hover:bg-gray-800 ring-transparent text-white [&>.
|
|
47
|
-
'dark': 'bg-gray-800 hover:bg-gray-700 ring-transparent text-white [&>.
|
|
48
|
-
'white': 'bg-white hover:bg-gray-50 ring-gray-300 text-gray-900 [&>.
|
|
49
|
-
'clear': 'hover:bg-gray-50 ring-gray-300 hover:text-foreground [&>.
|
|
50
|
-
'danger': 'bg-danger hover:bg-danger-hover ring-transparent text-white [&>.
|
|
51
|
-
'warning': 'bg-warning hover:bg-warning-hover ring-transparent text-white [&>.
|
|
52
|
-
'info': 'bg-info hover:bg-info-hover ring-transparent text-white [&>.
|
|
53
|
-
'success': 'bg-success hover:bg-success-hover ring-transparent text-white [&>.
|
|
44
|
+
'primary': 'bg-primary hover:bg-primary-hover ring-transparent text-white [&>.spinner]:border-white',
|
|
45
|
+
'secondary': 'bg-secondary hover:bg-secondary-hover ring-transparent text-white [&>.spinner]:border-white',
|
|
46
|
+
'black': 'bg-black hover:bg-gray-800 ring-transparent text-white [&>.spinner]:border-white',
|
|
47
|
+
'dark': 'bg-gray-800 hover:bg-gray-700 ring-transparent text-white [&>.spinner]:border-white',
|
|
48
|
+
'white': 'bg-white hover:bg-gray-50 ring-gray-300 text-gray-900 [&>.spinner]:border-black', // maybe change to text-foreground
|
|
49
|
+
'clear': 'hover:bg-gray-50 ring-gray-300 hover:text-foreground [&>.spinner]:border-foreground !shadow-none',
|
|
50
|
+
'danger': 'bg-danger hover:bg-danger-hover ring-transparent text-white [&>.spinner]:border-white',
|
|
51
|
+
'warning': 'bg-warning hover:bg-warning-hover ring-transparent text-white [&>.spinner]:border-white',
|
|
52
|
+
'info': 'bg-info hover:bg-info-hover ring-transparent text-white [&>.spinner]:border-white',
|
|
53
|
+
'success': 'bg-success hover:bg-success-hover ring-transparent text-white [&>.spinner]:border-white',
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// Button sizes (px is better for height consistency)
|
|
@@ -91,12 +91,17 @@ export function Button({
|
|
|
91
91
|
</span>
|
|
92
92
|
{(IconRight || IconRightEnd) && getIcon(IconRight || IconRightEnd)}
|
|
93
93
|
{
|
|
94
|
-
isLoading &&
|
|
95
|
-
<span className={
|
|
96
|
-
'loader !opacity-100 absolute top-[50%] left-[50%] w-[1rem] h-[1rem] ml-[-0.5rem] mt-[-0.5rem] ' +
|
|
97
|
-
'rounded-full animate-spin border-2 !border-t-transparent'
|
|
98
|
-
} />
|
|
94
|
+
isLoading && <Spinner className={'!opacity-100 size-[1rem]'} absoluteCenter={true} />
|
|
99
95
|
}
|
|
100
96
|
</button>
|
|
101
97
|
)
|
|
102
98
|
}
|
|
99
|
+
|
|
100
|
+
export function Spinner({ className, absoluteCenter }: { className?: string, absoluteCenter?: boolean }) {
|
|
101
|
+
const absoluteCenterClass = absoluteCenter ? 'absolute top-[50%] left-[50%] ml-[-0.5rem] mt-[-0.5rem]' : ''
|
|
102
|
+
return (
|
|
103
|
+
<span
|
|
104
|
+
className={twMerge(`spinner border-black border-2 inline-block size-[1em] rounded-full animate-spin ${absoluteCenterClass} ${className||''} !border-t-transparent `)}
|
|
105
|
+
/>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Spinner, twMerge } from 'nitro-web'
|
|
2
|
+
|
|
3
|
+
export function LoadingWithDots({ message='Loading', className, classNameDots }: {
|
|
4
|
+
message?: string,
|
|
5
|
+
className?: string,
|
|
6
|
+
classNameDots?: string
|
|
7
|
+
}) {
|
|
8
|
+
return (
|
|
9
|
+
<span className={`flex items-center gap-[0.2em] ${className}`}>
|
|
10
|
+
{message}<span className={twMerge('relative loading-dots', classNameDots)} />
|
|
11
|
+
</span>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function LoadingOverlay({ message='Loading', className }: { message?: string, className?: string }) {
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
className={twMerge('absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center z-10 text-md [&>span]:bg-white', className)}
|
|
19
|
+
>
|
|
20
|
+
<span className="inline-block flex items-center justify-center gap-3 p-2">
|
|
21
|
+
<Spinner />{message}
|
|
22
|
+
</span>
|
|
23
|
+
</div>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JSX, useState, useCallback, Fragment, useMemo, useEffect } from 'react'
|
|
2
2
|
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
|
|
3
|
-
import { Checkbox, queryObject, queryString, twMerge } from 'nitro-web'
|
|
3
|
+
import { Checkbox, queryObject, queryString, Spinner, twMerge, LoadingWithDots, LoadingOverlay } from 'nitro-web'
|
|
4
4
|
import { useLocation, useNavigate } from 'react-router-dom'
|
|
5
5
|
|
|
6
6
|
export type TableRowType = 'row' | 'loading' | 'empty' | 'thead'
|
|
@@ -45,7 +45,11 @@ export type TableProps<T> = {
|
|
|
45
45
|
columnHeaderClassName?: string
|
|
46
46
|
checkboxClassName?: string
|
|
47
47
|
checkboxSize?: number
|
|
48
|
+
loadingOverlayClassName?: string
|
|
48
49
|
isLoading?:boolean
|
|
50
|
+
loadingMessage?: string
|
|
51
|
+
showLoadingInline?: boolean|JSX.Element
|
|
52
|
+
showLoadingOverlay?: boolean|JSX.Element
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
export function Table<T extends TableRow>({
|
|
@@ -71,7 +75,12 @@ export function Table<T extends TableRow>({
|
|
|
71
75
|
columnHeaderClassName,
|
|
72
76
|
checkboxClassName,
|
|
73
77
|
checkboxSize=16,
|
|
78
|
+
loadingOverlayClassName,
|
|
79
|
+
// Loading
|
|
74
80
|
isLoading=false,
|
|
81
|
+
loadingMessage,
|
|
82
|
+
showLoadingInline=false,
|
|
83
|
+
showLoadingOverlay=true,
|
|
75
84
|
}: TableProps<T>) {
|
|
76
85
|
const location = useLocation()
|
|
77
86
|
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([])
|
|
@@ -80,9 +89,9 @@ export function Table<T extends TableRow>({
|
|
|
80
89
|
const [rand] = useState(() => new Date().getTime() + Math.random())
|
|
81
90
|
|
|
82
91
|
const rowsToRender = useMemo(() => {
|
|
83
|
-
// 1) Only show the first row when loading (content hidden), 2) an empty row when there are no records, or all rows
|
|
84
|
-
return rows.length > 0 ? (isLoading ? rows.slice(0, 1) : rows) : [{ _id: '' }] as unknown as T[]
|
|
85
|
-
}, [rows, isLoading])
|
|
92
|
+
// 1) Only show the first row when loading inline(content hidden), 2) an empty row when there are no records, or all rows
|
|
93
|
+
return rows.length > 0 ? ((isLoading && showLoadingInline) ? rows.slice(0, 1) : rows) : [{ _id: '' }] as unknown as T[]
|
|
94
|
+
}, [rows, isLoading, showLoadingInline])
|
|
86
95
|
|
|
87
96
|
const columns = useMemo(() => {
|
|
88
97
|
const checkboxCol: TableColumn = { value: 'checkbox', label: '', disableSort: true }
|
|
@@ -145,7 +154,7 @@ export function Table<T extends TableRow>({
|
|
|
145
154
|
>
|
|
146
155
|
<div
|
|
147
156
|
style={{ borderSpacing: `0 ${rowGap}px` }}
|
|
148
|
-
className={twMerge('table w-full border-separate', tableClassName)}
|
|
157
|
+
className={twMerge('table w-full border-separate', showLoadingOverlay ? 'relative' : '', tableClassName)}
|
|
149
158
|
>
|
|
150
159
|
{/* Thead row */}
|
|
151
160
|
<div className="table-row relative">
|
|
@@ -181,7 +190,7 @@ export function Table<T extends TableRow>({
|
|
|
181
190
|
>
|
|
182
191
|
{
|
|
183
192
|
col.value == 'checkbox'
|
|
184
|
-
?
|
|
193
|
+
? <Fragment>
|
|
185
194
|
<Checkbox
|
|
186
195
|
size={checkboxSize}
|
|
187
196
|
name={`checkbox-all-${rand}`}
|
|
@@ -195,7 +204,7 @@ export function Table<T extends TableRow>({
|
|
|
195
204
|
>
|
|
196
205
|
{generateCheckboxActions && generateCheckboxActions(selectedRowIds)}
|
|
197
206
|
</div>
|
|
198
|
-
|
|
207
|
+
</Fragment>
|
|
199
208
|
: <span className={twMerge(
|
|
200
209
|
'flex items-center gap-x-2 transition-opacity',
|
|
201
210
|
selectedRowIds.length ? 'opacity-0' : '',
|
|
@@ -267,9 +276,9 @@ export function Table<T extends TableRow>({
|
|
|
267
276
|
/>
|
|
268
277
|
}
|
|
269
278
|
{
|
|
270
|
-
// Rows (content hidden when loading)
|
|
279
|
+
// Rows (content hidden when loading inline)
|
|
271
280
|
row._id &&
|
|
272
|
-
<div className={isLoading ? 'opacity-0 pointer-events-none' : ''}>
|
|
281
|
+
<div className={isLoading && showLoadingInline ? 'opacity-0 pointer-events-none' : ''}>
|
|
273
282
|
{
|
|
274
283
|
col.value == 'checkbox'
|
|
275
284
|
? <Checkbox
|
|
@@ -287,10 +296,21 @@ export function Table<T extends TableRow>({
|
|
|
287
296
|
</div>
|
|
288
297
|
}
|
|
289
298
|
{
|
|
290
|
-
// Show "
|
|
291
|
-
j == 0 && (
|
|
292
|
-
<div className={'absolute top-0 h-full flex items-center justify-center text-sm text-gray-500'}>
|
|
293
|
-
{
|
|
299
|
+
// Show "no records" or "loading" text in the first column
|
|
300
|
+
j == 0 && (!row._id || isLoading) &&
|
|
301
|
+
<div className={'absolute top-0 h-full flex items-center justify-center gap-3 text-sm text-gray-500'}>
|
|
302
|
+
{
|
|
303
|
+
(!row._id && !isLoading) ? (
|
|
304
|
+
'No records found.'
|
|
305
|
+
) : (!row._id && isLoading && showLoadingInline === true) ? (
|
|
306
|
+
<Fragment>
|
|
307
|
+
<Spinner className="border-gray-500" />
|
|
308
|
+
<LoadingWithDots message={loadingMessage} />
|
|
309
|
+
</Fragment>
|
|
310
|
+
) : (!row._id && isLoading && showLoadingInline) ? (
|
|
311
|
+
showLoadingInline
|
|
312
|
+
) : null
|
|
313
|
+
}
|
|
294
314
|
</div>
|
|
295
315
|
}
|
|
296
316
|
</div>
|
|
@@ -302,6 +322,11 @@ export function Table<T extends TableRow>({
|
|
|
302
322
|
)
|
|
303
323
|
})
|
|
304
324
|
}
|
|
325
|
+
{
|
|
326
|
+
(isLoading && showLoadingOverlay === true)
|
|
327
|
+
? <LoadingOverlay className={twMerge('m-[1px]', loadingOverlayClassName)} message={loadingMessage} />
|
|
328
|
+
: (isLoading && showLoadingOverlay) ? showLoadingOverlay : null
|
|
329
|
+
}
|
|
305
330
|
</div>
|
|
306
331
|
</div>
|
|
307
332
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Drop, Dropdown, Field, Select, Button as ButtonNitro, Checkbox, GithubLink, Modal, Calendar, injectedConfig, TimePicker,
|
|
3
|
-
Filters, FilterType, Table, TableColumn, usePushChangesToPath,
|
|
3
|
+
Filters, FilterType, Table, TableColumn, usePushChangesToPath, Spinner, LoadingWithDots,
|
|
4
4
|
} from 'nitro-web'
|
|
5
5
|
import { date, getCurrencyOptions, onChange, ucFirst } from 'nitro-web/util'
|
|
6
6
|
import { Check, EllipsisVerticalIcon, FileEditIcon } from 'lucide-react'
|
|
@@ -44,6 +44,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
44
44
|
'Filters',
|
|
45
45
|
'Button Colors & Sizes',
|
|
46
46
|
'Button Icons',
|
|
47
|
+
'Loading Elements',
|
|
47
48
|
'Varients',
|
|
48
49
|
'Selects',
|
|
49
50
|
'Inputs',
|
|
@@ -367,6 +368,18 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
367
368
|
</div>
|
|
368
369
|
)}
|
|
369
370
|
|
|
371
|
+
{groups.includes('Loading Elements') && (
|
|
372
|
+
<div>
|
|
373
|
+
<h2 class="h3">Loading Elements</h2>
|
|
374
|
+
<div class="flex flex-wrap gap-x-6 gap-y-4 items-center mb-6">
|
|
375
|
+
<div><Spinner /></div>
|
|
376
|
+
<div><Spinner className="border-secondary" /></div>
|
|
377
|
+
<div><Spinner className="border-primary border-[3px]" /></div>
|
|
378
|
+
<div><LoadingWithDots message="Loading" /></div>
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
)}
|
|
382
|
+
|
|
370
383
|
{groups.includes('Varients') && (
|
|
371
384
|
<div>
|
|
372
385
|
<h2 class="h3">Varients</h2>
|
|
@@ -659,6 +672,17 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
659
672
|
className="mb-6"
|
|
660
673
|
isLoading={true}
|
|
661
674
|
/>
|
|
675
|
+
<Table
|
|
676
|
+
rows={[]}
|
|
677
|
+
columns={thead}
|
|
678
|
+
rowSideColor={(row) => ({ className: row?.status == 'pending' ? 'bg-yellow-400' : '', width: 5 })}
|
|
679
|
+
generateCheckboxActions={generateCheckboxActions}
|
|
680
|
+
generateTd={generateTd}
|
|
681
|
+
className="mb-6"
|
|
682
|
+
isLoading={true}
|
|
683
|
+
showLoadingOverlay={false}
|
|
684
|
+
showLoadingInline={true}
|
|
685
|
+
/>
|
|
662
686
|
<Table
|
|
663
687
|
rows={rows.slice(0, 2).map(row => ({ ...row, _id: row._id + '1' }))}
|
|
664
688
|
columns={thead}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitro-web",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.170",
|
|
4
4
|
"repository": "github:boycce/nitro-web",
|
|
5
5
|
"homepage": "https://boycce.github.io/nitro-web/",
|
|
6
6
|
"description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
|
package/server/models/user.js
CHANGED
|
@@ -7,20 +7,23 @@ export default {
|
|
|
7
7
|
avatar: { type: 'image' },
|
|
8
8
|
company: { model: 'company', required: true },
|
|
9
9
|
email: { type: 'email', required: true, index: 'unique' },
|
|
10
|
+
isInvited: { type: 'boolean' },
|
|
10
11
|
firstName: { type: 'string', required: true },
|
|
11
12
|
lastName: { type: 'string', required: true },
|
|
12
|
-
password: { type: 'string', minLength: 6 },
|
|
13
|
-
resetToken: { type: 'string' },
|
|
14
13
|
status: { type: 'string', default: 'active', enum: ['active', 'deleted', 'inactive'] },
|
|
15
14
|
stripeCustomer: { type: 'any' },
|
|
16
15
|
stripeSubscription: { type: 'any' },
|
|
17
16
|
stripeIntents: { type: 'any' },
|
|
18
17
|
type: { type: 'string', default: 'user', enum: ['user', 'admin'] },
|
|
19
18
|
usedFreeTrial: { type: 'boolean', default: false },
|
|
19
|
+
// hidden fields
|
|
20
|
+
password: { type: 'string', minLength: 6 },
|
|
21
|
+
inviteToken: { type: 'string' },
|
|
22
|
+
resetToken: { type: 'string' },
|
|
20
23
|
},
|
|
21
24
|
|
|
22
|
-
findBL: ['password', 'resetToken'],
|
|
23
|
-
updateBL: ['
|
|
25
|
+
findBL: ['password', 'inviteToken', 'resetToken'],
|
|
26
|
+
updateBL: ['password', 'inviteToken', 'resetToken', 'company', 'status', 'stripeSubscription', 'type', 'usedFreeTrial'],
|
|
24
27
|
|
|
25
28
|
messages: {
|
|
26
29
|
lastName: {
|
package/server/router.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.api.d.ts","sourceRoot":"","sources":["../../../components/auth/auth.api.js"],"names":[],"mappings":"AAkLA,qGAyCC;AAED;;GAKC;AAED,0FAQC;AAED;;;;iBAkDC;AAED,mDAOC;AAED,4CAYC;AAED,kFAiBC;AAOD,qEAeC;AAED,sEAWC;AAED,iEAMC;AAED,gEAMC;AAID,wEAoBC;AAED;;;;;;;;GAQG;AACH,yEANG;IAAoC,IAAI,EAAhC,OAAO,GAAG,QAAQ;IACuC,IAAI,EAA7D;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC;IAC5B,YAAY;IACZ,eAAe;CAC1C,GAAU,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"auth.api.d.ts","sourceRoot":"","sources":["../../../components/auth/auth.api.js"],"names":[],"mappings":"AAkLA,qGAyCC;AAED;;GAKC;AAED,0FAQC;AAED;;;;iBAkDC;AAED,mDAOC;AAED,4CAYC;AAED,kFAiBC;AAOD,qEAeC;AAED,sEAWC;AAED,iEAMC;AAED,gEAMC;AAID,wEAoBC;AAED;;;;;;;;GAQG;AACH,yEANG;IAAoC,IAAI,EAAhC,OAAO,GAAG,QAAQ;IACuC,IAAI,EAA7D;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC;IAC5B,YAAY;IACZ,eAAe;CAC1C,GAAU,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAC,CAAC,CAoCtE;AApbD;;;;;;;;;;;;;;;;;;;;EA6BC;AAmED,0DAEC;AAkCD,mDAEC;AAnBD,iDAeC;AA9BD,2DAaC;AAuBD,2DAwBC;AAjID,4DA+DC"}
|
|
@@ -14,62 +14,70 @@ declare namespace _default {
|
|
|
14
14
|
export { required_1 as required };
|
|
15
15
|
export let index: string;
|
|
16
16
|
}
|
|
17
|
-
export namespace
|
|
17
|
+
export namespace isInvited {
|
|
18
18
|
let type_2: string;
|
|
19
19
|
export { type_2 as type };
|
|
20
|
-
let required_2: boolean;
|
|
21
|
-
export { required_2 as required };
|
|
22
20
|
}
|
|
23
|
-
export namespace
|
|
21
|
+
export namespace firstName {
|
|
24
22
|
let type_3: string;
|
|
25
23
|
export { type_3 as type };
|
|
26
|
-
let
|
|
27
|
-
export {
|
|
24
|
+
let required_2: boolean;
|
|
25
|
+
export { required_2 as required };
|
|
28
26
|
}
|
|
29
|
-
export namespace
|
|
27
|
+
export namespace lastName {
|
|
30
28
|
let type_4: string;
|
|
31
29
|
export { type_4 as type };
|
|
32
|
-
|
|
30
|
+
let required_3: boolean;
|
|
31
|
+
export { required_3 as required };
|
|
33
32
|
}
|
|
34
|
-
export namespace
|
|
33
|
+
export namespace status {
|
|
35
34
|
let type_5: string;
|
|
36
35
|
export { type_5 as type };
|
|
37
|
-
}
|
|
38
|
-
export namespace status {
|
|
39
|
-
let type_6: string;
|
|
40
|
-
export { type_6 as type };
|
|
41
36
|
let _default: string;
|
|
42
37
|
export { _default as default };
|
|
43
38
|
let _enum: string[];
|
|
44
39
|
export { _enum as enum };
|
|
45
40
|
}
|
|
46
41
|
export namespace stripeCustomer {
|
|
42
|
+
let type_6: string;
|
|
43
|
+
export { type_6 as type };
|
|
44
|
+
}
|
|
45
|
+
export namespace stripeSubscription {
|
|
47
46
|
let type_7: string;
|
|
48
47
|
export { type_7 as type };
|
|
49
48
|
}
|
|
50
|
-
export namespace
|
|
49
|
+
export namespace stripeIntents {
|
|
51
50
|
let type_8: string;
|
|
52
51
|
export { type_8 as type };
|
|
53
52
|
}
|
|
54
|
-
export namespace
|
|
55
|
-
let
|
|
56
|
-
export {
|
|
57
|
-
}
|
|
58
|
-
export namespace type_10 {
|
|
59
|
-
let type_11: string;
|
|
60
|
-
export { type_11 as type };
|
|
53
|
+
export namespace type_9 {
|
|
54
|
+
let type_10: string;
|
|
55
|
+
export { type_10 as type };
|
|
61
56
|
let _default_1: string;
|
|
62
57
|
export { _default_1 as default };
|
|
63
58
|
let _enum_1: string[];
|
|
64
59
|
export { _enum_1 as enum };
|
|
65
60
|
}
|
|
66
|
-
export {
|
|
61
|
+
export { type_9 as type };
|
|
67
62
|
export namespace usedFreeTrial {
|
|
68
|
-
let
|
|
69
|
-
export {
|
|
63
|
+
let type_11: string;
|
|
64
|
+
export { type_11 as type };
|
|
70
65
|
let _default_2: boolean;
|
|
71
66
|
export { _default_2 as default };
|
|
72
67
|
}
|
|
68
|
+
export namespace password {
|
|
69
|
+
let type_12: string;
|
|
70
|
+
export { type_12 as type };
|
|
71
|
+
export let minLength: number;
|
|
72
|
+
}
|
|
73
|
+
export namespace inviteToken {
|
|
74
|
+
let type_13: string;
|
|
75
|
+
export { type_13 as type };
|
|
76
|
+
}
|
|
77
|
+
export namespace resetToken {
|
|
78
|
+
let type_14: string;
|
|
79
|
+
export { type_14 as type };
|
|
80
|
+
}
|
|
73
81
|
}
|
|
74
82
|
let findBL: string[];
|
|
75
83
|
let updateBL: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../server/models/user.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../server/models/user.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiDmB,gCAEd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../server/router.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../server/router.js"],"names":[],"mappings":"AAoCA,wHA6HC;AAoPD,+CAEC;AAED,kEAYC;AApGD,+BAA+B;AAC/B,yBADW,gBAAgB,CAkF1B;sBAnYY,OAAO,CAAC,OAAO,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAoB,CAAC;CAC7B;uBACS,OAAO,CAAC,QAAQ,GAAG;IAC3B,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,YAAY,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;IACvD,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;IACpD,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;IACnD,WAAW,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;CACvD;+BACS;IACR,KAAK,EAAE,MAAM,EAAE,CAAC;IACpB,CAAK,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,UAAU,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC;CACnF;iBA1Ba,MAAM;oBAIH,SAAS"}
|