This commit is contained in:
NotII
2025-03-24 17:18:27 +00:00
parent 43a3656233
commit 06984b53ef
2 changed files with 82 additions and 17 deletions

View File

@@ -20,7 +20,9 @@ import {
Loader2, Loader2,
RefreshCw, RefreshCw,
Eye, Eye,
User User,
ChevronLeft,
ChevronRight
} from "lucide-react"; } from "lucide-react";
import { clientFetch } from "@/lib/client-utils"; import { clientFetch } from "@/lib/client-utils";
import { toast } from "sonner"; import { toast } from "sonner";
@@ -41,12 +43,23 @@ interface UnreadCounts {
chatCounts: Record<string, number>; chatCounts: Record<string, number>;
} }
interface ChatResponse {
chats: Chat[];
page: number;
totalPages: number;
totalChats: number;
}
export default function ChatTable() { export default function ChatTable() {
const router = useRouter(); const router = useRouter();
const [chats, setChats] = useState<Chat[]>([]); const [chats, setChats] = useState<Chat[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [unreadCounts, setUnreadCounts] = useState<UnreadCounts>({ totalUnread: 0, chatCounts: {} }); const [unreadCounts, setUnreadCounts] = useState<UnreadCounts>({ totalUnread: 0, chatCounts: {} });
const audioRef = useRef<HTMLAudioElement | null>(null); const audioRef = useRef<HTMLAudioElement | null>(null);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalChats, setTotalChats] = useState(0);
const ITEMS_PER_PAGE = 10;
// Initialize audio element for notifications // Initialize audio element for notifications
useEffect(() => { useEffect(() => {
@@ -90,7 +103,7 @@ export default function ChatTable() {
return { vendorId, authToken }; return { vendorId, authToken };
}; };
// Fetch chats when component mounts // Fetch chats when component mounts or page changes
useEffect(() => { useEffect(() => {
fetchChats(); fetchChats();
@@ -100,7 +113,7 @@ export default function ChatTable() {
}, 30000); // Check every 30 seconds }, 30000); // Check every 30 seconds
return () => clearInterval(interval); return () => clearInterval(interval);
}, []); }, [currentPage]);
// Fetch unread counts // Fetch unread counts
const fetchUnreadCounts = async () => { const fetchUnreadCounts = async () => {
@@ -124,7 +137,7 @@ export default function ChatTable() {
} }
}; };
// Fetch chats // Fetch chats with pagination
const fetchChats = async () => { const fetchChats = async () => {
setLoading(true); setLoading(true);
@@ -132,10 +145,23 @@ export default function ChatTable() {
// Get the vendor ID from the auth token // Get the vendor ID from the auth token
const { vendorId } = getVendorIdFromToken(); const { vendorId } = getVendorIdFromToken();
// Now fetch chats for this vendor using clientFetch // Now fetch chats for this vendor using clientFetch with pagination
const response = await clientFetch(`/chats/vendor/${vendorId}`); const response = await clientFetch(`/chats/vendor/${vendorId}?page=${currentPage}&limit=${ITEMS_PER_PAGE}`);
// Check if the response is the old format (array) or new paginated format
if (Array.isArray(response)) {
// Handle old API response format (backward compatibility)
setChats(response);
setTotalPages(1);
setTotalChats(response.length);
} else {
// Handle new paginated response format
setChats(response.chats || []);
setTotalPages(response.totalPages || 1);
setCurrentPage(response.page || 1);
setTotalChats(response.totalChats || 0);
}
setChats(Array.isArray(response) ? response : []);
await fetchUnreadCounts(); await fetchUnreadCounts();
} catch (error) { } catch (error) {
console.error("Failed to fetch chats:", error); console.error("Failed to fetch chats:", error);
@@ -156,13 +182,29 @@ export default function ChatTable() {
router.push("/dashboard/chats/new"); router.push("/dashboard/chats/new");
}; };
// Handle pagination
const goToNextPage = () => {
if (currentPage < totalPages) {
setCurrentPage(prev => prev + 1);
}
};
const goToPrevPage = () => {
if (currentPage > 1) {
setCurrentPage(prev => prev - 1);
}
};
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
onClick={fetchChats} onClick={() => {
setCurrentPage(1);
fetchChats();
}}
disabled={loading} disabled={loading}
> >
{loading ? ( {loading ? (
@@ -266,6 +308,36 @@ export default function ChatTable() {
</TableBody> </TableBody>
</Table> </Table>
</div> </div>
{/* Pagination controls */}
{!loading && chats.length > 0 && (
<div className="flex items-center justify-between">
<div className="text-sm text-muted-foreground">
Showing {chats.length} of {totalChats} chats
</div>
<div className="flex items-center space-x-2">
<Button
variant="outline"
size="sm"
onClick={goToPrevPage}
disabled={currentPage <= 1 || loading}
>
<ChevronLeft className="h-4 w-4" />
</Button>
<div className="text-sm">
Page {currentPage} of {totalPages}
</div>
<Button
variant="outline"
size="sm"
onClick={goToNextPage}
disabled={currentPage >= totalPages || loading}
>
<ChevronRight className="h-4 w-4" />
</Button>
</div>
</div>
)}
</div> </div>
); );
} }

View File

@@ -6,17 +6,10 @@
* Get the authentication token from cookies or localStorage * Get the authentication token from cookies or localStorage
*/ */
export function getAuthToken(): string | null { export function getAuthToken(): string | null {
const token = document.cookie return document.cookie
.split('; ') .split('; ')
.find(row => row.startsWith('Authorization=')) .find(row => row.startsWith('Authorization='))
?.split('=')[1] || localStorage.getItem('Authorization'); ?.split('=')[1] || localStorage.getItem('Authorization');
// If token exists but doesn't have Bearer prefix, add it
if (token && !token.startsWith('Bearer ')) {
return `Bearer ${token}`;
}
return token;
} }
/** /**
@@ -37,7 +30,7 @@ export async function logoutUser(): Promise<void> {
await fetch(`/api/auth/logout`, { await fetch(`/api/auth/logout`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Authorization': token, 'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}).catch(err => { }).catch(err => {