diff --git a/sigap-website/.vscode/settings.json b/sigap-website/.vscode/settings.json
index 8bb69fd..86953b0 100644
--- a/sigap-website/.vscode/settings.json
+++ b/sigap-website/.vscode/settings.json
@@ -1,3 +1,3 @@
{
- "files.autoSave": "off"
+ "files.autoSave": "afterDelay"
}
diff --git a/sigap-website/app/(auth-pages)/_actions/session.ts b/sigap-website/app/(auth-pages)/_actions/session.ts
index a742b1d..5e2026e 100644
--- a/sigap-website/app/(auth-pages)/_actions/session.ts
+++ b/sigap-website/app/(auth-pages)/_actions/session.ts
@@ -20,7 +20,7 @@ export const checkSession = async () => {
return {
success: true,
session,
- redirectTo: "/protected/dashboard", // or your preferred authenticated route
+ redirectTo: "/dashboard",
};
}
diff --git a/sigap-website/app/(auth-pages)/_actions/sign-in.ts b/sigap-website/app/(auth-pages)/_actions/sign-in.ts
index 5c6ea79..dbdf00e 100644
--- a/sigap-website/app/(auth-pages)/_actions/sign-in.ts
+++ b/sigap-website/app/(auth-pages)/_actions/sign-in.ts
@@ -12,14 +12,16 @@ export const signInAction = async (formData: FormData) => {
try {
// First, check for existing session
- const { session, error: sessionError } = await checkSession();
+ const {
+ data: { session },
+ } = await supabase.auth.getSession();
// If there's an active session and the email matches
- if (session && session.user.email === email) {
+ if (session?.user?.email === email) {
return {
success: true,
- message: "Already logged in",
- redirectTo: "/protected/dashboard", // or wherever you want to redirect logged in users
+ message: "You are already signed in",
+ redirectTo: "/dashboard",
};
}
diff --git a/sigap-website/app/(auth-pages)/_actions/verify-otp.ts b/sigap-website/app/(auth-pages)/_actions/verify-otp.ts
index dee6f71..c512e33 100644
--- a/sigap-website/app/(auth-pages)/_actions/verify-otp.ts
+++ b/sigap-website/app/(auth-pages)/_actions/verify-otp.ts
@@ -26,5 +26,5 @@ export const verifyOtpAction = async (formData: FormData) => {
return redirect(`/verify-otp?error=${encodeURIComponent(error.message)}`);
}
- return redirect("/protected/dashboard?message=OTP verified successfully");
+ return redirect("/dashboard?message=OTP verified successfully");
};
diff --git a/sigap-website/app/(auth-pages)/layout.tsx b/sigap-website/app/(auth-pages)/layout.tsx
index 7102549..61b4de1 100644
--- a/sigap-website/app/(auth-pages)/layout.tsx
+++ b/sigap-website/app/(auth-pages)/layout.tsx
@@ -1,17 +1,21 @@
import { redirect } from "next/navigation";
import { checkSession } from "./_actions/session";
+import { createClient } from "@/utils/supabase/client";
export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
- const sessionResult = await checkSession();
+ // const supabase = createClient();
- // If there's an active session, redirect to dashboard
- if (sessionResult.success && sessionResult.redirectTo) {
- redirect(sessionResult.redirectTo);
- }
+ // const {
+ // data: { session },
+ // } = await supabase.auth.getSession();
+
+ // if (!session) {
+ // return redirect("/sign-in");
+ // }
return
{children}
;
}
diff --git a/sigap-website/app/(protected)/(admin)/dashboard/page.tsx b/sigap-website/app/(protected)/(admin)/dashboard/page.tsx
index 615f75b..afc58de 100644
--- a/sigap-website/app/(protected)/(admin)/dashboard/page.tsx
+++ b/sigap-website/app/(protected)/(admin)/dashboard/page.tsx
@@ -11,6 +11,7 @@ export default async function DashboardPage() {
if (!user) {
return redirect("/sign-in");
}
+
return (
<>
diff --git a/sigap-website/app/(protected)/(admin)/dashboard/user-management/action.ts b/sigap-website/app/(protected)/(admin)/dashboard/user-management/action.ts
index aacbbff..1f5a6d5 100644
--- a/sigap-website/app/(protected)/(admin)/dashboard/user-management/action.ts
+++ b/sigap-website/app/(protected)/(admin)/dashboard/user-management/action.ts
@@ -9,7 +9,6 @@ import {
UserResponse,
} from "@/src/models/users/users.model";
import { createClient } from "@/utils/supabase/server";
-import { createClient as createClientSide } from "@/utils/supabase/client";
import { createAdminClient } from "@/utils/supabase/admin";
// Initialize Supabase client with admin key
@@ -103,30 +102,34 @@ export async function createUser(
export async function uploadAvatar(userId: string, email: string, file: File) {
try {
- const supabase = createClientSide();
-
- // Pastikan mendapatkan session untuk autentikasi
- const { data: session } = await supabase.auth.getSession();
- if (!session) throw new Error("User is not authenticated");
-
- const baseUrl = `${process.env.NEXT_PUBLIC_SUPABASE_STORAGE_URL}/avatars`;
+ const supabase = await createClient();
const fileExt = file.name.split(".").pop();
const emailName = email.split("@")[0];
const fileName = `AVR-${emailName}.${fileExt}`;
- const filePath = `${baseUrl}/${fileName}`;
+ // Change this line - store directly in the user's folder
+ const filePath = `${userId}/${fileName}`;
+
+ // Upload the avatar to Supabase storage
const { error: uploadError } = await supabase.storage
.from("avatars")
- .upload(fileName, file, {
- upsert: false,
+ .upload(filePath, file, {
+ upsert: true,
contentType: file.type,
});
if (uploadError) {
+ console.error("Error uploading avatar:", uploadError);
throw uploadError;
}
+ // Get the public URL
+ const {
+ data: { publicUrl },
+ } = supabase.storage.from("avatars").getPublicUrl(filePath);
+
+ // Update user profile with the new avatar URL
await db.users.update({
where: {
id: userId,
@@ -134,16 +137,12 @@ export async function uploadAvatar(userId: string, email: string, file: File) {
data: {
profile: {
update: {
- avatar: filePath,
+ avatar: publicUrl,
},
},
},
});
- const {
- data: { publicUrl },
- } = supabase.storage.from("avatars").getPublicUrl(fileName);
-
return publicUrl;
} catch (error) {
console.error("Error uploading avatar:", error);
@@ -151,6 +150,7 @@ export async function uploadAvatar(userId: string, email: string, file: File) {
}
}
+
// Update an existing user
export async function updateUser(
userId: string,
diff --git a/sigap-website/app/(protected)/(admin)/layout.tsx b/sigap-website/app/(protected)/(admin)/layout.tsx
index 5216332..f20db60 100644
--- a/sigap-website/app/(protected)/(admin)/layout.tsx
+++ b/sigap-website/app/(protected)/(admin)/layout.tsx
@@ -27,12 +27,23 @@ import { Separator } from "@/app/_components/ui/separator";
import { InboxDrawer } from "@/app/_components/inbox-drawer";
import FloatingActionSearchBar from "@/app/_components/floating-action-search-bar";
import { AppSidebar } from "@/app/_components/admin/app-sidebar";
+import { createClient } from "@/utils/supabase/server";
+import { redirect } from "next/navigation";
export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
+ const supabase = await createClient();
+ const {
+ data: { session },
+ } = await supabase.auth.getSession();
+
+ if (!session) {
+ return redirect("/sign-in");
+ }
+
return (
<>
diff --git a/sigap-website/app/_components/admin/navigations/nav-main.tsx b/sigap-website/app/_components/admin/navigations/nav-main.tsx
index 6e92404..af4652d 100644
--- a/sigap-website/app/_components/admin/navigations/nav-main.tsx
+++ b/sigap-website/app/_components/admin/navigations/nav-main.tsx
@@ -19,6 +19,7 @@ import {
import type * as TablerIcons from "@tabler/icons-react";
import { useNavigations } from "@/app/_hooks/use-navigations";
+import { formatUrl } from "@/utils/utils";
interface SubSubItem {
title: string;
@@ -40,22 +41,6 @@ interface NavItem {
subItems?: SubItem[];
}
-// Helper function to ensure URLs are properly formatted
-function formatUrl(url: string): string {
- // If URL starts with a slash, it's already absolute
- if (url.startsWith("/")) {
- return url;
- }
-
- // Otherwise, ensure it's properly formatted relative to root
- // Remove any potential duplicated '/dashboard' prefixes
- if (url.startsWith("dashboard/")) {
- return "/" + url;
- }
-
- return "/" + url;
-}
-
function SubSubItemComponent({ item }: { item: SubSubItem }) {
const router = useNavigations();
const formattedUrl = formatUrl(item.url);
diff --git a/sigap-website/app/_components/admin/settings/setting-dialog.tsx b/sigap-website/app/_components/admin/settings/setting-dialog.tsx
index ce8a9ba..9ffb380 100644
--- a/sigap-website/app/_components/admin/settings/setting-dialog.tsx
+++ b/sigap-website/app/_components/admin/settings/setting-dialog.tsx
@@ -1,6 +1,6 @@
"use client";
-import * as React from "react";
+
import { cn } from "@/lib/utils";
import {
Dialog,
@@ -27,6 +27,7 @@ import {
import type { User } from "@/src/models/users/users.model";
import { ProfileSettings } from "./profile-settings";
import { DialogTitle } from "@radix-ui/react-dialog";
+import { useState } from "react";
interface SettingsDialogProps {
user: User | null;
@@ -55,7 +56,7 @@ export function SettingsDialog({
open,
onOpenChange,
}: SettingsDialogProps) {
- const [selectedTab, setSelectedTab] = React.useState(defaultTab);
+ const [selectedTab, setSelectedTab] = useState(defaultTab);
// Get user display name
const preferredName = user?.profile?.first_name || "";
diff --git a/sigap-website/app/_components/admin/users/user-management.tsx b/sigap-website/app/_components/admin/users/user-management.tsx
index 5b3dfe0..5d9a148 100644
--- a/sigap-website/app/_components/admin/users/user-management.tsx
+++ b/sigap-website/app/_components/admin/users/user-management.tsx
@@ -40,6 +40,7 @@ import { AddUserDialog } from "./add-user-dialog";
import { UserDetailsSheet } from "./sheet";
import { Avatar } from "@radix-ui/react-avatar";
import Image from "next/image";
+import { useNavigations } from "@/app/_hooks/use-navigations";
export default function UserManagement() {
const [searchQuery, setSearchQuery] = useState("");
@@ -65,11 +66,12 @@ export default function UserManagement() {
// Use React Query to fetch users
const [users, setUsers] = useState([]);
- const [isLoading, setIsLoading] = useState(true);
+ const { isLoading, setIsLoading } = useNavigations();
useEffect(() => {
const fetchData = async () => {
try {
+ setIsLoading(true);
const fetchedUsers = await fetchUsers();
setUsers(fetchedUsers);
} catch (error) {
diff --git a/sigap-website/app/_components/admin/users/user-stats.tsx b/sigap-website/app/_components/admin/users/user-stats.tsx
index 3f0b4d5..a07241d 100644
--- a/sigap-website/app/_components/admin/users/user-stats.tsx
+++ b/sigap-website/app/_components/admin/users/user-stats.tsx
@@ -5,6 +5,9 @@ import { Card, CardContent } from "@/app/_components/ui/card";
import { Users, UserCheck, UserX } from "lucide-react";
import { fetchUsers } from "@/app/(protected)/(admin)/dashboard/user-management/action";
import { User } from "@/src/models/users/users.model";
+import { useNavigations } from "@/app/_hooks/use-navigations";
+import { useEffect, useState } from "react";
+import { toast } from "sonner";
function calculateUserStats(users: User[]) {
const totalUsers = users.length;
@@ -25,10 +28,23 @@ function calculateUserStats(users: User[]) {
}
export function UserStats() {
- const { data: users = [], isLoading } = useQuery({
- queryKey: ["users"],
- queryFn: fetchUsers,
- });
+ const { isLoading, setIsLoading } = useNavigations();
+ const [users, setUsers] = useState([]);
+
+ useEffect(() => {
+ const fetchUserData = async () => {
+ try {
+ setIsLoading(true);
+ const fetchedUsers = await fetchUsers();
+ setUsers(fetchedUsers);
+ } catch (error) {
+ toast.error("Failed to fetch users");
+ } finally {
+ setIsLoading(false);
+ }
+ };
+ fetchUserData();
+ }, [setIsLoading]);
const stats = calculateUserStats(users);
diff --git a/sigap-website/app/_components/inbox-drawer.tsx b/sigap-website/app/_components/inbox-drawer.tsx
index 20ee2de..ef62448 100644
--- a/sigap-website/app/_components/inbox-drawer.tsx
+++ b/sigap-website/app/_components/inbox-drawer.tsx
@@ -145,9 +145,9 @@ const InboxDrawerComponent: React.FC = ({
@@ -171,7 +169,7 @@ const InboxDrawerComponent: React.FC = ({