mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-19 05:54:06 +01:00
feat: add notification page
This commit is contained in:
parent
a756e22cc8
commit
87e7947fcd
@ -1,46 +1,114 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useQuery } from "@supabase-cache-helpers/postgrest-react-query";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { BellIcon } from "lucide-react";
|
||||
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
|
||||
import { getNotificationByUserId } from "@/lib/data/norificationQuery";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useRouter } from "next/navigation";
|
||||
import useSession from "@/lib/supabase/useSession";
|
||||
import { LegacyLoader } from "@/components/loading/LegacyLoader";
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
return new Intl.DateTimeFormat("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: true,
|
||||
}).format(date);
|
||||
};
|
||||
|
||||
export default function Notification() {
|
||||
const sampleNotifications = [
|
||||
{ id: 1, message: "New message from John Doe", time: "5 minutes ago" },
|
||||
{ id: 2, message: "Your order has been shipped", time: "2 hours ago" },
|
||||
{ id: 3, message: "Meeting reminder: Team sync at 3 PM", time: "1 day ago" },
|
||||
];
|
||||
const supabase = createSupabaseClient();
|
||||
const router = useRouter();
|
||||
const { session, loading } = useSession();
|
||||
|
||||
const [showUnreadOnly, setShowUnreadOnly] = useState(false);
|
||||
|
||||
const {
|
||||
data: notifications,
|
||||
error,
|
||||
isLoading,
|
||||
refetch,
|
||||
} = useQuery(getNotificationByUserId(supabase, session?.user.id), { enabled: !!session });
|
||||
|
||||
if (loading) {
|
||||
return <LegacyLoader />;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
return (
|
||||
<div className="container max-w-screen-xl my-5">
|
||||
<p className="text-red-600">Error fetching data. Please try again.</p>={" "}
|
||||
<Button className="mt-4" onClick={() => router.refresh()}>
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const filteredNotifications = showUnreadOnly
|
||||
? notifications?.filter((notification) => !notification.is_read)
|
||||
: notifications;
|
||||
|
||||
const markAsRead = async (id: number) => {
|
||||
const { error } = await supabase.from("notification").update({ is_read: true }).eq("id", id);
|
||||
if (!error) {
|
||||
refetch();
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) return <LegacyLoader />;
|
||||
if (error) return <p>Error loading notifications: {error.message}</p>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="ml-24 md:ml-56 mt-16 ">
|
||||
<h1 className="font-bold text-2xl md:text-3xl h-0">Notifications</h1>
|
||||
<div className="w-full mt-20">
|
||||
{/* Cards */}
|
||||
<Card className="border-slate-800 w-3/4 p-6">
|
||||
<CardContent>
|
||||
<Card>
|
||||
<CardContent>
|
||||
{sampleNotifications.map((notification) => (
|
||||
<div
|
||||
key={notification.id}
|
||||
className="flex items-center justify-between p-4 border-b border-gray-200"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<BellIcon className="w-5 h-5 text-blue-500 mr-3" />
|
||||
<div>
|
||||
<p className="text-sm font-medium">{notification.message}</p>
|
||||
<p className="text-xs text-gray-500">{notification.time}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button className="text-sm text-blue-500 hover:text-blue-600">Mark as read</button>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="container max-w-screen-xl my-4">
|
||||
<h1 className="text-3xl font-bold mb-6 border-b pb-2">Notifications</h1>
|
||||
|
||||
<div className="mb-4 flex justify-end">
|
||||
<label className="text-sm mr-2 font-medium">Show Unread Only</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showUnreadOnly}
|
||||
onChange={() => setShowUnreadOnly((prev) => !prev)}
|
||||
className="cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Card className="shadow-lg rounded-lg border border-gray-200">
|
||||
<CardContent className="p-4 space-y-4">
|
||||
{filteredNotifications?.map((notification) => (
|
||||
<div
|
||||
key={notification.id}
|
||||
className={`flex items-center justify-between p-4 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-150 border ${
|
||||
notification.is_read ? "bg-gray-100 text-gray-400" : "bg-white text-gray-800"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<BellIcon className={`w-5 h-5 mr-3 ${notification.is_read ? "text-gray-400" : "text-blue-500"}`} />
|
||||
<div>
|
||||
<p className="text-sm font-medium">{notification.message}</p>
|
||||
<p className="text-xs text-gray-500">{formatDate(notification.created_at)}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!notification.is_read && (
|
||||
<button
|
||||
onClick={() => markAsRead(notification.id)}
|
||||
className="text-xs text-blue-500 hover:text-blue-600 transition duration-150"
|
||||
>
|
||||
Mark as read
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
41
src/lib/data/norificationQuery.ts
Normal file
41
src/lib/data/norificationQuery.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { SupabaseClient } from "@supabase/supabase-js";
|
||||
|
||||
interface NotificationData {
|
||||
count: number;
|
||||
status: number;
|
||||
statusText: string;
|
||||
}
|
||||
|
||||
export async function getUnreadNotificationCountByUserId(client: SupabaseClient, userId: string) {
|
||||
const { data, error } = await client
|
||||
.from("notification")
|
||||
.select("*", { count: "exact", head: true })
|
||||
.eq("receiver_id", userId)
|
||||
.eq("is_read", false);
|
||||
|
||||
if (error) {
|
||||
return { data: null, error: error };
|
||||
}
|
||||
|
||||
if (data === null) {
|
||||
return { data: null, error: error };
|
||||
} else {
|
||||
const notiData = data as unknown as NotificationData;
|
||||
return { data: notiData, error: error };
|
||||
}
|
||||
}
|
||||
|
||||
export function getNotificationByUserId(client: SupabaseClient, userId: string | undefined) {
|
||||
return client
|
||||
.from("notification")
|
||||
.select(
|
||||
`
|
||||
id,
|
||||
receiver_id,
|
||||
message,
|
||||
created_at,
|
||||
is_read
|
||||
`
|
||||
)
|
||||
.eq("receiver_id", userId);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user