mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 08:46:22 +02:00
chore: Updated UserRead schema to include pages_limit and pages_used fields
- Expanded installation options in README to include SurfSense Cloud as a new method. - Updated UserRead schema to include pages_limit and pages_used fields. - Added AnnouncementBanner component to the dashboard layout for improved user notifications. - Refactored DashboardPage to utilize useUser hook for user state management. - Integrated page usage display in AppSidebar to show user-specific page limits and usage. - Removed deprecated apiClient code and replaced it with hooks for better API interaction.
This commit is contained in:
parent
a3a5b13f48
commit
4dd7e8fc1f
13 changed files with 456 additions and 339 deletions
|
|
@ -13,24 +13,7 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { apiClient } from "@/lib/api";
|
||||
|
||||
interface Chat {
|
||||
created_at: string;
|
||||
id: number;
|
||||
type: string;
|
||||
title: string;
|
||||
messages: string[];
|
||||
search_space_id: number;
|
||||
}
|
||||
|
||||
interface SearchSpace {
|
||||
created_at: string;
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
user_id: string;
|
||||
}
|
||||
import { useChats, useSearchSpace, useUser } from "@/hooks";
|
||||
|
||||
interface AppSidebarProviderProps {
|
||||
searchSpaceId: string;
|
||||
|
|
@ -58,21 +41,25 @@ export function AppSidebarProvider({
|
|||
}: AppSidebarProviderProps) {
|
||||
const t = useTranslations("dashboard");
|
||||
const tCommon = useTranslations("common");
|
||||
const [recentChats, setRecentChats] = useState<
|
||||
{
|
||||
name: string;
|
||||
url: string;
|
||||
icon: string;
|
||||
id: number;
|
||||
search_space_id: number;
|
||||
actions: { name: string; icon: string; onClick: () => void }[];
|
||||
}[]
|
||||
>([]);
|
||||
const [searchSpace, setSearchSpace] = useState<SearchSpace | null>(null);
|
||||
const [isLoadingChats, setIsLoadingChats] = useState(true);
|
||||
const [isLoadingSearchSpace, setIsLoadingSearchSpace] = useState(true);
|
||||
const [chatError, setChatError] = useState<string | null>(null);
|
||||
const [searchSpaceError, setSearchSpaceError] = useState<string | null>(null);
|
||||
|
||||
// Use the new hooks
|
||||
const {
|
||||
chats,
|
||||
loading: isLoadingChats,
|
||||
error: chatError,
|
||||
fetchChats: fetchRecentChats,
|
||||
deleteChat,
|
||||
} = useChats({ searchSpaceId, limit: 5, skip: 0 });
|
||||
|
||||
const {
|
||||
searchSpace,
|
||||
loading: isLoadingSearchSpace,
|
||||
error: searchSpaceError,
|
||||
fetchSearchSpace,
|
||||
} = useSearchSpace({ searchSpaceId });
|
||||
|
||||
const { user } = useUser();
|
||||
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||
const [chatToDelete, setChatToDelete] = useState<{ id: number; name: string } | null>(null);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
|
@ -83,95 +70,32 @@ export function AppSidebarProvider({
|
|||
setIsClient(true);
|
||||
}, []);
|
||||
|
||||
// Memoized fetch function for chats
|
||||
const fetchRecentChats = useCallback(async () => {
|
||||
try {
|
||||
// Only run on client-side
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
const chats: Chat[] = await apiClient.get<Chat[]>(
|
||||
`api/v1/chats?limit=5&skip=0&search_space_id=${searchSpaceId}`
|
||||
);
|
||||
|
||||
// Sort chats by created_at in descending order (newest first)
|
||||
const sortedChats = chats.sort(
|
||||
(a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
||||
);
|
||||
|
||||
// Transform API response to the format expected by AppSidebar
|
||||
const formattedChats = sortedChats.map((chat) => ({
|
||||
name: chat.title || `Chat ${chat.id}`,
|
||||
url: `/dashboard/${chat.search_space_id}/researcher/${chat.id}`,
|
||||
icon: "MessageCircleMore",
|
||||
id: chat.id,
|
||||
search_space_id: chat.search_space_id,
|
||||
actions: [
|
||||
{
|
||||
name: "Delete",
|
||||
icon: "Trash2",
|
||||
onClick: () => {
|
||||
setChatToDelete({ id: chat.id, name: chat.title || `Chat ${chat.id}` });
|
||||
setShowDeleteDialog(true);
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
setRecentChats(formattedChats);
|
||||
setChatError(null);
|
||||
} catch (error) {
|
||||
console.error("Error fetching chats:", error);
|
||||
setChatError(error instanceof Error ? error.message : "Unknown error occurred");
|
||||
setRecentChats([]);
|
||||
} finally {
|
||||
setIsLoadingChats(false);
|
||||
}
|
||||
}, [searchSpaceId]);
|
||||
|
||||
// Memoized fetch function for search space
|
||||
const fetchSearchSpace = useCallback(async () => {
|
||||
try {
|
||||
// Only run on client-side
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
const data: SearchSpace = await apiClient.get<SearchSpace>(
|
||||
`api/v1/searchspaces/${searchSpaceId}`
|
||||
);
|
||||
setSearchSpace(data);
|
||||
setSearchSpaceError(null);
|
||||
} catch (error) {
|
||||
console.error("Error fetching search space:", error);
|
||||
setSearchSpaceError(error instanceof Error ? error.message : "Unknown error occurred");
|
||||
} finally {
|
||||
setIsLoadingSearchSpace(false);
|
||||
}
|
||||
}, [searchSpaceId]);
|
||||
|
||||
// Retry function
|
||||
const retryFetch = useCallback(() => {
|
||||
setChatError(null);
|
||||
setSearchSpaceError(null);
|
||||
setIsLoadingChats(true);
|
||||
setIsLoadingSearchSpace(true);
|
||||
fetchRecentChats();
|
||||
fetchSearchSpace();
|
||||
}, [fetchRecentChats, fetchSearchSpace]);
|
||||
|
||||
// Fetch recent chats
|
||||
useEffect(() => {
|
||||
fetchRecentChats();
|
||||
|
||||
// Set up a refresh interval (every 5 minutes)
|
||||
const intervalId = setInterval(fetchRecentChats, 5 * 60 * 1000);
|
||||
|
||||
// Clean up interval on component unmount
|
||||
return () => clearInterval(intervalId);
|
||||
}, [fetchRecentChats]);
|
||||
|
||||
// Fetch search space details
|
||||
useEffect(() => {
|
||||
fetchSearchSpace();
|
||||
}, [fetchSearchSpace]);
|
||||
// Transform API response to the format expected by AppSidebar
|
||||
const recentChats = useMemo(() => {
|
||||
return chats.map((chat) => ({
|
||||
name: chat.title || `Chat ${chat.id}`,
|
||||
url: `/dashboard/${chat.search_space_id}/researcher/${chat.id}`,
|
||||
icon: "MessageCircleMore",
|
||||
id: chat.id,
|
||||
search_space_id: chat.search_space_id,
|
||||
actions: [
|
||||
{
|
||||
name: "Delete",
|
||||
icon: "Trash2",
|
||||
onClick: () => {
|
||||
setChatToDelete({ id: chat.id, name: chat.title || `Chat ${chat.id}` });
|
||||
setShowDeleteDialog(true);
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
}, [chats]);
|
||||
|
||||
// Handle delete chat with better error handling
|
||||
const handleDeleteChat = useCallback(async () => {
|
||||
|
|
@ -179,11 +103,7 @@ export function AppSidebarProvider({
|
|||
|
||||
try {
|
||||
setIsDeleting(true);
|
||||
|
||||
await apiClient.delete(`api/v1/chats/${chatToDelete.id}`);
|
||||
|
||||
// Update local state
|
||||
setRecentChats((prev) => prev.filter((chat) => chat.id !== chatToDelete.id));
|
||||
await deleteChat(chatToDelete.id);
|
||||
} catch (error) {
|
||||
console.error("Error deleting chat:", error);
|
||||
// You could show a toast notification here
|
||||
|
|
@ -192,7 +112,7 @@ export function AppSidebarProvider({
|
|||
setShowDeleteDialog(false);
|
||||
setChatToDelete(null);
|
||||
}
|
||||
}, [chatToDelete]);
|
||||
}, [chatToDelete, deleteChat]);
|
||||
|
||||
// Memoized fallback chats
|
||||
const fallbackChats = useMemo(() => {
|
||||
|
|
@ -260,14 +180,34 @@ export function AppSidebarProvider({
|
|||
tCommon,
|
||||
]);
|
||||
|
||||
// Prepare page usage data
|
||||
const pageUsage = user
|
||||
? {
|
||||
pagesUsed: user.pages_used,
|
||||
pagesLimit: user.pages_limit,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
// Show loading state if not client-side
|
||||
if (!isClient) {
|
||||
return <AppSidebar navSecondary={navSecondary} navMain={navMain} RecentChats={[]} />;
|
||||
return (
|
||||
<AppSidebar
|
||||
navSecondary={navSecondary}
|
||||
navMain={navMain}
|
||||
RecentChats={[]}
|
||||
pageUsage={pageUsage}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppSidebar navSecondary={updatedNavSecondary} navMain={navMain} RecentChats={displayChats} />
|
||||
<AppSidebar
|
||||
navSecondary={updatedNavSecondary}
|
||||
navMain={navMain}
|
||||
RecentChats={displayChats}
|
||||
pageUsage={pageUsage}
|
||||
/>
|
||||
|
||||
{/* Delete Confirmation Dialog */}
|
||||
<Dialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue