Skip to content

Commit 72e3efa

Browse files
authored
improvement(settings): ui/ux (#1021)
* completed general * completed environment * completed account; updated general and environment * fixed skeleton * finished credentials * finished privacy; adjusted all colors and styling * added reset password * refactor: team and subscription * finalized subscription settings * fixed copilot key UI
1 parent b40fa3a commit 72e3efa

File tree

52 files changed

+2507
-1848
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2507
-1848
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { eq } from 'drizzle-orm'
2+
import { type NextRequest, NextResponse } from 'next/server'
3+
import { z } from 'zod'
4+
import { getSession } from '@/lib/auth'
5+
import { createLogger } from '@/lib/logs/console/logger'
6+
import { db } from '@/db'
7+
import { user } from '@/db/schema'
8+
9+
const logger = createLogger('UpdateUserProfileAPI')
10+
11+
// Schema for updating user profile
12+
const UpdateProfileSchema = z
13+
.object({
14+
name: z.string().min(1, 'Name is required').optional(),
15+
})
16+
.refine((data) => data.name !== undefined, {
17+
message: 'Name field must be provided',
18+
})
19+
20+
export const dynamic = 'force-dynamic'
21+
22+
export async function PATCH(request: NextRequest) {
23+
const requestId = crypto.randomUUID().slice(0, 8)
24+
25+
try {
26+
const session = await getSession()
27+
28+
if (!session?.user?.id) {
29+
logger.warn(`[${requestId}] Unauthorized profile update attempt`)
30+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
31+
}
32+
33+
const userId = session.user.id
34+
const body = await request.json()
35+
36+
const validatedData = UpdateProfileSchema.parse(body)
37+
38+
// Build update object
39+
const updateData: any = { updatedAt: new Date() }
40+
if (validatedData.name !== undefined) updateData.name = validatedData.name
41+
42+
// Update user profile
43+
const [updatedUser] = await db
44+
.update(user)
45+
.set(updateData)
46+
.where(eq(user.id, userId))
47+
.returning()
48+
49+
if (!updatedUser) {
50+
return NextResponse.json({ error: 'User not found' }, { status: 404 })
51+
}
52+
53+
logger.info(`[${requestId}] User profile updated`, {
54+
userId,
55+
updatedFields: Object.keys(validatedData),
56+
})
57+
58+
return NextResponse.json({
59+
success: true,
60+
user: {
61+
id: updatedUser.id,
62+
name: updatedUser.name,
63+
email: updatedUser.email,
64+
image: updatedUser.image,
65+
},
66+
})
67+
} catch (error: any) {
68+
if (error instanceof z.ZodError) {
69+
logger.warn(`[${requestId}] Invalid profile data`, {
70+
errors: error.errors,
71+
})
72+
return NextResponse.json(
73+
{ error: 'Invalid profile data', details: error.errors },
74+
{ status: 400 }
75+
)
76+
}
77+
78+
logger.error(`[${requestId}] Profile update error`, error)
79+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
80+
}
81+
}
82+
83+
// GET endpoint to fetch current user profile
84+
export async function GET() {
85+
const requestId = crypto.randomUUID().slice(0, 8)
86+
87+
try {
88+
const session = await getSession()
89+
90+
if (!session?.user?.id) {
91+
logger.warn(`[${requestId}] Unauthorized profile fetch attempt`)
92+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
93+
}
94+
95+
const userId = session.user.id
96+
97+
const [userRecord] = await db
98+
.select({
99+
id: user.id,
100+
name: user.name,
101+
email: user.email,
102+
image: user.image,
103+
emailVerified: user.emailVerified,
104+
})
105+
.from(user)
106+
.where(eq(user.id, userId))
107+
.limit(1)
108+
109+
if (!userRecord) {
110+
return NextResponse.json({ error: 'User not found' }, { status: 404 })
111+
}
112+
113+
return NextResponse.json({
114+
user: userRecord,
115+
})
116+
} catch (error: any) {
117+
logger.error(`[${requestId}] Profile fetch error`, error)
118+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
119+
}
120+
}

apps/sim/app/globals.css

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,23 +206,22 @@
206206
}
207207

208208
::-webkit-scrollbar-track {
209-
background-color: hsl(var(--scrollbar-track));
210-
border-radius: var(--radius);
209+
background: transparent;
211210
}
212211

213212
::-webkit-scrollbar-thumb {
214-
background-color: hsl(var(--scrollbar-thumb));
213+
background-color: hsl(var(--muted-foreground) / 0.3);
215214
border-radius: var(--radius);
216215
}
217216

218217
::-webkit-scrollbar-thumb:hover {
219-
background-color: hsl(var(--scrollbar-thumb-hover));
218+
background-color: hsl(var(--muted-foreground) / 0.3);
220219
}
221220

222221
/* For Firefox */
223222
* {
224223
scrollbar-width: thin;
225-
scrollbar-color: hsl(var(--scrollbar-thumb)) hsl(var(--scrollbar-track));
224+
scrollbar-color: hsl(var(--muted-foreground) / 0.3) transparent;
226225
}
227226
}
228227

apps/sim/app/workspace/[workspaceId]/w/components/search-modal/search-modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ export function SearchModal({
586586
className='bg-white/50 dark:bg-black/50'
587587
style={{ backdropFilter: 'blur(1.5px)' }}
588588
/>
589-
<DialogPrimitive.Content className='data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 flex h-[580px] w-[700px] translate-x-[-50%] translate-y-[-50%] flex-col gap-0 overflow-hidden rounded-[8px] border border-border bg-background p-0 focus:outline-none focus-visible:outline-none data-[state=closed]:animate-out data-[state=open]:animate-in'>
589+
<DialogPrimitive.Content className='data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 flex h-[580px] w-[700px] translate-x-[-50%] translate-y-[-50%] flex-col gap-0 overflow-hidden rounded-[10px] border border-border bg-background p-0 focus:outline-none focus-visible:outline-none data-[state=closed]:animate-out data-[state=open]:animate-in'>
590590
<VisuallyHidden.Root>
591591
<DialogTitle>Search</DialogTitle>
592592
</VisuallyHidden.Root>

0 commit comments

Comments
 (0)