diff --git a/sigap-website/app/(pages)/(admin)/_components/app-sidebar.tsx b/sigap-website/app/(pages)/(admin)/_components/app-sidebar.tsx index 6e63b9a..9bd9570 100644 --- a/sigap-website/app/(pages)/(admin)/_components/app-sidebar.tsx +++ b/sigap-website/app/(pages)/(admin)/_components/app-sidebar.tsx @@ -1,6 +1,6 @@ "use client"; -import * as React from "react"; +import { useEffect } from "react"; import { NavMain } from "@/app/(pages)/(admin)/_components/navigations/nav-main"; import { NavReports } from "@/app/(pages)/(admin)/_components/navigations/nav-report"; @@ -17,26 +17,25 @@ import { NavPreMain } from "./navigations/nav-pre-main"; import { navData } from "@/prisma/data/nav"; import { TeamSwitcher } from "../../../_components/team-switcher"; import { useGetCurrentUserQuery } from "../dashboard/user-management/_queries/queries"; +import { useUserStore } from "@/app/_utils/zustand/stores/user"; +import { useUserActionsHandler } from "../dashboard/user-management/_handlers/actions/use-user-actions"; export function AppSidebar({ ...props }: React.ComponentProps) { const { data: user, isPending, error } = useGetCurrentUserQuery() - // React.useEffect(() => { - // async function fetchUser() { - // try { - // setIsLoading(true); - // const userData = await getCurrentUser(); - // setUser(userData.data.user); - // } catch (error) { - // console.error("Failed to fetch user:", error); - // } finally { - // setIsLoading(false); - // } - // } + const { setUser, setIsPending } = useUserStore(); - // fetchUser(); - // }, []); + // Set pending state + useEffect(() => { + setIsPending(isPending); + }, [isPending, setIsPending]); + + useEffect(() => { + if (user) { + setUser(user); + } + }, [user, setUser]); return ( @@ -49,7 +48,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { - + diff --git a/sigap-website/app/(pages)/(admin)/_components/navigations/nav-user.tsx b/sigap-website/app/(pages)/(admin)/_components/navigations/nav-user.tsx index 9b04ad8..0842792 100644 --- a/sigap-website/app/(pages)/(admin)/_components/navigations/nav-user.tsx +++ b/sigap-website/app/(pages)/(admin)/_components/navigations/nav-user.tsx @@ -29,8 +29,18 @@ import type { IUserSchema } from "@/src/entities/models/users/users.model"; import { SettingsDialog } from "../settings/setting-dialog"; import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogCancel, AlertDialogAction } from "@/app/_components/ui/alert-dialog"; import { useSignOutHandler } from "@/app/(pages)/(auth)/_handlers/use-sign-out"; +import { useGetCurrentUserQuery } from "../../dashboard/user-management/_queries/queries"; +import { useUserStore } from "@/app/_utils/zustand/stores/user"; + +interface NavUserProps { + user: IUserSchema | null; + isPending: boolean; +} + +export function NavUser() { + + const { user, isPending } = useUserStore() -export function NavUser({ user }: { user: IUserSchema | null }) { const { isMobile } = useSidebar(); const [isDialogOpen, setIsDialogOpen] = useState(false); @@ -59,9 +69,9 @@ export function NavUser({ user }: { user: IUserSchema | null }) { return "U"; }; - const { handleSignOut, isPending, errors, error } = useSignOutHandler(); + const { handleSignOut, isPending: isSignOutPending, errors, error: isSignOutError } = useSignOutHandler(); - function LogoutButton({ handleSignOut, isPending }: { handleSignOut: () => void; isPending: boolean }) { + function LogoutButton({ handleSignOut, isSignOutPending }: { handleSignOut: () => void; isSignOutPending: boolean }) { const [open, setOpen] = useState(false); return ( @@ -72,11 +82,20 @@ export function NavUser({ user }: { user: IUserSchema | null }) { e.preventDefault(); setOpen(true); // Buka dialog saat diklik }} - disabled={isPending} + disabled={isSignOutPending} className="space-x-2" > - - Log out + {isSignOutPending ? ( + <> + + Logging out... + + ) : ( + <> + + Log out + + )} {/* Alert Dialog */} @@ -94,14 +113,14 @@ export function NavUser({ user }: { user: IUserSchema | null }) { onClick={() => { handleSignOut(); - if (!isPending) { + if (!isSignOutPending) { setOpen(false); } }} className="btn btn-primary" - disabled={isPending} + disabled={isSignOutPending} > - {isPending ? ( + {isSignOutPending ? ( <> Logging You Out... @@ -126,68 +145,81 @@ export function NavUser({ user }: { user: IUserSchema | null }) { size="lg" className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground" > - - - - {getInitials()} - - -
- {username} - {userEmail} -
- + {isPending ? ( +
+
+
+
+
+
+
+ ) : ( + <> + + + + {getInitials()} + + +
+ {username} + {userEmail} +
+ + + )} - - -
- - - - {getInitials()} - - -
- - {username} - - {userEmail} + {!isPending && ( + + +
+ + + + {getInitials()} + + +
+ + {username} + + {userEmail} +
-
- - - - - - Upgrade to Pro - - - - - { - e.preventDefault(); - }} - > - - Settings - - } - /> - - - - + + + + + + Upgrade to Pro + + + + + { + e.preventDefault(); + }} + > + + Settings + + } + /> + + + + + )} diff --git a/sigap-website/app/(pages)/(admin)/_components/settings/profile-settings.tsx b/sigap-website/app/(pages)/(admin)/_components/settings/profile-settings.tsx index 9ecda4a..588ebc7 100644 --- a/sigap-website/app/(pages)/(admin)/_components/settings/profile-settings.tsx +++ b/sigap-website/app/(pages)/(admin)/_components/settings/profile-settings.tsx @@ -46,65 +46,6 @@ interface ProfileSettingsProps { } export function ProfileSettings({ user }: ProfileSettingsProps) { - // const [isPending, setIsepisPending] = useState(false); - // const fileInputRef = useRef(null); - - // // Use profile data with fallbacks - // const username = user?.profile?.username || ""; - // const email = user?.email || ""; - // const userAvatar = user?.profile?.avatar || ""; - - // const form = useForm({ - // resolver: zodResolver(profileFormSchema), - // defaultValues: { - // username: username || "", - // avatar: userAvatar || "", - // }, - // }); - - // const handleFileChange = async (e: React.ChangeEvent) => { - // const file = e.target.files?.[0]; - - // if (!file || !user?.id || !user?.email) return; - - // try { - // setIsepisPending(true); - - // // Upload avatar to storage - // // const publicUrl = await uploadAvatar(user.id, user.email, file); - - // // console.log("publicUrl", publicUrl); - - // // Update the form value - // // form.setValue("avatar", publicUrl); - // } catch (error) { - // console.error("Error uploading avatar:", error); - // } finally { - // setIsepisPending(false); - // } - // }; - - // const handleAvatarClick = () => { - // fileInputRef.current?.click(); - // }; - - // async function onSubmit(data: ProfileFormValues) { - // try { - // if (!user?.id) return; - - // // Update profile in database - // const { error } = await updateUser(user.id, { - // profile: { - // avatar: data.avatar || undefined, - // username: data.username || undefined, - // }, - // }); - - // if (error) throw error; - // } catch (error) { - // console.error("Error updating profile:", error); - // } - const email = user?.email || ""; const username = user?.profile?.username || ""; diff --git a/sigap-website/app/(pages)/(admin)/_components/settings/security-setting.tsx b/sigap-website/app/(pages)/(admin)/_components/settings/security-setting.tsx index 25efc73..d0ecb36 100644 --- a/sigap-website/app/(pages)/(admin)/_components/settings/security-setting.tsx +++ b/sigap-website/app/(pages)/(admin)/_components/settings/security-setting.tsx @@ -1,11 +1,12 @@ "use client"; -import type { User } from "@/src/entities/models/users/users.model"; + import { Button } from "@/app/_components/ui/button"; import { Separator } from "@/app/_components/ui/separator"; +import { IUserSchema } from "@/src/entities/models/users/users.model"; interface SecuritySettingsProps { - user: User | null; + user: IUserSchema | null; } export function SecuritySettings({ user }: SecuritySettingsProps) { diff --git a/sigap-website/app/(pages)/(admin)/_components/settings/setting-dialog.tsx b/sigap-website/app/(pages)/(admin)/_components/settings/setting-dialog.tsx index 783c477..e3b80ac 100644 --- a/sigap-website/app/(pages)/(admin)/_components/settings/setting-dialog.tsx +++ b/sigap-website/app/(pages)/(admin)/_components/settings/setting-dialog.tsx @@ -36,9 +36,9 @@ import NotificationsSetting from "./notification-settings"; import PreferencesSettings from "./preference-settings"; import ImportData from "./import-data"; import { IUserSchema } from "@/src/entities/models/users/users.model"; +import { useUserStore } from "@/app/_utils/zustand/stores/user"; interface SettingsDialogProps { - user: IUserSchema | null; trigger: React.ReactNode; defaultTab?: string; open?: boolean; @@ -58,12 +58,14 @@ interface SettingsSection { } export function SettingsDialog({ - user, trigger, defaultTab = "account", open, onOpenChange, }: SettingsDialogProps) { + + const { user, isPending } = useUserStore(); + const [selectedTab, setSelectedTab] = useState(defaultTab); // Get user display name @@ -130,13 +132,23 @@ export function SettingsDialog({
- - - - {displayName[0].toUpperCase()} - - - {displayName} + {isPending ? ( +
+ ) : ( + + + + {displayName[0].toUpperCase()} + + + )} + + {isPending ? ( +
+ ) : ( + displayName + )} +
{sections.map((section, index) => (
@@ -173,7 +185,13 @@ export function SettingsDialog({ {/* Content */}
-
{currentTab?.content}
+
+ {isPending ? ( +
+ ) : ( + currentTab?.content + )} +
diff --git a/sigap-website/app/(pages)/(auth)/_handlers/use-sign-in-with-password.ts b/sigap-website/app/(pages)/(auth)/_handlers/use-sign-in-with-password.ts index 72a2c33..dc570f2 100644 --- a/sigap-website/app/(pages)/(auth)/_handlers/use-sign-in-with-password.ts +++ b/sigap-website/app/(pages)/(auth)/_handlers/use-sign-in-with-password.ts @@ -39,9 +39,8 @@ export const useSignInWithPasswordHandler = () => { formData.append('email', data.email); formData.append('password', data.password); - try { - toast.promise( + await toast.promise( signInWithPassword(formData), { loading: 'Signing in...', @@ -52,6 +51,7 @@ export const useSignInWithPasswordHandler = () => { }, error: (err) => { const errorMessage = err?.message || 'Failed to send email.'; + setError(errorMessage); return errorMessage; } @@ -63,6 +63,7 @@ export const useSignInWithPasswordHandler = () => { } }); + // Extract the validation error message for the email field const getFieldErrorMessage = (fieldName: keyof ISignInWithPasswordSchema) => { return formErrors[fieldName]?.message || ''; diff --git a/sigap-website/app/(pages)/(auth)/action.ts b/sigap-website/app/(pages)/(auth)/action.ts index 7077085..ad97233 100644 --- a/sigap-website/app/(pages)/(auth)/action.ts +++ b/sigap-website/app/(pages)/(auth)/action.ts @@ -62,8 +62,12 @@ export async function signInWithPassword(formData: FormData) { const email = formData.get("email")?.toString() const password = formData.get("password")?.toString() + console.log("woi:", email + " " + password) + const signInWithPasswordController = getInjection("ISignInWithPasswordController") - return await signInWithPasswordController({ email, password }) + await signInWithPasswordController({ email, password }) + + return { success: true } } catch (err) { if (err instanceof InputParseError) { return { error: err.message } diff --git a/sigap-website/app/(pages)/(auth)/sign-in/_components/sign-in-with-password-form.tsx b/sigap-website/app/(pages)/(auth)/sign-in/_components/sign-in-with-password-form.tsx index eef1071..2f068d6 100644 --- a/sigap-website/app/(pages)/(auth)/sign-in/_components/sign-in-with-password-form.tsx +++ b/sigap-website/app/(pages)/(auth)/sign-in/_components/sign-in-with-password-form.tsx @@ -29,6 +29,7 @@ export function SignInWithPasswordForm({ // Get the current active handler based on state const activeHandler = isSignInWithPassword ? passwordHandler : passwordlessHandler; + // Toggle password form field const togglePasswordField = () => { setIsSignInWithPassword(!isSignInWithPassword); diff --git a/sigap-website/app/_utils/zustand/stores/user.ts b/sigap-website/app/_utils/zustand/stores/user.ts new file mode 100644 index 0000000..3b08790 --- /dev/null +++ b/sigap-website/app/_utils/zustand/stores/user.ts @@ -0,0 +1,18 @@ +import { IUserSchema } from "@/src/entities/models/users/users.model"; +import { create } from "zustand"; + +interface UserState { + user: IUserSchema | null; + isPending: boolean; + setUser: (user: IUserSchema | null) => void; + setIsPending: (isPending: boolean) => void; + logout: () => void; +} + +export const useUserStore = create((set) => ({ + user: null, + isPending: false, + setUser: (user) => set({ user }), + setIsPending: (isPending) => set({ isPending }), + logout: () => set({ user: null, isPending: false }), +})); \ No newline at end of file diff --git a/sigap-website/package-lock.json b/sigap-website/package-lock.json index b55307a..83ec49e 100644 --- a/sigap-website/package-lock.json +++ b/sigap-website/package-lock.json @@ -50,7 +50,8 @@ "resend": "^4.1.2", "sonner": "^2.0.1", "vaul": "^1.1.2", - "zod": "^3.24.2" + "zod": "^3.24.2", + "zustand": "^5.0.3" }, "devDependencies": { "@tanstack/eslint-plugin-query": "^5.67.2", @@ -10787,6 +10788,35 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/sigap-website/package.json b/sigap-website/package.json index 15752d4..ad01913 100644 --- a/sigap-website/package.json +++ b/sigap-website/package.json @@ -55,7 +55,8 @@ "resend": "^4.1.2", "sonner": "^2.0.1", "vaul": "^1.1.2", - "zod": "^3.24.2" + "zod": "^3.24.2", + "zustand": "^5.0.3" }, "devDependencies": { "@tanstack/eslint-plugin-query": "^5.67.2", diff --git a/sigap-website/src/infrastructure/services/authentication.service.ts b/sigap-website/src/infrastructure/services/authentication.service.ts index 72a3a86..90d4811 100644 --- a/sigap-website/src/infrastructure/services/authentication.service.ts +++ b/sigap-website/src/infrastructure/services/authentication.service.ts @@ -59,6 +59,8 @@ export class AuthenticationService implements IAuthenticationService { const supabase = await this.supabaseServer const { email, password } = credentials + + const signIn = supabase.auth.signInWithPassword({ email, password }) const { data: { session }, error } = await this.instrumentationService.startSpan({