@betterstart/cli 0.1.79 → 0.1.81
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/package.json
CHANGED
|
@@ -9,6 +9,7 @@ import { updateEmail } from '@cms/actions/profile'
|
|
|
9
9
|
import { Avatar, AvatarFallback, AvatarImage } from '@cms/components/ui/avatar'
|
|
10
10
|
import { Button } from '@cms/components/ui/button'
|
|
11
11
|
import { Input } from '@cms/components/ui/input'
|
|
12
|
+
import { LoaderCircle } from 'lucide-react'
|
|
12
13
|
import {
|
|
13
14
|
Form,
|
|
14
15
|
FormControl,
|
|
@@ -18,7 +19,14 @@ import {
|
|
|
18
19
|
FormMessage,
|
|
19
20
|
} from '@cms/components/ui/form'
|
|
20
21
|
import { ImageUploadField } from '@cms/components/ui/image-upload-field'
|
|
21
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
Card,
|
|
24
|
+
CardContent,
|
|
25
|
+
CardDescription,
|
|
26
|
+
CardFooter,
|
|
27
|
+
CardHeader,
|
|
28
|
+
CardTitle,
|
|
29
|
+
} from '@cms/components/ui/card'
|
|
22
30
|
import { useRouter } from 'next/navigation'
|
|
23
31
|
import { useState } from 'react'
|
|
24
32
|
|
|
@@ -80,12 +88,12 @@ export function ProfileForm({ user }: ProfileFormProps) {
|
|
|
80
88
|
})
|
|
81
89
|
|
|
82
90
|
const emailDirty = profileForm.watch('email') !== user.email
|
|
91
|
+
const imageValue = profileForm.watch('image')
|
|
83
92
|
|
|
84
93
|
async function onProfileSubmit(values: ProfileValues) {
|
|
85
94
|
setProfilePending(true)
|
|
86
95
|
|
|
87
96
|
try {
|
|
88
|
-
// Update name and image via Better Auth
|
|
89
97
|
const { error } = await authClient.updateUser({
|
|
90
98
|
name: values.name,
|
|
91
99
|
image: values.image ?? null,
|
|
@@ -97,7 +105,6 @@ export function ProfileForm({ user }: ProfileFormProps) {
|
|
|
97
105
|
return
|
|
98
106
|
}
|
|
99
107
|
|
|
100
|
-
// If email changed, update via server action
|
|
101
108
|
if (values.email !== user.email) {
|
|
102
109
|
if (!values.currentPasswordForEmail) {
|
|
103
110
|
profileForm.setError('currentPasswordForEmail', {
|
|
@@ -158,202 +165,195 @@ export function ProfileForm({ user }: ProfileFormProps) {
|
|
|
158
165
|
}
|
|
159
166
|
}
|
|
160
167
|
|
|
161
|
-
const imageValue = profileForm.watch('image')
|
|
162
|
-
|
|
163
168
|
return (
|
|
164
169
|
<div className="space-y-6">
|
|
165
|
-
{/* Profile Section */}
|
|
166
170
|
<Form {...profileForm}>
|
|
167
|
-
<form
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
)}
|
|
245
|
-
/>
|
|
246
|
-
|
|
247
|
-
{emailDirty && (
|
|
248
|
-
<FormField
|
|
249
|
-
control={profileForm.control}
|
|
250
|
-
name="currentPasswordForEmail"
|
|
251
|
-
render={({ field: formField }) => (
|
|
252
|
-
<FormItem>
|
|
253
|
-
<FormLabel>Current Password</FormLabel>
|
|
254
|
-
<FormControl>
|
|
255
|
-
<Input
|
|
256
|
-
type="password"
|
|
257
|
-
placeholder="Enter current password to change email"
|
|
258
|
-
autoComplete="current-password"
|
|
259
|
-
disabled={profilePending}
|
|
260
|
-
{...formField}
|
|
261
|
-
/>
|
|
262
|
-
</FormControl>
|
|
263
|
-
<FormMessage />
|
|
264
|
-
</FormItem>
|
|
171
|
+
<form onSubmit={profileForm.handleSubmit(onProfileSubmit)}>
|
|
172
|
+
<Card className="material-sm!">
|
|
173
|
+
<CardHeader>
|
|
174
|
+
<div className="flex items-center gap-4">
|
|
175
|
+
<Avatar className="size-12">
|
|
176
|
+
<AvatarImage src={imageValue || undefined} />
|
|
177
|
+
<AvatarFallback className="text-lg font-semibold">
|
|
178
|
+
{user.name?.charAt(0) ?? '?'}
|
|
179
|
+
</AvatarFallback>
|
|
180
|
+
</Avatar>
|
|
181
|
+
<div>
|
|
182
|
+
<CardTitle>Profile</CardTitle>
|
|
183
|
+
<CardDescription>
|
|
184
|
+
Update your name, email, and profile picture
|
|
185
|
+
</CardDescription>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</CardHeader>
|
|
189
|
+
<CardContent className="space-y-6">
|
|
190
|
+
<FormField
|
|
191
|
+
control={profileForm.control}
|
|
192
|
+
name="name"
|
|
193
|
+
render={({ field: formField }) => (
|
|
194
|
+
<FormItem>
|
|
195
|
+
<FormLabel>Name</FormLabel>
|
|
196
|
+
<FormControl>
|
|
197
|
+
<Input
|
|
198
|
+
type="text"
|
|
199
|
+
placeholder="Your name"
|
|
200
|
+
disabled={profilePending}
|
|
201
|
+
{...formField}
|
|
202
|
+
/>
|
|
203
|
+
</FormControl>
|
|
204
|
+
<FormMessage />
|
|
205
|
+
</FormItem>
|
|
206
|
+
)}
|
|
207
|
+
/>
|
|
208
|
+
|
|
209
|
+
<FormField
|
|
210
|
+
control={profileForm.control}
|
|
211
|
+
name="email"
|
|
212
|
+
render={({ field: formField }) => (
|
|
213
|
+
<FormItem>
|
|
214
|
+
<FormLabel>Email</FormLabel>
|
|
215
|
+
<FormControl>
|
|
216
|
+
<Input
|
|
217
|
+
type="email"
|
|
218
|
+
placeholder="you@example.com"
|
|
219
|
+
disabled={profilePending}
|
|
220
|
+
{...formField}
|
|
221
|
+
/>
|
|
222
|
+
</FormControl>
|
|
223
|
+
<FormMessage />
|
|
224
|
+
</FormItem>
|
|
225
|
+
)}
|
|
226
|
+
/>
|
|
227
|
+
|
|
228
|
+
{emailDirty && (
|
|
229
|
+
<FormField
|
|
230
|
+
control={profileForm.control}
|
|
231
|
+
name="currentPasswordForEmail"
|
|
232
|
+
render={({ field: formField }) => (
|
|
233
|
+
<FormItem>
|
|
234
|
+
<FormLabel>Current Password</FormLabel>
|
|
235
|
+
<FormControl>
|
|
236
|
+
<Input
|
|
237
|
+
type="password"
|
|
238
|
+
placeholder="Enter current password to change email"
|
|
239
|
+
autoComplete="current-password"
|
|
240
|
+
disabled={profilePending}
|
|
241
|
+
{...formField}
|
|
242
|
+
/>
|
|
243
|
+
</FormControl>
|
|
244
|
+
<FormMessage />
|
|
245
|
+
</FormItem>
|
|
246
|
+
)}
|
|
247
|
+
/>
|
|
265
248
|
)}
|
|
266
|
-
/>
|
|
267
|
-
)}
|
|
268
249
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
250
|
+
<FormField
|
|
251
|
+
control={profileForm.control}
|
|
252
|
+
name="image"
|
|
253
|
+
render={({ field: formField }) => (
|
|
254
|
+
<FormItem>
|
|
255
|
+
<FormLabel>Profile Picture</FormLabel>
|
|
256
|
+
<FormControl>
|
|
257
|
+
<ImageUploadField
|
|
258
|
+
value={formField.value}
|
|
259
|
+
onChange={formField.onChange}
|
|
260
|
+
onBlur={formField.onBlur}
|
|
261
|
+
disabled={profilePending}
|
|
262
|
+
maxSizeInMB={5}
|
|
263
|
+
label=""
|
|
264
|
+
/>
|
|
265
|
+
</FormControl>
|
|
266
|
+
<FormMessage />
|
|
267
|
+
</FormItem>
|
|
268
|
+
)}
|
|
269
|
+
/>
|
|
270
|
+
</CardContent>
|
|
271
|
+
<CardFooter>
|
|
272
|
+
<Button type="submit" disabled={profilePending || !profileForm.formState.isDirty} size="sm" className="ml-auto min-w-25">
|
|
273
|
+
{profilePending && <LoaderCircle className="animate-spin" />}
|
|
274
|
+
{profilePending ? 'Saving...' : 'Save'}
|
|
275
|
+
</Button>
|
|
276
|
+
</CardFooter>
|
|
277
|
+
</Card>
|
|
274
278
|
</form>
|
|
275
279
|
</Form>
|
|
276
280
|
|
|
277
|
-
{/* Password Section */}
|
|
278
281
|
<Form {...passwordForm}>
|
|
279
|
-
<form
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
{passwordPending ? 'Changing...' : 'Change Password'}
|
|
355
|
-
</Button>
|
|
356
|
-
</div>
|
|
282
|
+
<form onSubmit={passwordForm.handleSubmit(onPasswordSubmit)}>
|
|
283
|
+
<Card className="material-sm!">
|
|
284
|
+
<CardHeader>
|
|
285
|
+
<CardTitle>Change Password</CardTitle>
|
|
286
|
+
<CardDescription>
|
|
287
|
+
Update your password to keep your account secure
|
|
288
|
+
</CardDescription>
|
|
289
|
+
</CardHeader>
|
|
290
|
+
<CardContent className="space-y-6">
|
|
291
|
+
<FormField
|
|
292
|
+
control={passwordForm.control}
|
|
293
|
+
name="currentPassword"
|
|
294
|
+
render={({ field: formField }) => (
|
|
295
|
+
<FormItem>
|
|
296
|
+
<FormLabel>Current Password</FormLabel>
|
|
297
|
+
<FormControl>
|
|
298
|
+
<Input
|
|
299
|
+
type="password"
|
|
300
|
+
placeholder="Enter current password"
|
|
301
|
+
autoComplete="current-password"
|
|
302
|
+
disabled={passwordPending}
|
|
303
|
+
{...formField}
|
|
304
|
+
/>
|
|
305
|
+
</FormControl>
|
|
306
|
+
<FormMessage />
|
|
307
|
+
</FormItem>
|
|
308
|
+
)}
|
|
309
|
+
/>
|
|
310
|
+
|
|
311
|
+
<FormField
|
|
312
|
+
control={passwordForm.control}
|
|
313
|
+
name="newPassword"
|
|
314
|
+
render={({ field: formField }) => (
|
|
315
|
+
<FormItem>
|
|
316
|
+
<FormLabel>New Password</FormLabel>
|
|
317
|
+
<FormControl>
|
|
318
|
+
<Input
|
|
319
|
+
type="password"
|
|
320
|
+
placeholder="Enter new password"
|
|
321
|
+
autoComplete="new-password"
|
|
322
|
+
disabled={passwordPending}
|
|
323
|
+
{...formField}
|
|
324
|
+
/>
|
|
325
|
+
</FormControl>
|
|
326
|
+
<FormMessage />
|
|
327
|
+
</FormItem>
|
|
328
|
+
)}
|
|
329
|
+
/>
|
|
330
|
+
|
|
331
|
+
<FormField
|
|
332
|
+
control={passwordForm.control}
|
|
333
|
+
name="confirmPassword"
|
|
334
|
+
render={({ field: formField }) => (
|
|
335
|
+
<FormItem>
|
|
336
|
+
<FormLabel>Confirm New Password</FormLabel>
|
|
337
|
+
<FormControl>
|
|
338
|
+
<Input
|
|
339
|
+
type="password"
|
|
340
|
+
placeholder="Confirm new password"
|
|
341
|
+
autoComplete="new-password"
|
|
342
|
+
disabled={passwordPending}
|
|
343
|
+
{...formField}
|
|
344
|
+
/>
|
|
345
|
+
</FormControl>
|
|
346
|
+
<FormMessage />
|
|
347
|
+
</FormItem>
|
|
348
|
+
)}
|
|
349
|
+
/>
|
|
350
|
+
</CardContent>
|
|
351
|
+
<CardFooter>
|
|
352
|
+
<Button type="submit" disabled={passwordPending || !passwordForm.formState.isDirty} size="sm" className="ml-auto min-w-25">
|
|
353
|
+
{passwordPending ? 'Changing...' : 'Change Password'}
|
|
354
|
+
</Button>
|
|
355
|
+
</CardFooter>
|
|
356
|
+
</Card>
|
|
357
357
|
</form>
|
|
358
358
|
</Form>
|
|
359
359
|
</div>
|
|
@@ -20,7 +20,7 @@ export default async function ProfilePage() {
|
|
|
20
20
|
return (
|
|
21
21
|
<>
|
|
22
22
|
{showPageHeader && <PageHeader title="Profile" />}
|
|
23
|
-
<main className="container mx-auto max-w-
|
|
23
|
+
<main className="container mx-auto max-w-5xl pt-10 pb-20 w-full">
|
|
24
24
|
<ProfileForm
|
|
25
25
|
user={{
|
|
26
26
|
name: session.user.name,
|