From 398ca613ba332fd2fc1c8a0d9fd732035034f6bf Mon Sep 17 00:00:00 2001 From: vergiLgood1 Date: Sun, 23 Mar 2025 06:28:39 +0700 Subject: [PATCH] fix bug invite user --- .../_components/navigations/nav-main.tsx | 10 +++++----- .../_components/user-management.tsx | 10 +++++++--- .../dashboard/user-management/action.ts | 9 ++++----- .../dashboard/user-management/handler.tsx | 12 +++++++++++ .../dashboard/user-management/queries.ts | 4 ++-- sigap-website/app/_styles/globals.css | 20 +++++++++---------- .../use-cases/auth/verify-otp.use-case.ts | 9 ++++++--- .../use-cases/users/invite-user.use-case.ts | 9 +++++---- .../auth/verify-otp.controller.tsx | 3 +++ 9 files changed, 54 insertions(+), 32 deletions(-) diff --git a/sigap-website/app/(pages)/(admin)/_components/navigations/nav-main.tsx b/sigap-website/app/(pages)/(admin)/_components/navigations/nav-main.tsx index 48ae392..e4f4c8b 100644 --- a/sigap-website/app/(pages)/(admin)/_components/navigations/nav-main.tsx +++ b/sigap-website/app/(pages)/(admin)/_components/navigations/nav-main.tsx @@ -52,7 +52,7 @@ function SubSubItemComponent({ item }: { item: SubSubItem }) { asChild className={ isActive - ? "bg-primary/10 active text-primary" + ? "bg-primary/40 active text-primary" : "" } > @@ -77,7 +77,7 @@ function SubItemComponent({ item }: { item: SubItem }) { asChild className={ isActive - ? "bg-primary/10 active text-primary" + ? "bg-primary/40 active text-primary" : "" } > @@ -99,7 +99,7 @@ function SubItemComponent({ item }: { item: SubItem }) { @@ -138,7 +138,7 @@ function RecursiveNavItem({ item, index }: { item: NavItem; index: number }) { asChild className={ isActive - ? "bg-primary/10 active text-primary" + ? "bg-primary/40 active text-primary" : "" } > @@ -166,7 +166,7 @@ function RecursiveNavItem({ item, index }: { item: NavItem; index: number }) { tooltip={item.title} className={ isActive - ? "bg-primary/10 active text-primary" + ? "bg-primary/40 active text-primary" : "" } > diff --git a/sigap-website/app/(pages)/(admin)/dashboard/user-management/_components/user-management.tsx b/sigap-website/app/(pages)/(admin)/dashboard/user-management/_components/user-management.tsx index 3f86968..86df656 100644 --- a/sigap-website/app/(pages)/(admin)/dashboard/user-management/_components/user-management.tsx +++ b/sigap-website/app/(pages)/(admin)/dashboard/user-management/_components/user-management.tsx @@ -143,17 +143,21 @@ export default function UserManagement() { user={detailUser} open={isSheetOpen} onOpenChange={setIsSheetOpen} - onUserUpdate={() => refetch()} + onUserUpdate={() => { }} /> )} - refetch()} /> + { }} + /> refetch()} /> {updateUser && ( refetch()} + onUserUpdated={() => { }} /> )} diff --git a/sigap-website/app/(pages)/(admin)/dashboard/user-management/action.ts b/sigap-website/app/(pages)/(admin)/dashboard/user-management/action.ts index 95172f6..0c9bdeb 100644 --- a/sigap-website/app/(pages)/(admin)/dashboard/user-management/action.ts +++ b/sigap-website/app/(pages)/(admin)/dashboard/user-management/action.ts @@ -14,6 +14,7 @@ import { IBanDuration, IBanUserSchema, ICredentialsBanUserSchema } from '@/src/e import { ICreateUserSchema } from '@/src/entities/models/users/create-user.model'; import { IUpdateUserSchema } from '@/src/entities/models/users/update-user.model'; import { ICredentialsInviteUserSchema } from '@/src/entities/models/users/invite-user.model'; +import { ICredentialGetUserByEmailSchema } from '@/src/entities/models/users/read-user.model'; export async function banUser(id: string, ban_duration: IBanDuration) { const instrumentationService = getInjection('IInstrumentationService'); @@ -116,9 +117,7 @@ export async function getCurrentUser() { { recordResponse: true }, async () => { try { - const getCurrentUserController = getInjection( - 'IGetCurrentUserController' - ); + const getCurrentUserController = getInjection('IGetCurrentUserController'); return await getCurrentUserController(); } catch (err) { @@ -182,7 +181,7 @@ export async function getUserById(id: string) { ); } -export async function getUserByEmail(email: string) { +export async function getUserByEmail(credential: ICredentialGetUserByEmailSchema) { const instrumentationService = getInjection('IInstrumentationService'); return await instrumentationService.instrumentServerAction( 'getUserByEmail', @@ -192,7 +191,7 @@ export async function getUserByEmail(email: string) { const getUserByEmailController = getInjection( 'IGetUserByEmailController' ); - return await getUserByEmailController({ email }); + return await getUserByEmailController({ email: credential.email }); } catch (err) { diff --git a/sigap-website/app/(pages)/(admin)/dashboard/user-management/handler.tsx b/sigap-website/app/(pages)/(admin)/dashboard/user-management/handler.tsx index 23f1b6f..d34ab0a 100644 --- a/sigap-website/app/(pages)/(admin)/dashboard/user-management/handler.tsx +++ b/sigap-website/app/(pages)/(admin)/dashboard/user-management/handler.tsx @@ -7,11 +7,14 @@ import { CreateUserSchema, defaulICreateUserSchemaValues, ICreateUserSchema } fr import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { defaulIInviteUserSchemaValues, IInviteUserSchema, InviteUserSchema } from '@/src/entities/models/users/invite-user.model'; +import { useQueryClient } from '@tanstack/react-query'; export const useAddUserDialogHandler = ({ onUserAdded, onOpenChange }: { onUserAdded: () => void; onOpenChange: (open: boolean) => void; }) => { + + const queryClient = useQueryClient(); const { createUser, isPending } = useCreateUserMutation(); const { @@ -38,7 +41,11 @@ export const useAddUserDialogHandler = ({ onUserAdded, onOpenChange }: { await createUser(data, { onSuccess: () => { + + queryClient.invalidateQueries({ queryKey: ["users"] }); + toast.success("User created successfully."); + onUserAdded(); onOpenChange(false); reset(); @@ -76,6 +83,7 @@ export const useInviteUserHandler = ({ onUserInvited, onOpenChange }: { onOpenChange: (open: boolean) => void; }) => { + const queryClient = useQueryClient(); const { inviteUser, isPending } = useInviteUserMutation(); const { @@ -95,7 +103,11 @@ export const useInviteUserHandler = ({ onUserInvited, onOpenChange }: { const onSubmit = handleSubmit(async (data) => { await inviteUser(data, { onSuccess: () => { + + queryClient.invalidateQueries({ queryKey: ["users"] }); + toast.success("Invitation sent"); + onUserInvited(); onOpenChange(false); reset(); diff --git a/sigap-website/app/(pages)/(admin)/dashboard/user-management/queries.ts b/sigap-website/app/(pages)/(admin)/dashboard/user-management/queries.ts index e92d23e..c2de53f 100644 --- a/sigap-website/app/(pages)/(admin)/dashboard/user-management/queries.ts +++ b/sigap-website/app/(pages)/(admin)/dashboard/user-management/queries.ts @@ -40,7 +40,7 @@ const useUsersAction = () => { const getUserByEmailQuery = (email: string) => ({ queryKey: ["user", "email", email], - queryFn: async () => await getUserByEmail(email) + queryFn: async () => await getUserByEmail({ email }) }); const getUserByUsernameQuery = (username: string) => ({ @@ -62,7 +62,7 @@ const useUsersAction = () => { // Create functions that return configured hooks const inviteUserMutation = useMutation({ mutationKey: ["inviteUser"], - mutationFn: async (credential: ICredentialsInviteUserSchema) => await inviteUser(credential) + mutationFn: async (credential: ICredentialsInviteUserSchema) => await inviteUser(credential) }); const createUserMutation = useMutation({ diff --git a/sigap-website/app/_styles/globals.css b/sigap-website/app/_styles/globals.css index 7339b30..f3d43b9 100644 --- a/sigap-website/app/_styles/globals.css +++ b/sigap-website/app/_styles/globals.css @@ -17,7 +17,7 @@ --popover-foreground: 0 0% 10%; /* #1a1a1a */ /* Warna utama: hijau Supabase #006239 */ - --primary: 155% 100% 19%; /* #006239 */ + --primary: 155 100% 19%; /* #006239 */ --primary-foreground: 0 0% 100%; /* #ffffff untuk kontras pada hijau */ /* Sekunder: abu-abu terang untuk elemen pendukung */ @@ -41,13 +41,13 @@ --input: 0 0% 80%; /* #cccccc */ /* Ring: sama dengan primary untuk fokus */ - --ring: 155% 100% 19%; /* #006239 */ + --ring: 155 100% 19%; /* #006239 */ /* Radius: sudut membulat ringan */ --radius: 0.5rem; /* Chart: gunakan hijau Supabase dan variasi */ - --chart-1: 155% 100% 19%; /* #006239 */ + --chart-1: 155 100% 19%; /* #006239 */ --chart-2: 160 60% 45%; /* sedikit lebih gelap */ --chart-3: 165 55% 40%; --chart-4: 170 50% 35%; @@ -56,12 +56,12 @@ /* Sidebar: mirip dengan kartu di mode terang */ --sidebar-background: 0 0% 98%; /* #fafafa */ --sidebar-foreground: 0 0% 10%; /* #1a1a1a */ - --sidebar-primary: 155% 100% 19%; /* #006239 */ + --sidebar-primary: 155 100% 19%; /* #006239 */ --sidebar-primary-foreground: 0 0% 100%; /* #ffffff */ --sidebar-accent: 0 0% 96%; /* #f5f5f5 */ --sidebar-accent-foreground: 0 0% 10%; /* #1a1a1a */ --sidebar-border: 0 0% 85%; /* #d9d9d9 */ - --sidebar-ring: 155% 100% 19%; /* #006239 */ + --sidebar-ring: 155 100% 19%; /* #006239 */ } .dark { @@ -78,7 +78,7 @@ --popover-foreground: 0 0% 85%; /* #d9d9d9 */ /* Warna utama: hijau Supabase tetap digunakan */ - --primary: 155% 100% 19%; /* #006239 */ + --primary: 155 100% 19%; /* #006239 */ --primary-foreground: 0 0% 100%; /* #ffffff */ /* Sekunder: abu-abu gelap untuk elemen pendukung */ @@ -102,10 +102,10 @@ --input: 0 0% 20%; /* #333333 */ /* Ring: sama dengan primary */ - --ring: 155% 100% 19%; /* #006239 */ + --ring: 155 100% 19%; /* #006239 */ /* Chart: sama seperti mode terang */ - --chart-1: 155% 100% 19%; /* #006239 */ + --chart-1: 155 100% 19%; /* #006239 */ --chart-2: 160 60% 45%; --chart-3: 165 55% 40%; --chart-4: 170 50% 35%; @@ -114,12 +114,12 @@ /* Sidebar: abu-abu gelap */ --sidebar-background: 0 0% 15%; /* #262626 */ --sidebar-foreground: 0 0% 85%; /* #d9d9d9 */ - --sidebar-primary: 155% 100% 19%; /* #006239 */ + --sidebar-primary: 155 100% 19%; /* #006239 */ --sidebar-primary-foreground: 0 0% 100%; /* #ffffff */ --sidebar-accent: 0 0% 20%; /* #333333 */ --sidebar-accent-foreground: 0 0% 85%; /* #d9d9d9 */ --sidebar-border: 0 0% 25%; /* #404040 */ - --sidebar-ring: 155% 100% 19%; /* #006239 */ + --sidebar-ring: 155 100% 19%; /* #006239 */ } } diff --git a/sigap-website/src/application/use-cases/auth/verify-otp.use-case.ts b/sigap-website/src/application/use-cases/auth/verify-otp.use-case.ts index f0bee45..2fa1718 100644 --- a/sigap-website/src/application/use-cases/auth/verify-otp.use-case.ts +++ b/sigap-website/src/application/use-cases/auth/verify-otp.use-case.ts @@ -1,4 +1,4 @@ -import { VerifyOtpSchema } from "@/src/entities/models/auth/verify-otp.model" +import { IVerifyOtpSchema } from "@/src/entities/models/auth/verify-otp.model" import { IUsersRepository } from "../../repositories/users.repository.interface" import { IAuthenticationService } from "../../services/authentication.service.interface" import { IInstrumentationService } from "../../services/instrumentation.service.interface" @@ -12,15 +12,18 @@ export const verifyOtpUseCase = ( instrumentationService: IInstrumentationService, authenticationService: IAuthenticationService, usersRepository: IUsersRepository -) => async (input: VerifyOtpSchema): Promise => { +) => async (input: IVerifyOtpSchema): Promise => { return await instrumentationService.startSpan({ name: "verifyOtp Use Case", op: "function" }, async () => { - const user = await usersRepository.getUserByEmail(input.email) + + const user = await usersRepository.getUserByEmail({ email: input.email }) if (!user) { throw new NotFoundError("User not found") } + console.log("email = ", user.email) + await authenticationService.verifyOtp({ email: input.email, token: input.token diff --git a/sigap-website/src/application/use-cases/users/invite-user.use-case.ts b/sigap-website/src/application/use-cases/users/invite-user.use-case.ts index 6a3fd87..0b1b7d9 100644 --- a/sigap-website/src/application/use-cases/users/invite-user.use-case.ts +++ b/sigap-website/src/application/use-cases/users/invite-user.use-case.ts @@ -14,11 +14,12 @@ export const inviteUserUseCase = ( ) => async (credential: ICredentialsInviteUserSchema): Promise => { return await instrumentationService.startSpan({ name: "inviteUser Use Case", op: "function" }, async () => { - const existingUser = await usersRepository.getUserByEmail(credential) - if (existingUser) { - throw new AuthenticationError("User already exists") - } + // const existingUser = await usersRepository.getUserByEmail(credential) + + // if (existingUser) { + // throw new AuthenticationError("User already exists") + // } const invitedUser = await usersRepository.inviteUser(credential) diff --git a/sigap-website/src/interface-adapters/controllers/auth/verify-otp.controller.tsx b/sigap-website/src/interface-adapters/controllers/auth/verify-otp.controller.tsx index 902c56a..9a0541f 100644 --- a/sigap-website/src/interface-adapters/controllers/auth/verify-otp.controller.tsx +++ b/sigap-website/src/interface-adapters/controllers/auth/verify-otp.controller.tsx @@ -18,6 +18,9 @@ export const verifyOtpController = ) => async (input: Partial>) => { return await instrumentationService.startSpan({ name: "verifyOtp Controller" }, async () => { + + // console.log("input", input) + const { data, error: inputParseError } = verifyOtpInputSchema.safeParse(input) if (inputParseError) {