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
|
asChild
|
||||||
className={
|
className={
|
||||||
isActive
|
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>
|
<span>{item.title}</span>
|
||||||
</a>
|
</a>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
|
@ -77,13 +77,13 @@ function SubItemComponent({ item }: { item: SubItem }) {
|
||||||
asChild
|
asChild
|
||||||
className={
|
className={
|
||||||
isActive
|
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 && (
|
||||||
<item.icon className={isActive ? "text-primary" : ""} />
|
<item.icon />
|
||||||
)}
|
)}
|
||||||
<span>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -99,14 +99,14 @@ function SubItemComponent({ item }: { item: SubItem }) {
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
className={
|
className={
|
||||||
isActive
|
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 && (
|
||||||
<item.icon className={isActive ? "text-primary" : ""} />
|
<item.icon />
|
||||||
)}
|
)}
|
||||||
<span className={isActive ? "text-primary" : ""}>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
<ChevronRight
|
<ChevronRight
|
||||||
className={`ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 ${isActive ? "text-primary" : ""}`}
|
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
|
asChild
|
||||||
className={
|
className={
|
||||||
isActive
|
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 && (
|
||||||
<item.icon className={isActive ? "text-primary" : ""} />
|
<item.icon />
|
||||||
)}
|
)}
|
||||||
<span>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -166,14 +166,14 @@ function RecursiveNavItem({ item, index }: { item: NavItem; index: number }) {
|
||||||
tooltip={item.title}
|
tooltip={item.title}
|
||||||
className={
|
className={
|
||||||
isActive
|
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 && (
|
||||||
<item.icon className={isActive ? "text-primary" : ""} />
|
<item.icon />
|
||||||
)}
|
)}
|
||||||
<span className={isActive ? "text-primary" : ""}>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
{hasSubItems && (
|
{hasSubItems && (
|
||||||
<ChevronRight
|
<ChevronRight
|
||||||
className={`ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 ${isActive ? "text-primary" : ""}`}
|
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;
|
const isActive = router.pathname === item.url;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarMenuItem className={isActive ? "active text-primary" : ""}>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton tooltip={item.title} asChild>
|
<SidebarMenuButton className={isActive ? "bg-primary/10 text-primary" : ""} tooltip={item.title} asChild>
|
||||||
<a href={item.url}>
|
<a href={item.url}>
|
||||||
<item.icon className="h-4 w-4" />
|
<item.icon className="h-4 w-4" />
|
||||||
<span>{item.title}</span>
|
<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);
|
// setLoading(false);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
const { isPending, handleSubmit, error, errors, clearError } = useSignInHandler();
|
const { isPending, handleSignIn, error, errors, clearError } = useSignInHandler();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -76,7 +76,7 @@ export function SignInForm({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4" {...props} noValidate>
|
<form onSubmit={handleSignIn} className="space-y-4" {...props} noValidate>
|
||||||
<FormField
|
<FormField
|
||||||
label="Email"
|
label="Email"
|
||||||
input={
|
input={
|
||||||
|
|
|
@ -28,7 +28,7 @@ export function VerifyOtpForm({ className, ...props }: VerifyOtpFormProps) {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleVerifyOtp,
|
||||||
handleOtpChange,
|
handleOtpChange,
|
||||||
errors,
|
errors,
|
||||||
isPending
|
isPending
|
||||||
|
@ -44,7 +44,7 @@ export function VerifyOtpForm({ className, ...props }: VerifyOtpFormProps) {
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleVerifyOtp} className="space-y-4">
|
||||||
<input type="hidden" {...register("email")} />
|
<input type="hidden" {...register("email")} />
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<Controller
|
<Controller
|
||||||
|
|
|
@ -25,6 +25,7 @@ export async function signIn(formData: FormData) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return { success: true }
|
return { success: true }
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (
|
if (
|
||||||
err instanceof InputParseError ||
|
err instanceof InputParseError ||
|
||||||
|
|
|
@ -54,7 +54,7 @@ export function useSignInHandler() {
|
||||||
return {
|
return {
|
||||||
// formData,
|
// formData,
|
||||||
// handleChange,
|
// handleChange,
|
||||||
handleSubmit,
|
handleSignIn: handleSubmit,
|
||||||
error,
|
error,
|
||||||
isPending: signIn.isPending,
|
isPending: signIn.isPending,
|
||||||
errors: !!error || signIn.error,
|
errors: !!error || signIn.error,
|
||||||
|
@ -123,7 +123,7 @@ export function useVerifyOtpHandler(email: string) {
|
||||||
return {
|
return {
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleVerifyOtp: handleSubmit,
|
||||||
handleOtpChange,
|
handleOtpChange,
|
||||||
errors: {
|
errors: {
|
||||||
...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';
|
import { signIn, signOut, verifyOtp } from './action';
|
||||||
|
|
||||||
export function useAuthActions() {
|
export function useAuthActions() {
|
||||||
// Sign In Mutation
|
// Sign In Mutation
|
||||||
const signInMutation = useMutation({
|
const signInMutation = useMutation({
|
||||||
|
mutationKey: ["signIn"],
|
||||||
mutationFn: async (formData: FormData) => {
|
mutationFn: async (formData: FormData) => {
|
||||||
const email = formData.get("email")?.toString()
|
|
||||||
const response = await signIn(formData);
|
const response = await signIn(formData);
|
||||||
|
|
||||||
// If the server action returns an error, treat it as an error for React Query
|
// If the server action returns an error, treat it as an error for React Query
|
||||||
if (response?.error) {
|
if (response?.error) {
|
||||||
throw new Error(response.error);
|
throw new Error(response.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { email };
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const verifyOtpMutation = useMutation({
|
const verifyOtpMutation = useMutation({
|
||||||
|
mutationKey: ["verifyOtp"],
|
||||||
mutationFn: async (formData: FormData) => {
|
mutationFn: async (formData: FormData) => {
|
||||||
const email = formData.get("email")?.toString()
|
|
||||||
const token = formData.get("token")?.toString()
|
|
||||||
const response = await verifyOtp(formData);
|
const response = await verifyOtp(formData);
|
||||||
|
|
||||||
// If the server action returns an error, treat it as an error for React Query
|
// If the server action returns an error, treat it as an error for React Query
|
||||||
if (response?.error) {
|
if (response?.error) {
|
||||||
throw new Error(response.error);
|
throw new Error(response.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { email, token };
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const signOutMutation = useMutation({
|
const signOutMutation = useMutation({
|
||||||
|
mutationKey: ["signOut"],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const response = await signOut();
|
const response = await signOut();
|
||||||
|
|
||||||
|
@ -40,8 +36,6 @@ export function useAuthActions() {
|
||||||
if (response?.error) {
|
if (response?.error) {
|
||||||
throw new Error(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 { 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() {
|
export function createUsersModule() {
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
import { createAdminClient } from "@/app/_utils/supabase/admin";
|
import { createAdminClient } from "@/app/_utils/supabase/admin";
|
||||||
import { createClient } from "@/app/_utils/supabase/client";
|
import { createClient } from "@/app/_utils/supabase/client";
|
||||||
import { CreateUser, InviteUser, UpdateUser, User, UserResponse } from "@/src/entities/models/users/users.model";
|
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";
|
import { ITransaction } from "@/src/entities/models/transaction.interface";
|
||||||
|
|
||||||
export interface IUsersRepository {
|
export interface IUsersRepository {
|
||||||
listUsers(): Promise<User[]>;
|
listUsers(): Promise<User[]>;
|
||||||
getCurrentUser(): Promise<UserResponse>;
|
getCurrentUser(): Promise<User>;
|
||||||
getUserById(id: string): Promise<User | undefined>;
|
getUserById(id: string): Promise<User | undefined>;
|
||||||
getUserByUsername(username: string): Promise<User | undefined>;
|
getUserByUsername(username: string): Promise<User | undefined>;
|
||||||
getUserByEmail(email: string): Promise<User | undefined>;
|
getUserByEmail(email: string): Promise<User | undefined>;
|
||||||
createUser(input: CreateUser, tx?: ITransaction): Promise<User | null>;
|
createUser(input: CreateUser, tx?: ITransaction): Promise<User>;
|
||||||
inviteUser(email: string, tx?: ITransaction): Promise<User | null>;
|
inviteUser(email: string, tx?: ITransaction): Promise<User>;
|
||||||
updateUser(id: string, input: Partial<UpdateUser>, tx?: ITransaction): Promise<UserResponse>;
|
updateUser(id: string, input: Partial<UpdateUser>, tx?: ITransaction): Promise<User>;
|
||||||
deleteUser(id: string, tx?: ITransaction): Promise<void>;
|
deleteUser(id: string, tx?: ITransaction): Promise<User>;
|
||||||
banUser(id: string, ban_duration: string, tx?: ITransaction): Promise<User>;
|
banUser(id: string, ban_duration: string, tx?: ITransaction): Promise<User>;
|
||||||
unbanUser(id: 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)
|
const bannedUser = await usersRepository.banUser(id, ban_duration)
|
||||||
|
|
||||||
return {
|
return bannedUser
|
||||||
...bannedUser
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -14,6 +14,7 @@ export const createUserUseCase = (
|
||||||
) => async (input: CreateUser): Promise<User> => {
|
) => async (input: CreateUser): Promise<User> => {
|
||||||
return await instrumentationService.startSpan({ name: "createUser Use Case", op: "function" },
|
return await instrumentationService.startSpan({ name: "createUser Use Case", op: "function" },
|
||||||
async () => {
|
async () => {
|
||||||
|
|
||||||
const existingUser = await usersRepository.getUserByEmail(input.email)
|
const existingUser = await usersRepository.getUserByEmail(input.email)
|
||||||
|
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
|
@ -26,13 +27,7 @@ export const createUserUseCase = (
|
||||||
email_confirm: true
|
email_confirm: true
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!newUser) {
|
return newUser
|
||||||
throw new InputParseError("User not created")
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...newUser
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,25 @@
|
||||||
|
import { NotFoundError } from "@/src/entities/errors/common"
|
||||||
import { IUsersRepository } from "../../repositories/users.repository.interface"
|
import { IUsersRepository } from "../../repositories/users.repository.interface"
|
||||||
import { IInstrumentationService } from "../../services/instrumentation.service.interface"
|
import { IInstrumentationService } from "../../services/instrumentation.service.interface"
|
||||||
|
import { User } from "@/src/entities/models/users/users.model"
|
||||||
|
|
||||||
export type IDeleteUserUseCase = ReturnType<typeof deleteUserUseCase>
|
export type IDeleteUserUseCase = ReturnType<typeof deleteUserUseCase>
|
||||||
|
|
||||||
const deleteUserUseCase = (
|
const deleteUserUseCase = (
|
||||||
instrumentationService: IInstrumentationService,
|
instrumentationService: IInstrumentationService,
|
||||||
usersRepository: IUsersRepository
|
usersRepository: IUsersRepository
|
||||||
) => async (id: string): Promise<void> => {
|
) => async (id: string): Promise<User> => {
|
||||||
return await instrumentationService.startSpan({ name: "deleteUser Use Case", op: "function" },
|
return await instrumentationService.startSpan({ name: "deleteUser Use Case", op: "function" },
|
||||||
async () => {
|
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 { NotFoundError } from "@/src/entities/errors/common"
|
||||||
import { IUsersRepository } from "../../repositories/users.repository.interface"
|
import { IUsersRepository } from "../../repositories/users.repository.interface"
|
||||||
import { IInstrumentationService } from "../../services/instrumentation.service.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>
|
export type IGetCurrentUserUseCase = ReturnType<typeof getCurrentUserUseCase>
|
||||||
|
@ -9,7 +10,7 @@ export type IGetCurrentUserUseCase = ReturnType<typeof getCurrentUserUseCase>
|
||||||
export const getCurrentUserUseCase = (
|
export const getCurrentUserUseCase = (
|
||||||
instrumentationService: IInstrumentationService,
|
instrumentationService: IInstrumentationService,
|
||||||
usersRepository: IUsersRepository
|
usersRepository: IUsersRepository
|
||||||
) => async (): Promise<UserResponse> => {
|
) => async (): Promise<User> => {
|
||||||
return await instrumentationService.startSpan({ name: "getCurrentUser Use Case", op: "function" },
|
return await instrumentationService.startSpan({ name: "getCurrentUser Use Case", op: "function" },
|
||||||
async () => {
|
async () => {
|
||||||
|
|
||||||
|
@ -19,9 +20,7 @@ export const getCurrentUserUseCase = (
|
||||||
throw new NotFoundError("User not found")
|
throw new NotFoundError("User not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return existingUser
|
||||||
...existingUser
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,9 @@ export const getListUsersUseCase = (
|
||||||
) => async (): Promise<User[]> => {
|
) => async (): Promise<User[]> => {
|
||||||
return await instrumentationService.startSpan({ name: "getListUsers Use Case", op: "function" },
|
return await instrumentationService.startSpan({ name: "getListUsers Use Case", op: "function" },
|
||||||
async () => {
|
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" },
|
return await instrumentationService.startSpan({ name: "getUserByEmail Use Case", op: "function" },
|
||||||
async () => {
|
async () => {
|
||||||
|
|
||||||
const existingUser = await usersRepository.getUserByEmail(email)
|
const user = await usersRepository.getUserByEmail(email)
|
||||||
|
|
||||||
if (!existingUser) {
|
if (!user) {
|
||||||
throw new NotFoundError("User not found")
|
throw new NotFoundError("User not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return user
|
||||||
...existingUser
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,15 +14,13 @@ export const getUserByIdUseCase = (
|
||||||
return await instrumentationService.startSpan({ name: "getUserById Use Case", op: "function" },
|
return await instrumentationService.startSpan({ name: "getUserById Use Case", op: "function" },
|
||||||
async () => {
|
async () => {
|
||||||
|
|
||||||
const existingUser = await usersRepository.getUserById(id)
|
const user = await usersRepository.getUserById(id)
|
||||||
|
|
||||||
if (!existingUser) {
|
if (!user) {
|
||||||
throw new NotFoundError("User not found")
|
throw new NotFoundError("User not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return user
|
||||||
...existingUser
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -12,15 +12,13 @@ const getUserByUsernameUseCase = (
|
||||||
return await instrumentationService.startSpan({ name: "getUserByUsername Use Case", op: "function" },
|
return await instrumentationService.startSpan({ name: "getUserByUsername Use Case", op: "function" },
|
||||||
async () => {
|
async () => {
|
||||||
|
|
||||||
const existingUser = await usersRepository.getUserByUsername(username)
|
const user = await usersRepository.getUserByUsername(username)
|
||||||
|
|
||||||
if (!existingUser) {
|
if (!user) {
|
||||||
throw new NotFoundError("User not found")
|
throw new NotFoundError("User not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return user
|
||||||
...existingUser
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -11,24 +11,22 @@ export const inviteUserUseCase = (
|
||||||
instrumentationService: IInstrumentationService,
|
instrumentationService: IInstrumentationService,
|
||||||
usersRepository: IUsersRepository,
|
usersRepository: IUsersRepository,
|
||||||
authenticationService: IAuthenticationService,
|
authenticationService: IAuthenticationService,
|
||||||
) => async (input: { email: string }): Promise<User> => {
|
) => async (email: string): Promise<User> => {
|
||||||
return await instrumentationService.startSpan({ name: "inviteUser Use Case", op: "function" },
|
return await instrumentationService.startSpan({ name: "inviteUser Use Case", op: "function" },
|
||||||
async () => {
|
async () => {
|
||||||
const existingUser = await usersRepository.getUserByEmail(input.email)
|
const existingUser = await usersRepository.getUserByEmail(email)
|
||||||
|
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
throw new AuthenticationError("User already exists")
|
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")
|
throw new AuthenticationError("User not invited")
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return invitedUser
|
||||||
...newUser
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = (
|
const updateUserUseCase = (
|
||||||
instrumentationService: IInstrumentationService,
|
instrumentationService: IInstrumentationService,
|
||||||
usersRepository: IUsersRepository
|
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" },
|
return await instrumentationService.startSpan({ name: "updateUser Use Case", op: "function" },
|
||||||
async () => {
|
async () => {
|
||||||
|
|
||||||
|
@ -20,9 +20,7 @@ const updateUserUseCase = (
|
||||||
|
|
||||||
const updatedUser = await usersRepository.updateUser(id, input)
|
const updatedUser = await usersRepository.updateUser(id, input)
|
||||||
|
|
||||||
return {
|
return updatedUser
|
||||||
...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 { CreateUser, UpdateUser, User, UserResponse } from "@/src/entities/models/users/users.model";
|
||||||
import { ITransaction } from "@/src/entities/models/transaction.interface";
|
import { ITransaction } from "@/src/entities/models/transaction.interface";
|
||||||
import db from "@/prisma/db";
|
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";
|
import { AuthenticationError } from "@/src/entities/errors/auth";
|
||||||
|
|
||||||
export class UsersRepository implements IUsersRepository {
|
export class UsersRepository implements IUsersRepository {
|
||||||
|
@ -39,6 +39,10 @@ export class UsersRepository implements IUsersRepository {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!users) {
|
||||||
|
throw new NotFoundError("Users not found");
|
||||||
|
}
|
||||||
|
|
||||||
return users;
|
return users;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.crashReporterService.report(err);
|
this.crashReporterService.report(err);
|
||||||
|
@ -71,8 +75,14 @@ export class UsersRepository implements IUsersRepository {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (user)
|
if (!user) {
|
||||||
return user;
|
throw new NotFoundError("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...user,
|
||||||
|
id,
|
||||||
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.crashReporterService.report(err);
|
this.crashReporterService.report(err);
|
||||||
throw 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) {
|
} catch (err) {
|
||||||
this.crashReporterService.report(err);
|
this.crashReporterService.report(err);
|
||||||
throw err;
|
throw err;
|
||||||
|
@ -141,34 +155,9 @@ export class UsersRepository implements IUsersRepository {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (user)
|
if (!user) {
|
||||||
return user;
|
throw new NotFoundError("User not found");
|
||||||
|
}
|
||||||
} catch (err) {
|
|
||||||
this.crashReporterService.report(err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCurrentUser(): Promise<UserResponse> {
|
|
||||||
return await this.instrumentationService.startSpan({
|
|
||||||
name: "UsersRepository > getCurrentUser",
|
|
||||||
}, async () => {
|
|
||||||
try {
|
|
||||||
const supabase = await this.supabaseServer;
|
|
||||||
|
|
||||||
const query = supabase.auth.getUser();
|
|
||||||
|
|
||||||
const user = await this.instrumentationService.startSpan({
|
|
||||||
name: "UsersRepository > getCurrentUser > supabase.auth.getUser",
|
|
||||||
op: "db:query",
|
|
||||||
attributes: { "system": "supabase.auth" },
|
|
||||||
},
|
|
||||||
async () => {
|
|
||||||
return await query;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -178,18 +167,52 @@ export class UsersRepository implements IUsersRepository {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async createUser(input: CreateUser, tx?: ITransaction): Promise<User | null> {
|
async getCurrentUser(): Promise<User> {
|
||||||
|
return await this.instrumentationService.startSpan({
|
||||||
|
name: "UsersRepository > getCurrentUser",
|
||||||
|
}, async () => {
|
||||||
|
try {
|
||||||
|
const supabase = await this.supabaseServer;
|
||||||
|
|
||||||
|
const query = supabase.auth.getUser();
|
||||||
|
|
||||||
|
const { data, error } = await this.instrumentationService.startSpan({
|
||||||
|
name: "UsersRepository > getCurrentUser > supabase.auth.getUser",
|
||||||
|
op: "db:query",
|
||||||
|
attributes: { "system": "supabase.auth" },
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
return await query;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async createUser(input: CreateUser, tx?: ITransaction): Promise<User> {
|
||||||
return await this.instrumentationService.startSpan({
|
return await this.instrumentationService.startSpan({
|
||||||
name: "UsersRepository > createUser",
|
name: "UsersRepository > createUser",
|
||||||
}, async () => {
|
}, async () => {
|
||||||
try {
|
try {
|
||||||
const supabase = this.supabaseAdmin;
|
const supabase = this.supabaseAdmin;
|
||||||
|
|
||||||
const query = supabase.auth.admin.createUser({
|
const query = supabase.auth.admin.createUser(input)
|
||||||
email: input.email,
|
|
||||||
password: input.password,
|
|
||||||
email_confirm: input.email_confirm,
|
|
||||||
})
|
|
||||||
|
|
||||||
const { data: { user } } = await this.instrumentationService.startSpan({
|
const { data: { user } } = await this.instrumentationService.startSpan({
|
||||||
name: "UsersRepository > createUser > supabase.auth.admin.createUser",
|
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;
|
return user;
|
||||||
|
|
||||||
} catch (err) {
|
} 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({
|
return await this.instrumentationService.startSpan({
|
||||||
name: "UsersRepository > inviteUser",
|
name: "UsersRepository > inviteUser",
|
||||||
}, async () => {
|
}, async () => {
|
||||||
|
@ -229,6 +256,10 @@ export class UsersRepository implements IUsersRepository {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new DatabaseOperationError("Failed to invite user");
|
||||||
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.crashReporterService.report(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({
|
return await this.instrumentationService.startSpan({
|
||||||
name: "UsersRepository > updateUser",
|
name: "UsersRepository > updateUser",
|
||||||
}, async () => {
|
}, async () => {
|
||||||
|
@ -267,7 +298,7 @@ export class UsersRepository implements IUsersRepository {
|
||||||
)
|
)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw new AuthenticationError(error.message);
|
throw new DatabaseOperationError("Failed to update user");
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryGetUser = db.users.findUnique({
|
const queryGetUser = db.users.findUnique({
|
||||||
|
@ -332,18 +363,13 @@ export class UsersRepository implements IUsersRepository {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!updatedUser) {
|
||||||
|
throw new DatabaseOperationError("Failed to update user");
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: {
|
...updatedUser,
|
||||||
user: {
|
id,
|
||||||
...data.user,
|
|
||||||
role: updatedUser.role,
|
|
||||||
profile: {
|
|
||||||
user_id: id,
|
|
||||||
...updatedUser.profile,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
error: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} catch (err) {
|
} 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({
|
return await this.instrumentationService.startSpan({
|
||||||
name: "UsersRepository > deleteUser",
|
name: "UsersRepository > deleteUser",
|
||||||
}, async () => {
|
}, async () => {
|
||||||
|
@ -362,7 +388,7 @@ export class UsersRepository implements IUsersRepository {
|
||||||
|
|
||||||
const query = supabase.auth.admin.deleteUser(id);
|
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",
|
name: "UsersRepository > deleteUser > supabase.auth.admin.deleteUser",
|
||||||
op: "db:query",
|
op: "db:query",
|
||||||
attributes: { "system": "supabase.auth" },
|
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) {
|
} catch (err) {
|
||||||
this.crashReporterService.report(err);
|
this.crashReporterService.report(err);
|
||||||
|
@ -392,7 +425,7 @@ export class UsersRepository implements IUsersRepository {
|
||||||
ban_duration: ban_duration ?? "100h",
|
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",
|
name: "UsersRepository > banUser > supabase.auth.admin.updateUserById",
|
||||||
op: "db:query",
|
op: "db:query",
|
||||||
attributes: { "system": "supabase.auth" },
|
attributes: { "system": "supabase.auth" },
|
||||||
|
@ -403,10 +436,13 @@ export class UsersRepository implements IUsersRepository {
|
||||||
)
|
)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw new AuthenticationError(error.message);
|
throw new DatabaseOperationError("Failed to ban user");
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.user;
|
return {
|
||||||
|
...user,
|
||||||
|
id
|
||||||
|
};
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.crashReporterService.report(err);
|
this.crashReporterService.report(err);
|
||||||
|
@ -427,7 +463,7 @@ export class UsersRepository implements IUsersRepository {
|
||||||
ban_duration: "none",
|
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",
|
name: "UsersRepository > unbanUser > supabase.auth.admin.updateUserById",
|
||||||
op: "db:query",
|
op: "db:query",
|
||||||
attributes: { "system": "supabase.auth" },
|
attributes: { "system": "supabase.auth" },
|
||||||
|
@ -438,10 +474,13 @@ export class UsersRepository implements IUsersRepository {
|
||||||
)
|
)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw new AuthenticationError(error.message);
|
throw new DatabaseOperationError("Failed to unban user");
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.user;
|
return {
|
||||||
|
...user,
|
||||||
|
id
|
||||||
|
};
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.crashReporterService.report(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 { 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 { ISignInUseCase } from "@/src/application/use-cases/auth/sign-in.use-case";
|
||||||
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
import { IInstrumentationService } from "@/src/application/services/instrumentation.service.interface";
|
||||||
import { InputParseError } from "@/src/entities/errors/common";
|
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
|
// Sign In Controller
|
||||||
const signInInputSchema = z.object({
|
const signInInputSchema = z.object({
|
||||||
email: z.string().email("Please enter a valid email address"),
|
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 { z } from "zod";
|
||||||
import { InputParseError } from "@/src/entities/errors/common";
|
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
|
// Verify OTP Controller
|
||||||
const verifyOtpInputSchema = z.object({
|
const verifyOtpInputSchema = z.object({
|
||||||
email: z.string().email("Please enter a valid email address"),
|
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))",
|
DEFAULT: "hsl(var(--card))",
|
||||||
foreground: "hsl(var(--card-foreground))",
|
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: {
|
borderRadius: {
|
||||||
lg: "var(--radius)",
|
lg: "var(--radius)",
|
||||||
|
|
Loading…
Reference in New Issue