Loading...
;
- if (error)
- return (
-
-
+
+
+
+ Hello{' '}
+ {isLoading ? 'Loading...' : data?.data.user?.name || 'Unknown User'}
+
+
+
+
);
}
diff --git a/src/app/api/user/[user]/calendar/route.ts b/src/app/api/user/[user]/calendar/route.ts
index 62142e9..f6b6098 100644
--- a/src/app/api/user/[user]/calendar/route.ts
+++ b/src/app/api/user/[user]/calendar/route.ts
@@ -136,15 +136,15 @@ export const GET = auth(async function GET(req, { params }) {
start_time: 'asc',
},
select: {
- id: true,
- reason: true,
+ id: requestUserId === requestedUserId ? true : false,
+ reason: requestUserId === requestedUserId ? true : false,
start_time: true,
end_time: true,
- is_recurring: true,
- recurrence_end_date: true,
- rrule: true,
- created_at: true,
- updated_at: true,
+ is_recurring: requestUserId === requestedUserId ? true : false,
+ recurrence_end_date: requestUserId === requestedUserId ? true : false,
+ rrule: requestUserId === requestedUserId ? true : false,
+ created_at: requestUserId === requestedUserId ? true : false,
+ updated_at: requestUserId === requestedUserId ? true : false,
},
},
},
@@ -167,7 +167,6 @@ export const GET = auth(async function GET(req, { params }) {
calendar.push({ ...event.meeting, type: 'event' });
} else {
calendar.push({
- id: event.meeting.id,
start_time: event.meeting.start_time,
end_time: event.meeting.end_time,
type: 'blocked_private',
@@ -183,7 +182,6 @@ export const GET = auth(async function GET(req, { params }) {
calendar.push({ ...event, type: 'event' });
} else {
calendar.push({
- id: event.id,
start_time: event.start_time,
end_time: event.end_time,
type: 'blocked_private',
@@ -192,35 +190,23 @@ export const GET = auth(async function GET(req, { params }) {
}
for (const slot of requestedUser.blockedSlots) {
- if (requestUserId === requestedUserId) {
- calendar.push({
- start_time: slot.start_time,
- end_time: slot.end_time,
- id: slot.id,
- reason: slot.reason,
- is_recurring: slot.is_recurring,
- recurrence_end_date: slot.recurrence_end_date,
- rrule: slot.rrule,
- created_at: slot.created_at,
- updated_at: slot.updated_at,
- type: 'blocked_owned',
- });
- } else {
- calendar.push({
- start_time: slot.start_time,
- end_time: slot.end_time,
- id: slot.id,
- type: 'blocked_private',
- });
- }
+ calendar.push({
+ start_time: slot.start_time,
+ end_time: slot.end_time,
+ id: slot.id,
+ reason: slot.reason,
+ is_recurring: slot.is_recurring,
+ recurrence_end_date: slot.recurrence_end_date,
+ rrule: slot.rrule,
+ created_at: slot.created_at,
+ updated_at: slot.updated_at,
+ type:
+ requestUserId === requestedUserId ? 'blocked_owned' : 'blocked_private',
+ });
}
return returnZodTypeCheckedResponse(UserCalendarResponseSchema, {
success: true,
- calendar: calendar.filter(
- (event, index, self) =>
- self.findIndex((e) => e.id === event.id && e.type === event.type) ===
- index,
- ),
+ calendar,
});
});
diff --git a/src/app/api/user/[user]/calendar/validation.ts b/src/app/api/user/[user]/calendar/validation.ts
index 1572793..a0d179f 100644
--- a/src/app/api/user/[user]/calendar/validation.ts
+++ b/src/app/api/user/[user]/calendar/validation.ts
@@ -13,28 +13,23 @@ export const BlockedSlotSchema = zod
start_time: eventStartTimeSchema,
end_time: eventEndTimeSchema,
type: zod.literal('blocked_private'),
- id: zod.string(),
})
.openapi('BlockedSlotSchema', {
description: 'Blocked time slot in the user calendar',
});
-export const OwnedBlockedSlotSchema = zod
- .object({
- start_time: eventStartTimeSchema,
- end_time: eventEndTimeSchema,
- id: zod.string(),
- reason: zod.string().nullish(),
- is_recurring: zod.boolean().default(false),
- recurrence_end_date: zod.date().nullish(),
- rrule: zod.string().nullish(),
- created_at: zod.date().nullish(),
- updated_at: zod.date().nullish(),
- type: zod.literal('blocked_owned'),
- })
- .openapi('OwnedBlockedSlotSchema', {
- description: 'Blocked slot owned by the user',
- });
+export const OwnedBlockedSlotSchema = BlockedSlotSchema.extend({
+ id: zod.string(),
+ reason: zod.string().nullish(),
+ is_recurring: zod.boolean().default(false),
+ recurrence_end_date: zod.date().nullish(),
+ rrule: zod.string().nullish(),
+ created_at: zod.date().nullish(),
+ updated_at: zod.date().nullish(),
+ type: zod.literal('blocked_owned'),
+}).openapi('OwnedBlockedSlotSchema', {
+ description: 'Blocked slot owned by the user',
+});
export const VisibleSlotSchema = EventSchema.omit({
organizer: true,
diff --git a/src/app/api/user/me/password/route.ts b/src/app/api/user/me/password/route.ts
deleted file mode 100644
index 0b92559..0000000
--- a/src/app/api/user/me/password/route.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import { auth } from '@/auth';
-import { prisma } from '@/prisma';
-import { updateUserPasswordServerSchema } from '../validation';
-import {
- returnZodTypeCheckedResponse,
- userAuthenticated,
-} from '@/lib/apiHelpers';
-import { FullUserResponseSchema } from '../../validation';
-import {
- ErrorResponseSchema,
- ZodErrorResponseSchema,
-} from '@/app/api/validation';
-import bcrypt from 'bcryptjs';
-
-export const PATCH = auth(async function PATCH(req) {
- const authCheck = userAuthenticated(req);
- if (!authCheck.continue)
- return returnZodTypeCheckedResponse(
- ErrorResponseSchema,
- authCheck.response,
- authCheck.metadata,
- );
-
- const body = await req.json();
- const parsedBody = updateUserPasswordServerSchema.safeParse(body);
- if (!parsedBody.success)
- return returnZodTypeCheckedResponse(
- ZodErrorResponseSchema,
- {
- success: false,
- message: 'Invalid request data',
- errors: parsedBody.error.issues,
- },
- { status: 400 },
- );
-
- const { current_password, new_password } = parsedBody.data;
-
- const dbUser = await prisma.user.findUnique({
- where: {
- id: authCheck.user.id,
- },
- include: {
- accounts: true,
- },
- });
-
- if (!dbUser)
- return returnZodTypeCheckedResponse(
- ErrorResponseSchema,
- {
- success: false,
- message: 'User not found',
- },
- { status: 404 },
- );
-
- if (!dbUser.password_hash)
- return returnZodTypeCheckedResponse(
- ErrorResponseSchema,
- {
- success: false,
- message: 'User does not have a password set',
- },
- { status: 400 },
- );
-
- if (
- dbUser.accounts.length === 0 ||
- dbUser.accounts[0].provider !== 'credentials'
- )
- return returnZodTypeCheckedResponse(
- ErrorResponseSchema,
- {
- success: false,
- message: 'Credentials login is not enabled for this user',
- },
- { status: 400 },
- );
-
- const isCurrentPasswordValid = await bcrypt.compare(
- current_password,
- dbUser.password_hash || '',
- );
-
- if (!isCurrentPasswordValid)
- return returnZodTypeCheckedResponse(
- ErrorResponseSchema,
- {
- success: false,
- message: 'Current password is incorrect',
- },
- { status: 401 },
- );
-
- const hashedNewPassword = await bcrypt.hash(new_password, 10);
-
- const updatedUser = await prisma.user.update({
- where: {
- id: dbUser.id,
- },
- data: {
- password_hash: hashedNewPassword,
- },
- select: {
- id: true,
- name: true,
- first_name: true,
- last_name: true,
- email: true,
- image: true,
- timezone: true,
- created_at: true,
- updated_at: true,
- },
- });
-
- return returnZodTypeCheckedResponse(FullUserResponseSchema, {
- success: true,
- user: updatedUser,
- });
-});
diff --git a/src/app/api/user/me/password/swagger.ts b/src/app/api/user/me/password/swagger.ts
deleted file mode 100644
index 0bc62f0..0000000
--- a/src/app/api/user/me/password/swagger.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
-import { FullUserResponseSchema } from '../../validation';
-import { updateUserPasswordServerSchema } from '../validation';
-import {
- invalidRequestDataResponse,
- notAuthenticatedResponse,
- serverReturnedDataValidationErrorResponse,
- userNotFoundResponse,
-} from '@/lib/defaultApiResponses';
-
-export default function registerSwaggerPaths(registry: OpenAPIRegistry) {
- registry.registerPath({
- method: 'patch',
- path: '/api/user/me/password',
- description: 'Update the password of the currently authenticated user',
- request: {
- body: {
- description: 'User password update request body',
- required: true,
- content: {
- 'application/json': {
- schema: updateUserPasswordServerSchema,
- },
- },
- },
- },
- responses: {
- 200: {
- description: 'User information updated successfully',
- content: {
- 'application/json': {
- schema: FullUserResponseSchema,
- },
- },
- },
- ...invalidRequestDataResponse,
- ...notAuthenticatedResponse,
- ...userNotFoundResponse,
- ...serverReturnedDataValidationErrorResponse,
- },
- tags: ['User'],
- });
-}
diff --git a/src/app/api/user/me/route.ts b/src/app/api/user/me/route.ts
index 5571a6b..5ba9792 100644
--- a/src/app/api/user/me/route.ts
+++ b/src/app/api/user/me/route.ts
@@ -8,7 +8,6 @@ import {
import { FullUserResponseSchema } from '../validation';
import {
ErrorResponseSchema,
- SuccessResponseSchema,
ZodErrorResponseSchema,
} from '@/app/api/validation';
@@ -118,43 +117,3 @@ export const PATCH = auth(async function PATCH(req) {
{ status: 200 },
);
});
-
-export const DELETE = auth(async function DELETE(req) {
- const authCheck = userAuthenticated(req);
- if (!authCheck.continue)
- return returnZodTypeCheckedResponse(
- ErrorResponseSchema,
- authCheck.response,
- authCheck.metadata,
- );
-
- const dbUser = await prisma.user.findUnique({
- where: {
- id: authCheck.user.id,
- },
- });
- if (!dbUser)
- return returnZodTypeCheckedResponse(
- ErrorResponseSchema,
- {
- success: false,
- message: 'User not found',
- },
- { status: 404 },
- );
-
- await prisma.user.delete({
- where: {
- id: authCheck.user.id,
- },
- });
-
- return returnZodTypeCheckedResponse(
- SuccessResponseSchema,
- {
- success: true,
- message: 'User deleted successfully',
- },
- { status: 200 },
- );
-});
diff --git a/src/app/api/user/me/swagger.ts b/src/app/api/user/me/swagger.ts
index 6a9e375..e0a36a1 100644
--- a/src/app/api/user/me/swagger.ts
+++ b/src/app/api/user/me/swagger.ts
@@ -7,7 +7,6 @@ import {
serverReturnedDataValidationErrorResponse,
userNotFoundResponse,
} from '@/lib/defaultApiResponses';
-import { SuccessResponseSchema } from '../../validation';
export default function registerSwaggerPaths(registry: OpenAPIRegistry) {
registry.registerPath({
@@ -61,24 +60,4 @@ export default function registerSwaggerPaths(registry: OpenAPIRegistry) {
},
tags: ['User'],
});
-
- registry.registerPath({
- method: 'delete',
- path: '/api/user/me',
- description: 'Delete the currently authenticated user',
- responses: {
- 200: {
- description: 'User deleted successfully',
- content: {
- 'application/json': {
- schema: SuccessResponseSchema,
- },
- },
- },
- ...notAuthenticatedResponse,
- ...userNotFoundResponse,
- ...serverReturnedDataValidationErrorResponse,
- },
- tags: ['User'],
- });
}
diff --git a/src/app/api/user/me/validation.ts b/src/app/api/user/me/validation.ts
index 66f07cc..49c6219 100644
--- a/src/app/api/user/me/validation.ts
+++ b/src/app/api/user/me/validation.ts
@@ -4,8 +4,6 @@ import {
lastNameSchema,
newUserEmailServerSchema,
newUserNameServerSchema,
- passwordSchema,
- timezoneSchema,
} from '@/app/api/user/validation';
// ----------------------------------------
@@ -18,16 +16,6 @@ export const updateUserServerSchema = zod.object({
first_name: firstNameSchema.optional(),
last_name: lastNameSchema.optional(),
email: newUserEmailServerSchema.optional(),
- image: zod.url().optional(),
- timezone: timezoneSchema.optional(),
+ image: zod.string().optional(),
+ timezone: zod.string().optional(),
});
-
-export const updateUserPasswordServerSchema = zod
- .object({
- current_password: zod.string().min(1, 'Current password is required'),
- new_password: passwordSchema,
- confirm_new_password: passwordSchema,
- })
- .refine((data) => data.new_password === data.confirm_new_password, {
- message: 'New password and confirm new password must match',
- });
diff --git a/src/app/api/user/validation.ts b/src/app/api/user/validation.ts
index 89b8ba4..79b1e7e 100644
--- a/src/app/api/user/validation.ts
+++ b/src/app/api/user/validation.ts
@@ -1,7 +1,6 @@
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
import { prisma } from '@/prisma';
import zod from 'zod/v4';
-import { allTimeZones } from '@/lib/timezones';
extendZodWithOpenApi(zod);
@@ -108,15 +107,6 @@ export const passwordSchema = zod
'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character',
);
-// ----------------------------------------
-//
-// Timezone Validation
-//
-// ----------------------------------------
-export const timezoneSchema = zod.enum(allTimeZones).openapi('Timezone', {
- description: 'Valid timezone from the list of supported timezones',
-});
-
// ----------------------------------------
//
// User Schema Validation (for API responses)
@@ -129,11 +119,8 @@ export const FullUserSchema = zod
first_name: zod.string().nullish(),
last_name: zod.string().nullish(),
email: zod.email(),
- image: zod.url().nullish(),
- timezone: zod
- .string()
- .refine((i) => (allTimeZones as string[]).includes(i))
- .nullish(),
+ image: zod.string().nullish(),
+ timezone: zod.string(),
created_at: zod.date(),
updated_at: zod.date(),
})
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 47cec2d..af40867 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -3,8 +3,6 @@ import { ThemeProvider } from '@/components/wrappers/theme-provider';
import type { Metadata } from 'next';
import './globals.css';
import { QueryProvider } from '@/components/wrappers/query-provider';
-import { Toaster } from '@/components/ui/sonner';
-import { SessionProvider } from 'next-auth/react';
export const metadata: Metadata = {
title: 'MeetUp',
@@ -52,17 +50,14 @@ export default function RootLayout({
-
-
- {children}
-
-
-
+
+ {children}
+