Membuat use case dan controller untuk users repository
This commit is contained in:
parent
009bfc19c3
commit
4750f0055e
|
@ -52,11 +52,11 @@ function SubSubItemComponent({ item }: { item: SubSubItem }) {
|
|||
asChild
|
||||
className={
|
||||
isActive
|
||||
? "font-medium bg-primary/10 before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:bg-primary"
|
||||
? "bg-primary/10 active text-primary"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<a href={formattedUrl} className={isActive ? "text-primary" : ""}>
|
||||
<a href={formattedUrl}>
|
||||
<span>{item.title}</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
|
@ -77,13 +77,13 @@ function SubItemComponent({ item }: { item: SubItem }) {
|
|||
asChild
|
||||
className={
|
||||
isActive
|
||||
? "font-medium bg-primary/10 before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:bg-primary"
|
||||
? "bg-primary/10 active text-primary"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<a href={formattedUrl} className={isActive ? "text-primary" : ""}>
|
||||
<a href={formattedUrl}>
|
||||
{item.icon && (
|
||||
<item.icon className={isActive ? "text-primary" : ""} />
|
||||
<item.icon />
|
||||
)}
|
||||
<span>{item.title}</span>
|
||||
</a>
|
||||
|
@ -99,14 +99,14 @@ function SubItemComponent({ item }: { item: SubItem }) {
|
|||
<SidebarMenuButton
|
||||
className={
|
||||
isActive
|
||||
? "font-medium bg-primary/10 before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:bg-primary"
|
||||
? "bg-primary/10 active text-primary"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{item.icon && (
|
||||
<item.icon className={isActive ? "text-primary" : ""} />
|
||||
<item.icon />
|
||||
)}
|
||||
<span className={isActive ? "text-primary" : ""}>{item.title}</span>
|
||||
<span>{item.title}</span>
|
||||
<ChevronRight
|
||||
className={`ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 ${isActive ? "text-primary" : ""}`}
|
||||
/>
|
||||
|
@ -138,13 +138,13 @@ function RecursiveNavItem({ item, index }: { item: NavItem; index: number }) {
|
|||
asChild
|
||||
className={
|
||||
isActive
|
||||
? "font-medium bg-primary/10 before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:bg-primary"
|
||||
? "bg-primary/10 active text-primary"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<a href={formattedUrl} className={isActive ? "text-primary" : ""}>
|
||||
<a href={formattedUrl}>
|
||||
{item.icon && (
|
||||
<item.icon className={isActive ? "text-primary" : ""} />
|
||||
<item.icon />
|
||||
)}
|
||||
<span>{item.title}</span>
|
||||
</a>
|
||||
|
@ -166,14 +166,14 @@ function RecursiveNavItem({ item, index }: { item: NavItem; index: number }) {
|
|||
tooltip={item.title}
|
||||
className={
|
||||
isActive
|
||||
? "font-medium bg-primary/10 before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:bg-primary"
|
||||
? "bg-primary/10 active text-primary"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{item.icon && (
|
||||
<item.icon className={isActive ? "text-primary" : ""} />
|
||||
<item.icon />
|
||||
)}
|
||||
<span className={isActive ? "text-primary" : ""}>{item.title}</span>
|
||||
<span>{item.title}</span>
|
||||
{hasSubItems && (
|
||||
<ChevronRight
|
||||
className={`ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 ${isActive ? "text-primary" : ""}`}
|
||||
|
|
|
@ -25,8 +25,8 @@ function NavItemComponent({ item }: { item: NavItem }) {
|
|||
const isActive = router.pathname === item.url;
|
||||
|
||||
return (
|
||||
<SidebarMenuItem className={isActive ? "active text-primary" : ""}>
|
||||
<SidebarMenuButton tooltip={item.title} asChild>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton className={isActive ? "bg-primary/10 text-primary" : ""} tooltip={item.title} asChild>
|
||||
<a href={item.url}>
|
||||
<item.icon className="h-4 w-4" />
|
||||
<span>{item.title}</span>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
const WelcomePage = () => {
|
||||
return (
|
||||
<>
|
||||
<h1>Welcome to the dashboard</h1>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default WelcomePage;
|
|
@ -33,7 +33,7 @@ export function SignInForm({
|
|||
// setLoading(false);
|
||||
// };
|
||||
|
||||
const { isPending, handleSubmit, error, errors, clearError } = useSignInHandler();
|
||||
const { isPending, handleSignIn, error, errors, clearError } = useSignInHandler();
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -76,7 +76,7 @@ export function SignInForm({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4" {...props} noValidate>
|
||||
<form onSubmit={handleSignIn} className="space-y-4" {...props} noValidate>
|
||||
<FormField
|
||||
label="Email"
|
||||
input={
|
||||
|
|
|
@ -28,7 +28,7 @@ export function VerifyOtpForm({ className, ...props }: VerifyOtpFormProps) {
|
|||
const {
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
handleVerifyOtp,
|
||||
handleOtpChange,
|
||||
errors,
|
||||
isPending
|
||||
|
@ -44,7 +44,7 @@ export function VerifyOtpForm({ className, ...props }: VerifyOtpFormProps) {
|
|||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<form onSubmit={handleVerifyOtp} className="space-y-4">
|
||||
<input type="hidden" {...register("email")} />
|
||||
<div className="space-y-6">
|
||||
<Controller
|
||||
|
|
|
@ -25,6 +25,7 @@ export async function signIn(formData: FormData) {
|
|||
// }
|
||||
|
||||
return { success: true }
|
||||
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof InputParseError ||
|
||||
|
|
|
@ -54,7 +54,7 @@ export function useSignInHandler() {
|
|||
return {
|
||||
// formData,
|
||||
// handleChange,
|
||||
handleSubmit,
|
||||
handleSignIn: handleSubmit,
|
||||
error,
|
||||
isPending: signIn.isPending,
|
||||
errors: !!error || signIn.error,
|
||||
|
@ -123,7 +123,7 @@ export function useVerifyOtpHandler(email: string) {
|
|||
return {
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
handleVerifyOtp: handleSubmit,
|
||||
handleOtpChange,
|
||||
errors: {
|
||||
...errors,
|
||||
|
|
|
@ -1,38 +1,34 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
import { queryOptions, useMutation } from '@tanstack/react-query';
|
||||
import { signIn, signOut, verifyOtp } from './action';
|
||||
|
||||
export function useAuthActions() {
|
||||
// Sign In Mutation
|
||||
const signInMutation = useMutation({
|
||||
mutationKey: ["signIn"],
|
||||
mutationFn: async (formData: FormData) => {
|
||||
const email = formData.get("email")?.toString()
|
||||
const response = await signIn(formData);
|
||||
|
||||
// If the server action returns an error, treat it as an error for React Query
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
return { email };
|
||||
}
|
||||
});
|
||||
|
||||
const verifyOtpMutation = useMutation({
|
||||
mutationKey: ["verifyOtp"],
|
||||
mutationFn: async (formData: FormData) => {
|
||||
const email = formData.get("email")?.toString()
|
||||
const token = formData.get("token")?.toString()
|
||||
const response = await verifyOtp(formData);
|
||||
|
||||
// If the server action returns an error, treat it as an error for React Query
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
return { email, token };
|
||||
}
|
||||
})
|
||||
|
||||
const signOutMutation = useMutation({
|
||||
mutationKey: ["signOut"],
|
||||
mutationFn: async () => {
|
||||
const response = await signOut();
|
||||
|
||||
|
@ -40,8 +36,6 @@ export function useAuthActions() {
|
|||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { createModule } from '@evyweb/ioctopus';
|
|||
|
||||
|
||||
import { DI_SYMBOLS } from '@/di/types';
|
||||
import { UsersRepository } from '@/src/infrastructure/repositories/users.repository.impl';
|
||||
import { UsersRepository } from '@/src/infrastructure/repositories/users.repository';
|
||||
|
||||
|
||||
export function createUsersModule() {
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
import { createAdminClient } from "@/app/_utils/supabase/admin";
|
||||
import { createClient } from "@/app/_utils/supabase/client";
|
||||
import { CreateUser, InviteUser, UpdateUser, User, UserResponse } from "@/src/entities/models/users/users.model";
|
||||
import db from "@/prisma/db";
|
||||
import { DatabaseOperationError, NotFoundError } from "@/src/entities/errors/common";
|
||||
import { AuthenticationError } from "@/src/entities/errors/auth";
|
||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { ICrashReporterService } from "@/src/application/services/crash-reporter.service.interface";
|
||||
import { ITransaction } from "@/src/entities/models/transaction.interface";
|
||||
|
||||
export interface IUsersRepository {
|
||||
listUsers(): Promise<User[]>;
|
||||
getCurrentUser(): Promise<UserResponse>;
|
||||
getCurrentUser(): Promise<User>;
|
||||
getUserById(id: string): Promise<User | undefined>;
|
||||
getUserByUsername(username: string): Promise<User | undefined>;
|
||||
getUserByEmail(email: string): Promise<User | undefined>;
|
||||
createUser(input: CreateUser, tx?: ITransaction): Promise<User | null>;
|
||||
inviteUser(email: string, tx?: ITransaction): Promise<User | null>;
|
||||
updateUser(id: string, input: Partial<UpdateUser>, tx?: ITransaction): Promise<UserResponse>;
|
||||
deleteUser(id: string, tx?: ITransaction): Promise<void>;
|
||||
createUser(input: CreateUser, tx?: ITransaction): Promise<User>;
|
||||
inviteUser(email: string, tx?: ITransaction): Promise<User>;
|
||||
updateUser(id: string, input: Partial<UpdateUser>, tx?: ITransaction): Promise<User>;
|
||||
deleteUser(id: string, tx?: ITransaction): Promise<User>;
|
||||
banUser(id: string, ban_duration: string, tx?: ITransaction): Promise<User>;
|
||||
unbanUser(id: string, tx?: ITransaction): Promise<User>;
|
||||
}
|
||||
|
|
|
@ -19,9 +19,7 @@ export const banUserUseCase = (
|
|||
|
||||
const bannedUser = await usersRepository.banUser(id, ban_duration)
|
||||
|
||||
return {
|
||||
...bannedUser
|
||||
}
|
||||
return bannedUser
|
||||
}
|
||||
)
|
||||
}
|
|
@ -14,6 +14,7 @@ export const createUserUseCase = (
|
|||
) => async (input: CreateUser): Promise<User> => {
|
||||
return await instrumentationService.startSpan({ name: "createUser Use Case", op: "function" },
|
||||
async () => {
|
||||
|
||||
const existingUser = await usersRepository.getUserByEmail(input.email)
|
||||
|
||||
if (existingUser) {
|
||||
|
@ -26,13 +27,7 @@ export const createUserUseCase = (
|
|||
email_confirm: true
|
||||
})
|
||||
|
||||
if (!newUser) {
|
||||
throw new InputParseError("User not created")
|
||||
}
|
||||
|
||||
return {
|
||||
...newUser
|
||||
};
|
||||
return newUser
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,25 @@
|
|||
import { NotFoundError } from "@/src/entities/errors/common"
|
||||
import { IUsersRepository } from "../../repositories/users.repository.interface"
|
||||
import { IInstrumentationService } from "../../services/instrumentation.service.interface"
|
||||
import { User } from "@/src/entities/models/users/users.model"
|
||||
|
||||
export type IDeleteUserUseCase = ReturnType<typeof deleteUserUseCase>
|
||||
|
||||
const deleteUserUseCase = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
usersRepository: IUsersRepository
|
||||
) => async (id: string): Promise<void> => {
|
||||
) => async (id: string): Promise<User> => {
|
||||
return await instrumentationService.startSpan({ name: "deleteUser Use Case", op: "function" },
|
||||
async () => {
|
||||
await usersRepository.deleteUser(id)
|
||||
const user = await usersRepository.getUserById(id)
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundError("User not found")
|
||||
}
|
||||
|
||||
const deletedUser = await usersRepository.deleteUser(id)
|
||||
|
||||
return deletedUser
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
import { NotFoundError } from "@/src/entities/errors/common"
|
||||
import { IUsersRepository } from "../../repositories/users.repository.interface"
|
||||
import { IInstrumentationService } from "../../services/instrumentation.service.interface"
|
||||
import { UserResponse } from "@/src/entities/models/users/users.model"
|
||||
import { User, UserResponse } from "@/src/entities/models/users/users.model"
|
||||
import { AuthenticationError } from "@/src/entities/errors/auth"
|
||||
|
||||
|
||||
export type IGetCurrentUserUseCase = ReturnType<typeof getCurrentUserUseCase>
|
||||
|
@ -9,7 +10,7 @@ export type IGetCurrentUserUseCase = ReturnType<typeof getCurrentUserUseCase>
|
|||
export const getCurrentUserUseCase = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
usersRepository: IUsersRepository
|
||||
) => async (): Promise<UserResponse> => {
|
||||
) => async (): Promise<User> => {
|
||||
return await instrumentationService.startSpan({ name: "getCurrentUser Use Case", op: "function" },
|
||||
async () => {
|
||||
|
||||
|
@ -19,9 +20,7 @@ export const getCurrentUserUseCase = (
|
|||
throw new NotFoundError("User not found")
|
||||
}
|
||||
|
||||
return {
|
||||
...existingUser
|
||||
}
|
||||
return existingUser
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ export const getListUsersUseCase = (
|
|||
) => async (): Promise<User[]> => {
|
||||
return await instrumentationService.startSpan({ name: "getListUsers Use Case", op: "function" },
|
||||
async () => {
|
||||
return await usersRepository.listUsers()
|
||||
const users = await usersRepository.listUsers()
|
||||
|
||||
return users
|
||||
}
|
||||
)
|
||||
}
|
|
@ -12,15 +12,13 @@ const getUserByEmailUseCase = (
|
|||
return await instrumentationService.startSpan({ name: "getUserByEmail Use Case", op: "function" },
|
||||
async () => {
|
||||
|
||||
const existingUser = await usersRepository.getUserByEmail(email)
|
||||
const user = await usersRepository.getUserByEmail(email)
|
||||
|
||||
if (!existingUser) {
|
||||
if (!user) {
|
||||
throw new NotFoundError("User not found")
|
||||
}
|
||||
|
||||
return {
|
||||
...existingUser
|
||||
}
|
||||
return user
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -14,15 +14,13 @@ export const getUserByIdUseCase = (
|
|||
return await instrumentationService.startSpan({ name: "getUserById Use Case", op: "function" },
|
||||
async () => {
|
||||
|
||||
const existingUser = await usersRepository.getUserById(id)
|
||||
const user = await usersRepository.getUserById(id)
|
||||
|
||||
if (!existingUser) {
|
||||
if (!user) {
|
||||
throw new NotFoundError("User not found")
|
||||
}
|
||||
|
||||
return {
|
||||
...existingUser
|
||||
}
|
||||
return user
|
||||
}
|
||||
)
|
||||
}
|
|
@ -12,15 +12,13 @@ const getUserByUsernameUseCase = (
|
|||
return await instrumentationService.startSpan({ name: "getUserByUsername Use Case", op: "function" },
|
||||
async () => {
|
||||
|
||||
const existingUser = await usersRepository.getUserByUsername(username)
|
||||
const user = await usersRepository.getUserByUsername(username)
|
||||
|
||||
if (!existingUser) {
|
||||
if (!user) {
|
||||
throw new NotFoundError("User not found")
|
||||
}
|
||||
|
||||
return {
|
||||
...existingUser
|
||||
}
|
||||
return user
|
||||
}
|
||||
)
|
||||
}
|
|
@ -11,24 +11,22 @@ export const inviteUserUseCase = (
|
|||
instrumentationService: IInstrumentationService,
|
||||
usersRepository: IUsersRepository,
|
||||
authenticationService: IAuthenticationService,
|
||||
) => async (input: { email: string }): Promise<User> => {
|
||||
) => async (email: string): Promise<User> => {
|
||||
return await instrumentationService.startSpan({ name: "inviteUser Use Case", op: "function" },
|
||||
async () => {
|
||||
const existingUser = await usersRepository.getUserByEmail(input.email)
|
||||
const existingUser = await usersRepository.getUserByEmail(email)
|
||||
|
||||
if (existingUser) {
|
||||
throw new AuthenticationError("User already exists")
|
||||
}
|
||||
|
||||
const newUser = await usersRepository.inviteUser(input.email)
|
||||
const invitedUser = await usersRepository.inviteUser(email)
|
||||
|
||||
if (!newUser) {
|
||||
if (!invitedUser) {
|
||||
throw new AuthenticationError("User not invited")
|
||||
}
|
||||
|
||||
return {
|
||||
...newUser
|
||||
}
|
||||
return invitedUser
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { NotFoundError } from "@/src/entities/errors/common"
|
||||
import { IUsersRepository } from "../../repositories/users.repository.interface"
|
||||
import { IInstrumentationService } from "../../services/instrumentation.service.interface"
|
||||
import { User } from "@/src/entities/models/users/users.model"
|
||||
|
||||
export type IUnbanUserUseCase = ReturnType<typeof unbanUserUseCase>
|
||||
|
||||
export function unbanUserUseCase(
|
||||
instrumentationService: IInstrumentationService,
|
||||
usersRepository: IUsersRepository
|
||||
) {
|
||||
return async (id: string): Promise<User> => {
|
||||
return await instrumentationService.startSpan({ name: "unbanUser Use Case", op: "function" },
|
||||
async () => {
|
||||
const existingUser = await usersRepository.getUserById(id)
|
||||
|
||||
if (!existingUser) {
|
||||
throw new NotFoundError("User not found")
|
||||
}
|
||||
|
||||
const unbanUser = await usersRepository.unbanUser(id)
|
||||
|
||||
return unbanUser
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ export type IUpdateUserUseCase = ReturnType<typeof updateUserUseCase>
|
|||
const updateUserUseCase = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
usersRepository: IUsersRepository
|
||||
) => async (id: string, input: UpdateUser): Promise<UserResponse> => {
|
||||
) => async (id: string, input: UpdateUser): Promise<User> => {
|
||||
return await instrumentationService.startSpan({ name: "updateUser Use Case", op: "function" },
|
||||
async () => {
|
||||
|
||||
|
@ -20,9 +20,7 @@ const updateUserUseCase = (
|
|||
|
||||
const updatedUser = await usersRepository.updateUser(id, input)
|
||||
|
||||
return {
|
||||
...updatedUser
|
||||
}
|
||||
return updatedUser
|
||||
}
|
||||
)
|
||||
}
|
|
@ -6,7 +6,7 @@ import { createClient as createServerClient } from "@/app/_utils/supabase/server
|
|||
import { CreateUser, UpdateUser, User, UserResponse } from "@/src/entities/models/users/users.model";
|
||||
import { ITransaction } from "@/src/entities/models/transaction.interface";
|
||||
import db from "@/prisma/db";
|
||||
import { NotFoundError } from "@/src/entities/errors/common";
|
||||
import { DatabaseOperationError, NotFoundError } from "@/src/entities/errors/common";
|
||||
import { AuthenticationError } from "@/src/entities/errors/auth";
|
||||
|
||||
export class UsersRepository implements IUsersRepository {
|
||||
|
@ -39,6 +39,10 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
if (!users) {
|
||||
throw new NotFoundError("Users not found");
|
||||
}
|
||||
|
||||
return users;
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
||||
|
@ -71,8 +75,14 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
if (user)
|
||||
return user;
|
||||
if (!user) {
|
||||
throw new NotFoundError("User not found");
|
||||
}
|
||||
|
||||
return {
|
||||
...user,
|
||||
id,
|
||||
};
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
||||
throw err;
|
||||
|
@ -106,9 +116,13 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
if (user)
|
||||
return user;
|
||||
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundError("User not found");
|
||||
}
|
||||
|
||||
return user;
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
||||
throw err;
|
||||
|
@ -141,9 +155,11 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
if (user)
|
||||
return user;
|
||||
if (!user) {
|
||||
throw new NotFoundError("User not found");
|
||||
}
|
||||
|
||||
return user;
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
||||
throw err;
|
||||
|
@ -151,7 +167,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
})
|
||||
}
|
||||
|
||||
async getCurrentUser(): Promise<UserResponse> {
|
||||
async getCurrentUser(): Promise<User> {
|
||||
return await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > getCurrentUser",
|
||||
}, async () => {
|
||||
|
@ -160,7 +176,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
|
||||
const query = supabase.auth.getUser();
|
||||
|
||||
const user = await this.instrumentationService.startSpan({
|
||||
const { data, error } = await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > getCurrentUser > supabase.auth.getUser",
|
||||
op: "db:query",
|
||||
attributes: { "system": "supabase.auth" },
|
||||
|
@ -170,7 +186,18 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
return user;
|
||||
if (error) {
|
||||
throw new AuthenticationError("Failed to get current user");
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
throw new NotFoundError("User not found");
|
||||
}
|
||||
|
||||
return {
|
||||
...data,
|
||||
id: data.user.id,
|
||||
};
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
||||
throw err;
|
||||
|
@ -178,18 +205,14 @@ export class UsersRepository implements IUsersRepository {
|
|||
})
|
||||
}
|
||||
|
||||
async createUser(input: CreateUser, tx?: ITransaction): Promise<User | null> {
|
||||
async createUser(input: CreateUser, tx?: ITransaction): Promise<User> {
|
||||
return await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > createUser",
|
||||
}, async () => {
|
||||
try {
|
||||
const supabase = this.supabaseAdmin;
|
||||
|
||||
const query = supabase.auth.admin.createUser({
|
||||
email: input.email,
|
||||
password: input.password,
|
||||
email_confirm: input.email_confirm,
|
||||
})
|
||||
const query = supabase.auth.admin.createUser(input)
|
||||
|
||||
const { data: { user } } = await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > createUser > supabase.auth.admin.createUser",
|
||||
|
@ -201,6 +224,10 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
if (!user) {
|
||||
throw new DatabaseOperationError("Failed to create user");
|
||||
}
|
||||
|
||||
return user;
|
||||
|
||||
} catch (err) {
|
||||
|
@ -210,7 +237,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
})
|
||||
}
|
||||
|
||||
async inviteUser(email: string, tx?: ITransaction): Promise<User | null> {
|
||||
async inviteUser(email: string, tx?: ITransaction): Promise<User> {
|
||||
return await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > inviteUser",
|
||||
}, async () => {
|
||||
|
@ -229,6 +256,10 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
if (!user) {
|
||||
throw new DatabaseOperationError("Failed to invite user");
|
||||
}
|
||||
|
||||
return user;
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
||||
|
@ -237,7 +268,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
})
|
||||
}
|
||||
|
||||
async updateUser(id: string, input: Partial<UpdateUser>, tx?: ITransaction): Promise<UserResponse> {
|
||||
async updateUser(id: string, input: Partial<UpdateUser>, tx?: ITransaction): Promise<User> {
|
||||
return await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > updateUser",
|
||||
}, async () => {
|
||||
|
@ -267,7 +298,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
)
|
||||
|
||||
if (error) {
|
||||
throw new AuthenticationError(error.message);
|
||||
throw new DatabaseOperationError("Failed to update user");
|
||||
}
|
||||
|
||||
const queryGetUser = db.users.findUnique({
|
||||
|
@ -332,18 +363,13 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
if (!updatedUser) {
|
||||
throw new DatabaseOperationError("Failed to update user");
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
user: {
|
||||
...data.user,
|
||||
role: updatedUser.role,
|
||||
profile: {
|
||||
user_id: id,
|
||||
...updatedUser.profile,
|
||||
},
|
||||
},
|
||||
},
|
||||
error: null,
|
||||
...updatedUser,
|
||||
id,
|
||||
};
|
||||
|
||||
} catch (err) {
|
||||
|
@ -353,7 +379,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
})
|
||||
}
|
||||
|
||||
async deleteUser(id: string, tx?: ITransaction): Promise<void> {
|
||||
async deleteUser(id: string, tx?: ITransaction): Promise<User> {
|
||||
return await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > deleteUser",
|
||||
}, async () => {
|
||||
|
@ -362,7 +388,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
|
||||
const query = supabase.auth.admin.deleteUser(id);
|
||||
|
||||
await this.instrumentationService.startSpan({
|
||||
const { data: user, error } = await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > deleteUser > supabase.auth.admin.deleteUser",
|
||||
op: "db:query",
|
||||
attributes: { "system": "supabase.auth" },
|
||||
|
@ -372,7 +398,14 @@ export class UsersRepository implements IUsersRepository {
|
|||
}
|
||||
)
|
||||
|
||||
return;
|
||||
if (error) {
|
||||
throw new DatabaseOperationError("Failed to delete user");
|
||||
}
|
||||
|
||||
return {
|
||||
...user,
|
||||
id
|
||||
};
|
||||
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
||||
|
@ -392,7 +425,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
ban_duration: ban_duration ?? "100h",
|
||||
})
|
||||
|
||||
const { data, error } = await this.instrumentationService.startSpan({
|
||||
const { data: user, error } = await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > banUser > supabase.auth.admin.updateUserById",
|
||||
op: "db:query",
|
||||
attributes: { "system": "supabase.auth" },
|
||||
|
@ -403,10 +436,13 @@ export class UsersRepository implements IUsersRepository {
|
|||
)
|
||||
|
||||
if (error) {
|
||||
throw new AuthenticationError(error.message);
|
||||
throw new DatabaseOperationError("Failed to ban user");
|
||||
}
|
||||
|
||||
return data.user;
|
||||
return {
|
||||
...user,
|
||||
id
|
||||
};
|
||||
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
||||
|
@ -427,7 +463,7 @@ export class UsersRepository implements IUsersRepository {
|
|||
ban_duration: "none",
|
||||
})
|
||||
|
||||
const { data, error } = await this.instrumentationService.startSpan({
|
||||
const { data: user, error } = await this.instrumentationService.startSpan({
|
||||
name: "UsersRepository > unbanUser > supabase.auth.admin.updateUserById",
|
||||
op: "db:query",
|
||||
attributes: { "system": "supabase.auth" },
|
||||
|
@ -438,10 +474,13 @@ export class UsersRepository implements IUsersRepository {
|
|||
)
|
||||
|
||||
if (error) {
|
||||
throw new AuthenticationError(error.message);
|
||||
throw new DatabaseOperationError("Failed to unban user");
|
||||
}
|
||||
|
||||
return data.user;
|
||||
return {
|
||||
...user,
|
||||
id
|
||||
};
|
||||
|
||||
} catch (err) {
|
||||
this.crashReporterService.report(err);
|
|
@ -1,201 +1,8 @@
|
|||
// "use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import {
|
||||
defaultSignInPasswordlessValues,
|
||||
SignInFormData,
|
||||
SignInSchema,
|
||||
} from "@/src/entities/models/auth/sign-in.model";
|
||||
import { useState, type FormEvent, type ChangeEvent } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
// import { signIn } from "";
|
||||
import { useAuthActions } from "./auth-controller";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { AuthenticationError } from "@/src/entities/errors/auth";
|
||||
import { ISignInUseCase } from "@/src/application/use-cases/auth/sign-in.use-case";
|
||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
|
||||
type SignInFormErrors = Partial<Record<keyof SignInFormData, string>>;
|
||||
|
||||
// export function useSignInForm() {
|
||||
// const [formData, setFormData] = useState<SignInFormData>(defaultSignInValues);
|
||||
// const [errors, setErrors] = useState<SignInFormErrors>({});
|
||||
// const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
// const [message, setMessage] = useState<string | null>(null);
|
||||
// const router = useRouter();
|
||||
|
||||
// const validateForm = (): boolean => {
|
||||
// try {
|
||||
// SignInSchema.parse(formData);
|
||||
// setErrors({});
|
||||
// return true;
|
||||
// } catch (error) {
|
||||
// if (error instanceof z.ZodError) {
|
||||
// const formattedErrors: SignInFormErrors = {};
|
||||
// error.errors.forEach((err) => {
|
||||
// const path = err.path[0] as keyof SignInFormData;
|
||||
// formattedErrors[path] = err.message;
|
||||
// });
|
||||
// setErrors(formattedErrors);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// };
|
||||
|
||||
// const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
// const { name, value } = e.target;
|
||||
// setFormData((prev) => ({
|
||||
// ...prev,
|
||||
// [name]: value,
|
||||
// }));
|
||||
// };
|
||||
|
||||
// const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
// e.preventDefault();
|
||||
// if (!validateForm()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// setIsSubmitting(true);
|
||||
// setMessage(null);
|
||||
|
||||
// try {
|
||||
// const result = await signIn(formData);
|
||||
|
||||
// if (result.success) {
|
||||
// setMessage(result.message);
|
||||
// toast.success(result.message);
|
||||
|
||||
// // Handle client-side navigation
|
||||
// if (result.redirectTo) {
|
||||
// router.push(result.redirectTo);
|
||||
// }
|
||||
// } else {
|
||||
// setErrors({
|
||||
// email: result.message || "Sign in failed. Please try again.",
|
||||
// });
|
||||
// toast.error(result.message || "Sign in failed. Please try again.");
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error("Sign in failed", error);
|
||||
// setErrors({
|
||||
// email: "An unexpected error occurred. Please try again.",
|
||||
// });
|
||||
// toast.error("An unexpected error occurred. Please try again.");
|
||||
// } finally {
|
||||
// setIsSubmitting(false);
|
||||
// }
|
||||
// };
|
||||
|
||||
// return {
|
||||
// formData,
|
||||
// errors,
|
||||
// isSubmitting,
|
||||
// message,
|
||||
// setFormData,
|
||||
// handleChange,
|
||||
// handleSubmit,
|
||||
// };
|
||||
// }
|
||||
|
||||
// export function useSignInController() {
|
||||
// const [formData, setFormData] = useState<SignInFormData>(defaultSignInValues);
|
||||
// const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
|
||||
// const { signIn } = useAuthActions();
|
||||
|
||||
// const form = useForm<SignInFormData>({
|
||||
// resolver: zodResolver(SignInSchema),
|
||||
// defaultValues: defaultSignInValues,
|
||||
// });
|
||||
|
||||
// // Handle input changes
|
||||
// const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// const { name, value } = e.target;
|
||||
// setFormData(prev => ({
|
||||
// ...prev,
|
||||
// [name]: value
|
||||
// }));
|
||||
|
||||
// // Clear error when user starts typing
|
||||
// if (errors[name]) {
|
||||
// setErrors(prev => ({
|
||||
// ...prev,
|
||||
// [name]: ''
|
||||
// }));
|
||||
// }
|
||||
// };
|
||||
|
||||
// // Direct handleSubmit handler for the form
|
||||
// const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
// e.preventDefault();
|
||||
// setErrors({});
|
||||
|
||||
// try {
|
||||
// // Basic email validation before sending to API
|
||||
// if (!formData.email || !formData.email.includes('@')) {
|
||||
// setErrors({ email: 'Please enter a valid email address' });
|
||||
// return;
|
||||
// }
|
||||
|
||||
// await signIn.mutate(formData);
|
||||
// } catch (error) {
|
||||
// // This catch block will likely not be used since errors are handled in the mutation
|
||||
// console.error("Form submission error:", error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// // Combine form validation errors with API errors
|
||||
// const formErrors = {
|
||||
// ...errors,
|
||||
// // If there's an API error from the mutation, add it to the appropriate field
|
||||
// ...(signIn.error instanceof AuthenticationError ?
|
||||
// { email: signIn.error.message } :
|
||||
// {})
|
||||
// };
|
||||
|
||||
// return {
|
||||
// formData,
|
||||
// handleChange,
|
||||
// handleSubmit,
|
||||
// isPending: signIn.isPending,
|
||||
// error: formErrors
|
||||
// };
|
||||
// }
|
||||
|
||||
// export function useSignInController() {
|
||||
// const { signIn } = useAuthActions();
|
||||
|
||||
// // Gunakan react-hook-form untuk mengelola form state & error handling
|
||||
// const {
|
||||
// register,
|
||||
// handleSubmit,
|
||||
// formState: { errors },
|
||||
// } = useForm<SignInFormData>({
|
||||
// resolver: zodResolver(SignInSchema),
|
||||
// defaultValues: defaultSignInPasswordlessValues,
|
||||
// });
|
||||
|
||||
// // Handler untuk submit form
|
||||
// const onSubmit = handleSubmit(async (data) => {
|
||||
// try {
|
||||
// signIn.mutate(data);
|
||||
// } catch (error) {
|
||||
// console.error("Sign-in submission error:", error);
|
||||
// }
|
||||
// });
|
||||
|
||||
// return {
|
||||
// register,
|
||||
// handleSubmit: onSubmit,
|
||||
// errors,
|
||||
// isPending: signIn.isPending,
|
||||
// };
|
||||
// }
|
||||
|
||||
// Sign In Controller
|
||||
const signInInputSchema = z.object({
|
||||
email: z.string().email("Please enter a valid email address"),
|
||||
|
|
|
@ -3,105 +3,6 @@ import { IVerifyOtpUseCase } from "@/src/application/use-cases/auth/verify-otp.u
|
|||
import { z } from "zod";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
|
||||
// export function useVerifyOtpForm(email: string) {
|
||||
// const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
// const [message, setMessage] = useState<string | null>(null);
|
||||
// const { router } = useNavigations();
|
||||
|
||||
// const form = useForm<VerifyOtpFormData>({
|
||||
// resolver: zodResolver(verifyOtpSchema),
|
||||
// defaultValues: { ...defaultVerifyOtpValues, email: email },
|
||||
// });
|
||||
|
||||
// const onSubmit = async (data: VerifyOtpFormData) => {
|
||||
// setIsSubmitting(true);
|
||||
// setMessage(null);
|
||||
|
||||
// try {
|
||||
// const result = await verifyOtp(data);
|
||||
|
||||
// if (result.success) {
|
||||
// setMessage(result.message);
|
||||
// // Redirect or update UI state as needed
|
||||
// toast.success(result.message);
|
||||
// if (result.redirectTo) {
|
||||
// router.push(result.redirectTo);
|
||||
// }
|
||||
// } else {
|
||||
// toast.error(result.message);
|
||||
// form.setError("token", { type: "manual", message: result.message });
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error("OTP verification failed", error);
|
||||
// toast.error("An unexpected error occurred. Please try again.");
|
||||
// form.setError("token", {
|
||||
// type: "manual",
|
||||
// message: "An unexpected error occurred. Please try again.",
|
||||
// });
|
||||
// } finally {
|
||||
// setIsSubmitting(false);
|
||||
// }
|
||||
// };
|
||||
|
||||
// return {
|
||||
// form,
|
||||
// isSubmitting,
|
||||
// message,
|
||||
// onSubmit,
|
||||
// };
|
||||
// }
|
||||
|
||||
// export const useVerifyOtpController = (email: string) => {
|
||||
// const { verifyOtp } = useAuthActions()
|
||||
|
||||
// const {
|
||||
// control,
|
||||
// register,
|
||||
// handleSubmit,
|
||||
// reset,
|
||||
// formState: { errors, isSubmitSuccessful },
|
||||
// } = useForm<VerifyOtpFormData>({
|
||||
// resolver: zodResolver(verifyOtpSchema),
|
||||
// defaultValues: { ...defaultVerifyOtpValues, email: email },
|
||||
// })
|
||||
|
||||
// // Clear form after successful submission
|
||||
// useEffect(() => {
|
||||
// if (isSubmitSuccessful) {
|
||||
// reset({ ...defaultVerifyOtpValues, email })
|
||||
// }
|
||||
// }, [isSubmitSuccessful, reset, email])
|
||||
|
||||
// const onSubmit = handleSubmit(async (data) => {
|
||||
// try {
|
||||
// await verifyOtp.mutate(data)
|
||||
// } catch (error) {
|
||||
// console.error("OTP verification failed", error)
|
||||
// }
|
||||
// })
|
||||
|
||||
// // Function to handle auto-submission when all digits are entered
|
||||
// const handleOtpChange = (value: string, onChange: (value: string) => void) => {
|
||||
// onChange(value)
|
||||
|
||||
// // Auto-submit when all 6 digits are entered
|
||||
// if (value.length === 6) {
|
||||
// setTimeout(() => {
|
||||
// onSubmit()
|
||||
// }, 300) // Small delay to allow the UI to update
|
||||
// }
|
||||
// }
|
||||
|
||||
// return {
|
||||
// control,
|
||||
// register,
|
||||
// handleSubmit: onSubmit,
|
||||
// handleOtpChange,
|
||||
// errors,
|
||||
// isPending: verifyOtp.isPending,
|
||||
// }
|
||||
// }
|
||||
|
||||
// Verify OTP Controller
|
||||
const verifyOtpInputSchema = z.object({
|
||||
email: z.string().email("Please enter a valid email address"),
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { IBanUserUseCase } from "@/src/application/use-cases/users/ban-user.use-case";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
import { z } from "zod";
|
||||
|
||||
const inputSchema = z.object({
|
||||
id: z.string(),
|
||||
ban_duration: z.string()
|
||||
})
|
||||
|
||||
export type IBanUserController = ReturnType<typeof banUserController>
|
||||
|
||||
export const banUserController = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
banUserUseCase: IBanUserUseCase
|
||||
) =>
|
||||
async (input: Partial<z.infer<typeof inputSchema>>) => {
|
||||
return await instrumentationService.startSpan({ name: "banUser Controller" }, async () => {
|
||||
const { data, error: inputParseError } = inputSchema.safeParse(input);
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError("Invalid data", { cause: inputParseError });
|
||||
}
|
||||
|
||||
return await banUserUseCase(data.id, data.ban_duration);
|
||||
})
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import { IUsersRepository } from "@/src/application/repositories/users.repository.interface"
|
||||
import { IAuthenticationService } from "@/src/application/services/authentication.service.interface"
|
||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface"
|
||||
import { ICreateUserUseCase } from "@/src/application/use-cases/users/create-user.use-case"
|
||||
import { UnauthenticatedError } from "@/src/entities/errors/auth"
|
||||
import { InputParseError } from "@/src/entities/errors/common"
|
||||
import { CreateUserSchema } from "@/src/entities/models/users/users.model"
|
||||
import { z } from "zod"
|
||||
|
||||
const inputSchema = CreateUserSchema
|
||||
|
||||
export type ICreateUserController = ReturnType<typeof createUserController>
|
||||
|
||||
export const createUserController = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
createUserUseCase: ICreateUserUseCase,
|
||||
authenticationService: IAuthenticationService
|
||||
) => async (input: Partial<z.infer<typeof inputSchema>>) => {
|
||||
|
||||
const session = await authenticationService.getSession()
|
||||
|
||||
if (!session) {
|
||||
throw new UnauthenticatedError("Must be logged in to create a todo")
|
||||
}
|
||||
|
||||
const { data, error: inputParseError } = inputSchema.safeParse(input)
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError("Invalid data", { cause: inputParseError })
|
||||
}
|
||||
|
||||
return await createUserUseCase(data);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { IAuthenticationService } from "@/src/application/services/authentication.service.interface"
|
||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface"
|
||||
import { IDeleteUserUseCase } from "@/src/application/use-cases/users/delete-user.use-case"
|
||||
import { UnauthenticatedError } from "@/src/entities/errors/auth"
|
||||
|
||||
export type IDeleteUserController = ReturnType<typeof deleteUserController>
|
||||
|
||||
export const deleteUserController =
|
||||
(
|
||||
instrumentationService: IInstrumentationService,
|
||||
deleteUserUseCase: IDeleteUserUseCase,
|
||||
authenticationService: IAuthenticationService
|
||||
) =>
|
||||
async (id: string) => {
|
||||
return await instrumentationService.startSpan({ name: "deleteUser Controller" }, async () => {
|
||||
|
||||
const session = await authenticationService.getSession()
|
||||
|
||||
if (!session) {
|
||||
throw new UnauthenticatedError("Must be logged in to create a todo")
|
||||
}
|
||||
|
||||
return await deleteUserUseCase(id);
|
||||
})
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { IUsersRepository } from "@/src/application/repositories/users.repository.interface"
|
||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface"
|
||||
import { IGetCurrentUserUseCase } from "@/src/application/use-cases/users/get-current-user.use-case"
|
||||
import { NotFoundError } from "@/src/entities/errors/common"
|
||||
|
||||
export type IGetCurrentUserController = ReturnType<typeof getCurrentUserController>
|
||||
|
||||
export const getCurrentUserController =
|
||||
(
|
||||
instrumentationService: IInstrumentationService,
|
||||
getCurrentUserUseCase: IGetCurrentUserUseCase
|
||||
) =>
|
||||
async () => {
|
||||
return await instrumentationService.startSpan({ name: "getCurrentUser Controller" }, async () => {
|
||||
|
||||
return await getCurrentUserUseCase();
|
||||
})
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { IUsersRepository } from "@/src/application/repositories/users.repository.interface"
|
||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface"
|
||||
|
||||
export type IGetListUserController = ReturnType<typeof getListUsersController>
|
||||
|
||||
export const getListUsersController =
|
||||
(
|
||||
instrumentationService: IInstrumentationService,
|
||||
usersRepository: IUsersRepository
|
||||
) =>
|
||||
async () => {
|
||||
return await instrumentationService.startSpan({ name: "getListUsers Controller" }, async () => {
|
||||
return await usersRepository.listUsers();
|
||||
})
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { IGetUserByEmailUseCase } from "@/src/application/use-cases/users/get-user-by-email.use-case";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
import { z } from "zod";
|
||||
|
||||
const inputSchema = z.object({
|
||||
email: z.string().email()
|
||||
})
|
||||
|
||||
export type IGetUserByEmailController = ReturnType<typeof getUserByEmailController>
|
||||
|
||||
export const getUserByEmailController =
|
||||
(
|
||||
instrumentationService: IInstrumentationService,
|
||||
getUserByEmailUseCase: IGetUserByEmailUseCase
|
||||
) =>
|
||||
async (input: Partial<z.infer<typeof inputSchema>>) => {
|
||||
return await instrumentationService.startSpan({ name: "getUserByEmail Controller" }, async () => {
|
||||
const { data, error: inputParseError } = inputSchema.safeParse(input);
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError("Invalid data", { cause: inputParseError });
|
||||
}
|
||||
|
||||
return await getUserByEmailUseCase(data.email);
|
||||
})
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface"
|
||||
import { IGetUserByIdUseCase } from "@/src/application/use-cases/users/get-user-by-id.use-case"
|
||||
import { InputParseError } from "@/src/entities/errors/common"
|
||||
import { z } from "zod"
|
||||
|
||||
const inputSchema = z.object({
|
||||
id: z.string()
|
||||
})
|
||||
|
||||
export type IGetUserByIdController = ReturnType<typeof getUserByIdController>
|
||||
|
||||
export const getUserByIdController = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
getUserByIdUseCase: IGetUserByIdUseCase
|
||||
) =>
|
||||
async (input: Partial<z.infer<typeof inputSchema>>) => {
|
||||
return await instrumentationService.startSpan({ name: "getUserById Controller" }, async () => {
|
||||
const { data, error: inputParseError } = inputSchema.safeParse(input);
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError("Invalid data", { cause: inputParseError });
|
||||
}
|
||||
|
||||
return await getUserByIdUseCase(data.id);
|
||||
})
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { IGetUserByUsernameUseCase } from "@/src/application/use-cases/users/get-user-by-username.use-case";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
import { z } from "zod";
|
||||
|
||||
const inputSchema = z.object({
|
||||
username: z.string()
|
||||
})
|
||||
|
||||
export type IGetUserByUsernameController = ReturnType<typeof getUserByUsernameController>
|
||||
|
||||
export const getUserByUsernameController =
|
||||
(
|
||||
instrumentationService: IInstrumentationService,
|
||||
getUserByUsernameUseCase: IGetUserByUsernameUseCase
|
||||
) =>
|
||||
async (input: Partial<z.infer<typeof inputSchema>>) => {
|
||||
return await instrumentationService.startSpan({ name: "getUserByUsername Controller" }, async () => {
|
||||
const { data, error: inputParseError } = inputSchema.safeParse(input);
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError("Invalid data", { cause: inputParseError });
|
||||
}
|
||||
|
||||
return await getUserByUsernameUseCase(data.username);
|
||||
})
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { IInviteUserUseCase } from "@/src/application/use-cases/users/invite-user.use-case";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
import { z } from "zod";
|
||||
|
||||
const inputSchema = z.object({
|
||||
email: z.string().email(),
|
||||
})
|
||||
|
||||
export type IInviteUserController = ReturnType<typeof inviteUserController>
|
||||
|
||||
export const inviteUserController =
|
||||
(
|
||||
instrumentationService: IInstrumentationService,
|
||||
inviteUserUseCase: IInviteUserUseCase
|
||||
) =>
|
||||
async (input: Partial<z.infer<typeof inputSchema>>) => {
|
||||
return await instrumentationService.startSpan({ name: "inviteUser Controller" }, async () => {
|
||||
const { data, error: inputParseError } = inputSchema.safeParse(input);
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError("Invalid data", { cause: inputParseError });
|
||||
}
|
||||
|
||||
return await inviteUserUseCase(data.email);
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { IUnbanUserUseCase } from "@/src/application/use-cases/users/unban-user.use-case";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
import { z } from "zod";
|
||||
|
||||
const inputSchema = z.object({
|
||||
id: z.string()
|
||||
})
|
||||
|
||||
export type IUnbanUserController = ReturnType<typeof unbanUserController>
|
||||
|
||||
export const unbanUserController = (
|
||||
instrumentationService: IInstrumentationService,
|
||||
unbanUserUseCase: IUnbanUserUseCase
|
||||
) =>
|
||||
async (input: Partial<z.infer<typeof inputSchema>>) => {
|
||||
return await instrumentationService.startSpan({ name: "unbanUser Controller" }, async () => {
|
||||
const { data, error: inputParseError } = inputSchema.safeParse(input);
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError("Invalid data", { cause: inputParseError });
|
||||
}
|
||||
|
||||
return await unbanUserUseCase(data.id);
|
||||
})
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { IAuthenticationService } from "@/src/application/services/authentication.service.interface";
|
||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||
import { IUpdateUserUseCase } from "@/src/application/use-cases/users/update-user.use-case";
|
||||
import { UnauthenticatedError } from "@/src/entities/errors/auth";
|
||||
import { InputParseError } from "@/src/entities/errors/common";
|
||||
import { UpdateUser, UpdateUserSchema } from "@/src/entities/models/users/users.model";
|
||||
import { z } from "zod";
|
||||
|
||||
const inputSchema = UpdateUserSchema
|
||||
|
||||
export type IUpdateUserController = ReturnType<typeof updateUserController>
|
||||
|
||||
export const updateUserController =
|
||||
(
|
||||
instrumentationService: IInstrumentationService,
|
||||
updateUserUseCase: IUpdateUserUseCase,
|
||||
authenticationService: IAuthenticationService
|
||||
) =>
|
||||
async (id: string, input: Partial<z.infer<typeof inputSchema>>,) => {
|
||||
return await instrumentationService.startSpan({ name: "updateUser Controller" }, async () => {
|
||||
|
||||
const session = await authenticationService.getSession()
|
||||
|
||||
if (!session) {
|
||||
throw new UnauthenticatedError("Must be logged in to create a todo")
|
||||
}
|
||||
|
||||
const { data, error: inputParseError } = inputSchema.safeParse(input)
|
||||
|
||||
if (inputParseError) {
|
||||
throw new InputParseError("Invalid data", { cause: inputParseError })
|
||||
}
|
||||
|
||||
return await updateUserUseCase(id, data);
|
||||
})
|
||||
}
|
|
@ -52,6 +52,16 @@ const config = {
|
|||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
sidebar: {
|
||||
DEFAULT: "hsl(var(--sidebar-background))",
|
||||
foreground: "hsl(var(--sidebar-foreground))",
|
||||
primary: "hsl(var(--sidebar-primary))",
|
||||
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
|
||||
accent: "hsl(var(--sidebar-accent))",
|
||||
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
|
||||
border: "hsl(var(--sidebar-border))",
|
||||
ring: "hsl(var(--sidebar-ring))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
|
|
Loading…
Reference in New Issue