nitro-web 0.0.183 → 0.0.185

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,106 @@
1
+ import { Topbar, Field, FormError, Button, request, onChange, getResponseErrors, showError } from 'nitro-web'
2
+ import { Errors } from 'nitro-web/types'
3
+ import { Fragment, useEffect } from 'react'
4
+
5
+ type InviteConfirmProps = {
6
+ className?: string,
7
+ elements?: { Button?: typeof Button },
8
+ redirectTo?: string,
9
+ }
10
+
11
+ export function InviteConfirm({ className, elements, redirectTo }: InviteConfirmProps) {
12
+ const navigate = useNavigate()
13
+ const params = useParams()
14
+ const [store, setStore] = useTracked()
15
+ const [isLoading, setIsLoading] = useState(false)
16
+ const [accepted, setAccepted] = useState(false)
17
+ const [state, setState] = useState(() => ({
18
+ firstName: '',
19
+ lastName: '',
20
+ password: '',
21
+ password2: '',
22
+ token: params.token,
23
+ errors: [] as Errors,
24
+ }))
25
+
26
+ const Elements = {
27
+ Button: elements?.Button || Button,
28
+ }
29
+
30
+ // Auto-confirm on mount for already signed-in users
31
+ useEffect(() => {
32
+ if (store.user) submit({ token: params.token })
33
+ }, [])
34
+
35
+ async function submit(data: object, event?: React.FormEvent<HTMLFormElement>) {
36
+ try {
37
+ if (isLoading) return
38
+ const result = await request('post /api/invite-confirm', data, event, setIsLoading, setState)
39
+ setStore((s) => ({ ...s, ...result }))
40
+ setAccepted(true)
41
+ setTimeout(() => navigate(redirectTo || '/'), 5000)
42
+ } catch (e) {
43
+ showError(setStore, e)
44
+ setState((s) => ({ ...s, errors: getResponseErrors(e) }))
45
+ }
46
+ }
47
+
48
+ if (store.user) {
49
+ return (
50
+ <div className={className}>
51
+ <div class="py-12 text-center">
52
+ {accepted ? (
53
+ <Fragment>
54
+ <p class="text-lg font-semibold">Your invite has been accepted.</p>
55
+ <p class="text-sm text-gray-500 mt-1">You&apos;ll be redirected back to the <Link to="/">home page</Link> shortly...</p>
56
+ </Fragment>
57
+ ) : isLoading ? (
58
+ <Fragment>
59
+ <p class="text-lg font-semibold">Accepting your invite...</p>
60
+ <p class="text-sm text-gray-500 mt-1">Please wait while we confirm your invite.</p>
61
+ </Fragment>
62
+ ) : (
63
+ <Fragment>
64
+ <p class="text-lg font-semibold mb-2">Oops! Something went wrong.</p>
65
+ <span class="text-sm text-red-500 bg-red-50 p-1 rounded-md mt-1">{state.errors.map((error) => error.detail).join(', ')}</span>
66
+ </Fragment>
67
+ )}
68
+ </div>
69
+ </div>
70
+ )
71
+ }
72
+
73
+ return (
74
+ <div className={className}>
75
+ <Topbar title={<Fragment>Accept Your Invite</Fragment>} />
76
+
77
+ <form onSubmit={(e) => submit(state, e)} class="mb-0">
78
+ <div class="grid grid-cols-2 gap-6">
79
+ <div>
80
+ <label for="firstName">First Name</label>
81
+ <Field name="firstName" type="text" state={state} onChange={(e) => onChange(e, setState)} placeholder="Your first name..." />
82
+ </div>
83
+ <div>
84
+ <label for="lastName">Last Name</label>
85
+ <Field name="lastName" type="text" state={state} onChange={(e) => onChange(e, setState)} placeholder="Your last name..." />
86
+ </div>
87
+ </div>
88
+ <div>
89
+ <label for="password">Choose a Password</label>
90
+ <Field name="password" type="password" state={state} onChange={(e) => onChange(e, setState)} />
91
+ </div>
92
+ <div>
93
+ <label for="password2">Repeat Your Password</label>
94
+ <Field name="password2" type="password" state={state} onChange={(e) => onChange(e, setState)} />
95
+ </div>
96
+
97
+ <div class="mb-14">
98
+ Already have an account? <Link to="/signin" class="underline2 is-active">Sign in here</Link> first then revisit this link.
99
+ <FormError state={state} className="pt-2" />
100
+ </div>
101
+
102
+ <Elements.Button class="w-full" isLoading={isLoading} type="submit">Accept Invite & Create Account</Elements.Button>
103
+ </form>
104
+ </div>
105
+ )
106
+ }
@@ -15,7 +15,7 @@ export function Signup({ className, elements, redirectTo }: signupProps) {
15
15
  const [state, setState] = useState({
16
16
  email: injectedConfig.env === 'development' ? (injectedConfig.placeholderEmail || '') : '',
17
17
  name: injectedConfig.env === 'development' ? 'Bruce Wayne' : '',
18
- business: { name: injectedConfig.env === 'development' ? 'Wayne Enterprises' : '' },
18
+ company: { business: { name: injectedConfig.env === 'development' ? 'Wayne Enterprises' : '' } },
19
19
  password: injectedConfig.env === 'development' ? '' : '',
20
20
  errors: [] as Errors,
21
21
  })
@@ -49,8 +49,11 @@ export function Signup({ className, elements, redirectTo }: signupProps) {
49
49
  />
50
50
  </div>
51
51
  <div>
52
- <label for="business.name">Company Name</label>
53
- <Field name="business.name" placeholder="E.g. Wayne Enterprises" state={state} onChange={(e) => onChange(e, setState)} />
52
+ <label for="company.business.name">Company Name</label>
53
+ <Field name="company.business.name" placeholder="E.g. Wayne Enterprises" state={state}
54
+ onChange={(e) => onChange(e, setState)}
55
+ errorTitle={/business\.name/}
56
+ />
54
57
  </div>
55
58
  </div>
56
59
  <div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.183",
3
+ "version": "0.0.185",
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 🚀",
@@ -0,0 +1,268 @@
1
+ // --- Enums ------------------------------------
2
+
3
+ /**
4
+ * @typedef {'af'|'al'|'dz'|'ad'|'ao'|'ag'|'ar'|'am'|'au'|'at'|'az'|'bs'|'bh'|'bd'|'bb'|'by'|'be'|'bz'|'bj'|'bt'|'bo'|'ba'|'bw'|'br'|
5
+ * 'bn'|'bg'|'bf'|'bi'|'cv'|'kh'|'cm'|'ca'|'cf'|'td'|'cl'|'cn'|'co'|'km'|'cg'|'cr'|'hr'|'cu'|'cy'|'cz'|'cd'|'dk'|'dj'|'dm'|'do'|'ec'|
6
+ * 'eg'|'sv'|'gq'|'er'|'ee'|'sz'|'et'|'fj'|'fi'|'fr'|'ga'|'gm'|'ge'|'de'|'gh'|'gr'|'gd'|'gt'|'gn'|'gw'|'gy'|'ht'|'hn'|'hu'|'is'|
7
+ * 'in'|'id'|'ir'|'iq'|'ie'|'il'|'it'|'jm'|'jp'|'jo'|'kz'|'ke'|'ki'|'kw'|'kg'|'la'|'lv'|'lb'|'ls'|'lr'|'ly'|'li'|'lt'|'lu'|'mg'|
8
+ * 'mw'|'my'|'mv'|'ml'|'mt'|'mh'|'mr'|'mu'|'mx'|'fm'|'md'|'mc'|'mn'|'me'|'ma'|'mz'|'mm'|'na'|'nr'|'np'|'nl'|'nz'|'ni'|'ne'|'ng'|
9
+ * 'kp'|'mk'|'no'|'om'|'pk'|'pw'|'pa'|'pg'|'py'|'pe'|'ph'|'pl'|'pt'|'qa'|'ro'|'ru'|'rw'|'kn'|'lc'|'vc'|'ws'|'sm'|'st'|'sa'|'sn'|
10
+ * 'rs'|'sc'|'sl'|'sg'|'sk'|'si'|'sb'|'so'|'za'|'kr'|'ss'|'es'|'lk'|'sd'|'sr'|'se'|'ch'|'sy'|'tj'|'tz'|'th'|'tl'|'tg'|'to'|'tt'|
11
+ * 'tn'|'tr'|'tm'|'tv'|'ug'|'ua'|'ae'|'gb'|'us'|'uy'|'uz'|'vu'|'va'|'ve'|'vn'|'ye'|'zm'|'zw'} Country
12
+ * @typedef {'nzd'|'aud'|'usd'|'gbp'|'btc'|'aed'|'ars'|'bdt'|'bhd'|'brl'|'cad'|'chf'|'clp'|'cny'|'cop'|'czk'|'dkk'|'egp'|'eur'|
13
+ * 'hkd'|'huf'|'idr'|'ils'|'inr'|'jod'|'jpy'|'kes'|'krw'|'kwd'|'lkr'|'mad'|'mxn'|'myr'|'ngn'|'nok'|'omr'|'pen'|'php'|'pkt'|
14
+ * 'pln'|'qar'|'ron'|'rub'|'sar'|'sek'|'sgd'|'thb'|'try'|'twd'|'uah'|'vnd'|'zar'} Currency
15
+ */
16
+
17
+ /** @type {{ [key in Currency]: { name: string, symbol: string, digits: number } }} */
18
+ export const currencies = {
19
+ nzd: { name: 'New Zealand Dollar', symbol: '$', digits: 2 },
20
+ aud: { name: 'Australian Dollar', symbol: '$', digits: 2 },
21
+ usd: { name: 'US Dollar', symbol: '$', digits: 2 },
22
+ gbp: { name: 'Great Britain Pound', symbol: '£', digits: 2 },
23
+ btc: { name: 'Bitcoin', symbol: '₿', digits: 8 },
24
+ aed: { name: 'UAE Dirham', symbol: 'د.إ', digits: 2 },
25
+ ars: { name: 'Argentine Peso', symbol: '$', digits: 2 },
26
+ bdt: { name: 'Bangladeshi Taka', symbol: '৳', digits: 2 },
27
+ bhd: { name: 'Bahraini Dinar', symbol: '.د.ب', digits: 3 },
28
+ brl: { name: 'Brazilian Real', symbol: 'R$', digits: 2 },
29
+ cad: { name: 'Canadian Dollar', symbol: '$', digits: 2 },
30
+ chf: { name: 'Swiss Franc', symbol: 'Fr', digits: 2 },
31
+ clp: { name: 'Chilean Peso', symbol: '$', digits: 0 },
32
+ cny: { name: 'Chinese Yuan', symbol: '¥', digits: 2 },
33
+ cop: { name: 'Colombian Peso', symbol: '$', digits: 2 },
34
+ czk: { name: 'Czech Koruna', symbol: 'Kč', digits: 2 },
35
+ dkk: { name: 'Danish Krone', symbol: 'kr', digits: 2 },
36
+ egp: { name: 'Egyptian Pound', symbol: '£', digits: 2 },
37
+ eur: { name: 'Euro', symbol: '€', digits: 2 },
38
+ hkd: { name: 'Hong Kong Dollar', symbol: '$', digits: 2 },
39
+ huf: { name: 'Hungarian Forint', symbol: 'Ft', digits: 0 },
40
+ idr: { name: 'Indonesian Rupiah', symbol: 'Rp', digits: 0 },
41
+ ils: { name: 'Israeli Shekel', symbol: '₪', digits: 2 },
42
+ inr: { name: 'Indian Rupee', symbol: '₹', digits: 2 },
43
+ jod: { name: 'Jordanian Dinar', symbol: 'د.ا', digits: 3 },
44
+ jpy: { name: 'Japanese Yen', symbol: '¥', digits: 0 },
45
+ kes: { name: 'Kenyan Shilling', symbol: 'Sh', digits: 2 },
46
+ krw: { name: 'South Korean Won', symbol: '₩', digits: 0 },
47
+ kwd: { name: 'Kuwaiti Dinar', symbol: 'د.ك', digits: 3 },
48
+ lkr: { name: 'Sri Lankan Rupee', symbol: 'Rs', digits: 2 },
49
+ mad: { name: 'Moroccan Dirham', symbol: 'د.م.', digits: 2 },
50
+ mxn: { name: 'Mexican Peso', symbol: '$', digits: 2 },
51
+ myr: { name: 'Malaysian Ringgit', symbol: 'RM', digits: 2 },
52
+ ngn: { name: 'Nigerian Naira', symbol: '₦', digits: 2 },
53
+ nok: { name: 'Norwegian Krone', symbol: 'kr', digits: 2 },
54
+ omr: { name: 'Omani Rial', symbol: '﷼', digits: 3 },
55
+ pen: { name: 'Peruvian Sol', symbol: 'S/', digits: 2 },
56
+ php: { name: 'Philippine Peso', symbol: '₱', digits: 2 },
57
+ pkt: { name: 'Pakistani Rupee', symbol: '₨', digits: 2 },
58
+ pln: { name: 'Polish Zloty', symbol: 'zł', digits: 2 },
59
+ qar: { name: 'Qatari Riyal', symbol: '﷼', digits: 2 },
60
+ ron: { name: 'Romanian Leu', symbol: 'lei', digits: 2 },
61
+ rub: { name: 'Russian Ruble', symbol: '₽', digits: 2 },
62
+ sar: { name: 'Saudi Riyal', symbol: '﷼', digits: 2 },
63
+ sek: { name: 'Swedish Krona', symbol: 'kr', digits: 2 },
64
+ sgd: { name: 'Singapore Dollar', symbol: '$', digits: 2 },
65
+ thb: { name: 'Thai Baht', symbol: '฿', digits: 2 },
66
+ try: { name: 'Turkish Lira', symbol: '₺', digits: 2 },
67
+ twd: { name: 'New Taiwan Dollar', symbol: 'NT$', digits: 2 },
68
+ uah: { name: 'Ukrainian Hryvnia', symbol: '₴', digits: 2 },
69
+ vnd: { name: 'Vietnamese Dong', symbol: '₫', digits: 0 },
70
+ zar: { name: 'South African Rand', symbol: 'R', digits: 2 },
71
+ }
72
+
73
+ /** @type {{ [key in Country]: { name: string } }} */
74
+ export const countries = {
75
+ af: { name: 'Afghanistan' },
76
+ al: { name: 'Albania' },
77
+ dz: { name: 'Algeria' },
78
+ ad: { name: 'Andorra' },
79
+ ao: { name: 'Angola' },
80
+ ag: { name: 'Antigua and Barbuda' },
81
+ ar: { name: 'Argentina' },
82
+ am: { name: 'Armenia' },
83
+ au: { name: 'Australia' },
84
+ at: { name: 'Austria' },
85
+ az: { name: 'Azerbaijan' },
86
+ bs: { name: 'Bahamas' },
87
+ bh: { name: 'Bahrain' },
88
+ bd: { name: 'Bangladesh' },
89
+ bb: { name: 'Barbados' },
90
+ by: { name: 'Belarus' },
91
+ be: { name: 'Belgium' },
92
+ bz: { name: 'Belize' },
93
+ bj: { name: 'Benin' },
94
+ bt: { name: 'Bhutan' },
95
+ bo: { name: 'Bolivia' },
96
+ ba: { name: 'Bosnia and Herzegovina' },
97
+ bw: { name: 'Botswana' },
98
+ br: { name: 'Brazil' },
99
+ bn: { name: 'Brunei' },
100
+ bg: { name: 'Bulgaria' },
101
+ bf: { name: 'Burkina Faso' },
102
+ bi: { name: 'Burundi' },
103
+ cv: { name: 'Cabo Verde' },
104
+ kh: { name: 'Cambodia' },
105
+ cm: { name: 'Cameroon' },
106
+ ca: { name: 'Canada' },
107
+ cf: { name: 'Central African Republic' },
108
+ td: { name: 'Chad' },
109
+ cl: { name: 'Chile' },
110
+ cn: { name: 'China' },
111
+ co: { name: 'Colombia' },
112
+ km: { name: 'Comoros' },
113
+ cg: { name: 'Congo (Congo-Brazzaville)' },
114
+ cr: { name: 'Costa Rica' },
115
+ hr: { name: 'Croatia' },
116
+ cu: { name: 'Cuba' },
117
+ cy: { name: 'Cyprus' },
118
+ cz: { name: 'Czechia' },
119
+ cd: { name: 'Democratic Republic of the Congo' },
120
+ dk: { name: 'Denmark' },
121
+ dj: { name: 'Djibouti' },
122
+ dm: { name: 'Dominica' },
123
+ do: { name: 'Dominican Republic' },
124
+ ec: { name: 'Ecuador' },
125
+ eg: { name: 'Egypt' },
126
+ sv: { name: 'El Salvador' },
127
+ gq: { name: 'Equatorial Guinea' },
128
+ er: { name: 'Eritrea' },
129
+ ee: { name: 'Estonia' },
130
+ sz: { name: 'Eswatini' },
131
+ et: { name: 'Ethiopia' },
132
+ fj: { name: 'Fiji' },
133
+ fi: { name: 'Finland' },
134
+ fr: { name: 'France' },
135
+ ga: { name: 'Gabon' },
136
+ gm: { name: 'Gambia' },
137
+ ge: { name: 'Georgia' },
138
+ de: { name: 'Germany' },
139
+ gh: { name: 'Ghana' },
140
+ gr: { name: 'Greece' },
141
+ gd: { name: 'Grenada' },
142
+ gt: { name: 'Guatemala' },
143
+ gn: { name: 'Guinea' },
144
+ gw: { name: 'Guinea-Bissau' },
145
+ gy: { name: 'Guyana' },
146
+ ht: { name: 'Haiti' },
147
+ hn: { name: 'Honduras' },
148
+ hu: { name: 'Hungary' },
149
+ is: { name: 'Iceland' },
150
+ in: { name: 'India' },
151
+ id: { name: 'Indonesia' },
152
+ ir: { name: 'Iran' },
153
+ iq: { name: 'Iraq' },
154
+ ie: { name: 'Ireland' },
155
+ il: { name: 'Israel' },
156
+ it: { name: 'Italy' },
157
+ jm: { name: 'Jamaica' },
158
+ jp: { name: 'Japan' },
159
+ jo: { name: 'Jordan' },
160
+ kz: { name: 'Kazakhstan' },
161
+ ke: { name: 'Kenya' },
162
+ ki: { name: 'Kiribati' },
163
+ kw: { name: 'Kuwait' },
164
+ kg: { name: 'Kyrgyzstan' },
165
+ la: { name: 'Laos' },
166
+ lv: { name: 'Latvia' },
167
+ lb: { name: 'Lebanon' },
168
+ ls: { name: 'Lesotho' },
169
+ lr: { name: 'Liberia' },
170
+ ly: { name: 'Libya' },
171
+ li: { name: 'Liechtenstein' },
172
+ lt: { name: 'Lithuania' },
173
+ lu: { name: 'Luxembourg' },
174
+ mg: { name: 'Madagascar' },
175
+ mw: { name: 'Malawi' },
176
+ my: { name: 'Malaysia' },
177
+ mv: { name: 'Maldives' },
178
+ ml: { name: 'Mali' },
179
+ mt: { name: 'Malta' },
180
+ mh: { name: 'Marshall Islands' },
181
+ mr: { name: 'Mauritania' },
182
+ mu: { name: 'Mauritius' },
183
+ mx: { name: 'Mexico' },
184
+ fm: { name: 'Micronesia' },
185
+ md: { name: 'Moldova' },
186
+ mc: { name: 'Monaco' },
187
+ mn: { name: 'Mongolia' },
188
+ me: { name: 'Montenegro' },
189
+ ma: { name: 'Morocco' },
190
+ mz: { name: 'Mozambique' },
191
+ mm: { name: 'Myanmar' },
192
+ na: { name: 'Namibia' },
193
+ nr: { name: 'Nauru' },
194
+ np: { name: 'Nepal' },
195
+ nl: { name: 'Netherlands' },
196
+ nz: { name: 'New Zealand' },
197
+ ni: { name: 'Nicaragua' },
198
+ ne: { name: 'Niger' },
199
+ ng: { name: 'Nigeria' },
200
+ kp: { name: 'North Korea' },
201
+ mk: { name: 'North Macedonia' },
202
+ no: { name: 'Norway' },
203
+ om: { name: 'Oman' },
204
+ pk: { name: 'Pakistan' },
205
+ pw: { name: 'Palau' },
206
+ pa: { name: 'Panama' },
207
+ pg: { name: 'Papua New Guinea' },
208
+ py: { name: 'Paraguay' },
209
+ pe: { name: 'Peru' },
210
+ ph: { name: 'Philippines' },
211
+ pl: { name: 'Poland' },
212
+ pt: { name: 'Portugal' },
213
+ qa: { name: 'Qatar' },
214
+ ro: { name: 'Romania' },
215
+ ru: { name: 'Russia' },
216
+ rw: { name: 'Rwanda' },
217
+ kn: { name: 'Saint Kitts and Nevis' },
218
+ lc: { name: 'Saint Lucia' },
219
+ vc: { name: 'Saint Vincent and the Grenadines' },
220
+ ws: { name: 'Samoa' },
221
+ sm: { name: 'San Marino' },
222
+ st: { name: 'Sao Tome and Principe' },
223
+ sa: { name: 'Saudi Arabia' },
224
+ sn: { name: 'Senegal' },
225
+ rs: { name: 'Serbia' },
226
+ sc: { name: 'Seychelles' },
227
+ sl: { name: 'Sierra Leone' },
228
+ sg: { name: 'Singapore' },
229
+ sk: { name: 'Slovakia' },
230
+ si: { name: 'Slovenia' },
231
+ sb: { name: 'Solomon Islands' },
232
+ so: { name: 'Somalia' },
233
+ za: { name: 'South Africa' },
234
+ kr: { name: 'South Korea' },
235
+ ss: { name: 'South Sudan' },
236
+ es: { name: 'Spain' },
237
+ lk: { name: 'Sri Lanka' },
238
+ sd: { name: 'Sudan' },
239
+ sr: { name: 'Suriname' },
240
+ se: { name: 'Sweden' },
241
+ ch: { name: 'Switzerland' },
242
+ sy: { name: 'Syria' },
243
+ tj: { name: 'Tajikistan' },
244
+ tz: { name: 'Tanzania' },
245
+ th: { name: 'Thailand' },
246
+ tl: { name: 'Timor-Leste' },
247
+ tg: { name: 'Togo' },
248
+ to: { name: 'Tonga' },
249
+ tt: { name: 'Trinidad and Tobago' },
250
+ tn: { name: 'Tunisia' },
251
+ tr: { name: 'Turkey' },
252
+ tm: { name: 'Turkmenistan' },
253
+ tv: { name: 'Tuvalu' },
254
+ ug: { name: 'Uganda' },
255
+ ua: { name: 'Ukraine' },
256
+ ae: { name: 'United Arab Emirates' },
257
+ gb: { name: 'United Kingdom' },
258
+ us: { name: 'United States' },
259
+ uy: { name: 'Uruguay' },
260
+ uz: { name: 'Uzbekistan' },
261
+ vu: { name: 'Vanuatu' },
262
+ va: { name: 'Vatican City' },
263
+ ve: { name: 'Venezuela' },
264
+ vn: { name: 'Vietnam' },
265
+ ye: { name: 'Yemen' },
266
+ zm: { name: 'Zambia' },
267
+ zw: { name: 'Zimbabwe' },
268
+ }
package/server/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  // @ts-nocheck
2
2
  export * from '../util.js'
3
3
  export * as util from '../util.js'
4
+ export { currencies, countries } from './constants.js'
4
5
 
5
6
  /**
6
- * Re-export the MiddlewareConfig type from nitro-web/server
7
+ * Re-export types from nitro-web/server
7
8
  * @typedef {import('./router.js').MiddlewareConfig} MiddlewareConfig
9
+ * @typedef {import('./constants.js').Country} Country
10
+ * @typedef {import('./constants.js').Currency} Currency
8
11
  */
9
12
 
10
13
  // Export models
@@ -13,17 +13,20 @@ export default {
13
13
  phone: { type: 'string' },
14
14
  website: { type: 'string', isURL: true },
15
15
  },
16
- status: { type: 'string', default: 'active', enum: ['active', 'unpaid', 'deleted'] },
16
+ status: { type: 'string', default: 'active', enum: ['active', 'unpaid', 'deleted'], required: true },
17
17
  users: [{
18
- _id: { model: 'user' },
19
- role: { type: 'string', enum: ['owner', 'manager', 'accountant'] },
20
- status: { type: 'string', required: true, enum: ['invited', 'active', 'deleted'] },
21
- inviteEmail: { type: 'string' },
22
- inviteToken: { type: 'string' },
18
+ _id: { model: 'user', required: true },
19
+ role: { type: 'string', enum: ['owner', 'manager'], required: true },
20
+ status: { type: 'string', default: 'active', enum: ['active', 'deleted'], required: true },
21
+ }],
22
+ invites: [{
23
+ email: { type: 'email', required: true },
24
+ role: { type: 'string', enum: ['owner', 'manager'], required: true },
25
+ inviteToken: { type: 'string', required: true },
23
26
  }],
24
27
  },
25
28
 
26
- findBL: ['users.inviteToken'],
29
+ findBL: ['invites.token'],
27
30
  updateBL: ['status', 'users'],
28
31
 
29
32
  afterFind: [
@@ -34,8 +37,6 @@ export default {
34
37
  for (let i=data.users.length; i--;) {
35
38
  const user = data.users[i]
36
39
  const userExpanded = data.usersExpanded.find(o => String(o._id) == String(user._id))
37
- // console.log(userExpanded)
38
- if (user.inviteEmail) user.email = user.inviteEmail
39
40
  if (userExpanded) Object.assign(user, { ...userExpanded, name: fullName(userExpanded) })
40
41
  }
41
42
  delete data.usersExpanded
@@ -5,25 +5,26 @@ export default {
5
5
 
6
6
  fields: {
7
7
  avatar: { type: 'image' },
8
- company: { model: 'company', required: true },
8
+ company: { model: 'company', required: true }, // AKA "active company"
9
9
  email: { type: 'email', required: true, index: 'unique' },
10
- isInvited: { type: 'boolean' },
10
+ isAdmin: { type: 'boolean', default: false },
11
11
  firstName: { type: 'string', required: true },
12
12
  lastName: { type: 'string', required: true },
13
- status: { type: 'string', default: 'active', enum: ['active', 'deleted', 'inactive'] },
14
13
  stripeCustomer: { type: 'any' },
15
14
  stripeSubscription: { type: 'any' },
16
15
  stripeIntents: { type: 'any' },
17
- type: { type: 'string', default: 'user', enum: ['user', 'admin'] },
18
16
  usedFreeTrial: { type: 'boolean', default: false },
19
17
  // hidden fields
20
18
  password: { type: 'string', minLength: 6 },
21
- inviteToken: { type: 'string' },
22
19
  resetToken: { type: 'string' },
20
+ // If single tenancy application
21
+ // status: { type: 'string', default: 'active', enum: ['active', 'deleted'] },
22
+ // isInvited: { type: 'boolean' }
23
+ // inviteToken: { type: 'string' },
23
24
  },
24
25
 
25
26
  findBL: ['password', 'inviteToken', 'resetToken'],
26
- updateBL: ['password', 'inviteToken', 'resetToken', 'company', 'status', 'stripeSubscription', 'type', 'usedFreeTrial'],
27
+ updateBL: ['password', 'inviteToken', 'resetToken', 'company', 'status', 'stripeSubscription', 'isAdmin', 'usedFreeTrial'],
27
28
 
28
29
  messages: {
29
30
  lastName: {
package/server/router.js CHANGED
@@ -404,7 +404,7 @@ export const middleware = {
404
404
  }
405
405
 
406
406
  export function isAdminUser(req) {
407
- return (req.user?.type?.match(/admin/) || req.user?.isAdmin) ? true : false
407
+ return req.user?.isAdmin ? true : false
408
408
  }
409
409
 
410
410
  export function isValidUserOrRespond(req, res) {
@@ -424,7 +424,7 @@ export function isValidUserOrRespond(req, res) {
424
424
  function isValidParamCompanyUserOrRespond(req, res, checkIsOwner = false) {
425
425
  const _company = req.user?.company?._id?.toString() == req.params.cid ? req.user.company : false
426
426
  const company = _company || req.user?.companies?.find((o) => o._id.toString() == req.params.cid)
427
- const isCompanyOwner = company?.users?.find((o) => o._id.toString() == req.user?._id?.toString() && o.type === 'owner')
427
+ const isCompanyOwner = company?.users?.find((o) => o._id.toString() == req.user?._id?.toString() && o.role === 'owner')
428
428
  if (!isValidUserOrRespond(req, res)) return
429
429
  else if (!isAdminUser(req) && !company) res.unauthorized('You are not authorised to make this request.')
430
430
  else if (!isAdminUser(req) && checkIsOwner && !isCompanyOwner) res.unauthorized('Only owners can make this request.')
@@ -1,37 +1,48 @@
1
- export function findUserFromProvider(query: any, passwordToCheck: any, ...args: any[]): Promise<any>;
2
- export function getStore(user: any): Promise<{
3
- user: any;
4
- }>;
5
- export function signinAndGetStore(user: any, isDesktop: any, getStore: any): Promise<any>;
6
- export function userCreate({ business, password, ...userDataProp }: {
7
- [x: string]: any;
8
- business: any;
9
- password: any;
10
- }): Promise<any>;
11
- export function tokenCreate(id: any): Promise<any>;
12
- export function tokenParse(token: any): any;
13
- export function validatePassword(password: string, password2: any): Promise<void>;
14
1
  export function resetInstructions(req: any, res: any): Promise<void>;
15
2
  export function inviteInstructions(req: any, res: any): Promise<void>;
16
- export function inviteConfirm(req: any, res: any): Promise<void>;
17
3
  export function resetConfirm(req: any, res: any): Promise<void>;
18
- export function inviteOrResetConfirm(type: any, req: any): Promise<any>;
4
+ export function inviteConfirm(req: any, res: any): Promise<void>;
5
+ export function userFindFromProvider(query: any, passwordToCheck: any, ...args: any[]): Promise<any>;
6
+ export function userSigninGetStore(user: any, isDesktop: any): Promise<any>;
7
+ export function getStore(user: any): Promise<{
8
+ user: any;
9
+ }>;
10
+ /**
11
+ * Creates a new user and company (if multi tenant and `user.company` is not an id)
12
+ * @param {object} userData - user data
13
+ * @param {string} [userData.password] - optional
14
+ * @param {string} [userData.password2] - optional, to confirm the password
15
+ * @param {string} [userData.company] - if multi tenant and `user.company` is not an id, create a new company
16
+ * @param {boolean} [skipSendEmail=false] - whether to skip sending the welcome email
17
+ * @returns {Promise<object>} - the created user
18
+ */
19
+ export function userCreate({ password, password2, company, ...userDataProp }: {
20
+ password?: string;
21
+ password2?: string;
22
+ company?: string;
23
+ }, skipSendEmail?: boolean): Promise<object>;
24
+ export function passwordValidate(password: string, password2: any): Promise<void>;
25
+ export function tokenCreate(modelName: any, id: any): Promise<any>;
26
+ export function tokenParse(token: any, modelName: any, maxAgeMs?: number): any;
27
+ export function tokenConfirmForReset(req: any): Promise<any>;
28
+ export function tokenConfirmForSingleTenant(req: any, isReset: any): Promise<any>;
29
+ export function tokenConfirmForMultiTenant(req: any): Promise<any>;
19
30
  /**
20
- * Checks if the user exists, updates the user with the invite token and sends the invite email
31
+ * Creates and sends a reset or invite token to a user or company
21
32
  * @param {object} options
22
- * @param {'reset' | 'invite'} options.type - The type of token to send (default: 'reset')
23
- * @param {{_id: string, email: string, firstName: string}} options.user - The user to send the invite email to
24
- * @param {function} [options.beforeUpdate] - callback hook to run before updating the user
25
- * @param {function} [options.beforeSendEmail] - callback hook to run before sending the email
33
+ * @param {'reset' | 'invite' | 'companyInvite'} options.type - token type (default: 'reset')
34
+ * @param {string} options._id - user or company id
35
+ * @param {string} options.email - recipient email
36
+ * @param {string} options.firstName - recipient first name
37
+ * @param {function} [options.beforeUpdate] - runs before updating the model with the token, return null to skip update
38
+ * @param {function} [options.beforeSendEmail] - runs before sending the email, receives (options, token)
26
39
  * @returns {Promise<{token: string, mailgunPromise: Promise<unknown>}>}
27
40
  */
28
- export function sendToken({ type, user, beforeUpdate, beforeSendEmail }: {
29
- type: "reset" | "invite";
30
- user: {
31
- _id: string;
32
- email: string;
33
- firstName: string;
34
- };
41
+ export function tokenSend({ type, _id, email, firstName, beforeUpdate, beforeSendEmail }: {
42
+ type: "reset" | "invite" | "companyInvite";
43
+ _id: string;
44
+ email: string;
45
+ firstName: string;
35
46
  beforeUpdate?: Function;
36
47
  beforeSendEmail?: Function;
37
48
  }): Promise<{
@@ -44,26 +55,17 @@ export const routes: {
44
55
  'post /api/signin': (typeof signin)[];
45
56
  'post /api/signup': (typeof signup)[];
46
57
  'post /api/reset-instructions': (typeof resetInstructions)[];
47
- 'post /api/reset-password': (typeof resetConfirm)[];
58
+ 'post /api/reset-confirm': (typeof resetConfirm)[];
48
59
  'post /api/invite-instructions': (typeof inviteInstructions)[];
49
- 'post /api/invite-accept': (typeof inviteConfirm)[];
60
+ 'post /api/invite-confirm': (typeof inviteConfirm)[];
50
61
  'delete /api/account/:uid': (typeof remove)[];
51
62
  setup: typeof setup;
52
- findUserFromProvider: typeof findUserFromProvider;
53
- getStore: typeof getStore;
54
- signinAndGetStore: typeof signinAndGetStore;
55
- tokenCreate: typeof tokenCreate;
56
- tokenParse: typeof tokenParse;
57
- userCreate: typeof userCreate;
58
- validatePassword: typeof validatePassword;
59
- sendToken: typeof sendToken;
60
- inviteOrResetConfirm: typeof inviteOrResetConfirm;
61
63
  };
62
64
  declare function store(req: any, res: any): Promise<void>;
63
65
  declare function signout(req: any, res: any): void;
64
66
  declare function signin(req: any, res: any): any;
65
67
  declare function signup(req: any, res: any): Promise<void>;
66
68
  declare function remove(req: any, res: any): Promise<void>;
67
- declare function setup(middleware: any, _config: any): void;
69
+ declare function setup(middleware: any, _config: any, helpers?: {}): void;
68
70
  export {};
69
71
  //# sourceMappingURL=auth.api.d.ts.map
@@ -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,CAoCtE;AApbD;;;;;;;;;;;;;;;;;;;;EA6BC;AAmED,0DAEC;AAkCD,mDAEC;AAnBD,iDAeC;AA9BD,2DAaC;AAuBD,2DAwBC;AAjID,4DA+DC"}
1
+ {"version":3,"file":"auth.api.d.ts","sourceRoot":"","sources":["../../../components/auth/auth.api.js"],"names":[],"mappings":"AAuKA,qEAeC;AAED,sEAsCC;AAED,gEAMC;AAED,iEAgBC;AAID,qGA8CC;AAED,4EAOC;AAED;;GAKC;AAID;;;;;;;;GAQG;AACH,8EANG;IAA0B,QAAQ,GAA1B,MAAM;IACY,SAAS,GAA3B,MAAM;IACY,OAAO,GAAzB,MAAM;CACd,kBAAQ,OAAO,GACL,OAAO,CAAC,MAAM,CAAC,CA0D3B;AAED,kFAiBC;AAED,mEAOC;AAED,+EAWC;AAED,6DAEC;AAED,kFAoBC;AAED,mEA4BC;AAED;;;;;;;;;;GAUG;AACH,0FARG;IAAsD,IAAI,EAAlD,OAAO,GAAG,QAAQ,GAAG,eAAe;IACpB,GAAG,EAAnB,MAAM;IACU,KAAK,EAArB,MAAM;IACU,SAAS,EAAzB,MAAM;IACa,YAAY;IACZ,eAAe;CAC1C,GAAU,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAC,CAAC,CAuCtE;AA9fD;;;;;;;;;;;EAaC;AAyED,0DAEC;AA6BD,mDAEC;AAnBD,iDAeC;AAzBD,2DAQC;AAuBD,2DAwBC;AAlID,0EAqEC"}