Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/(landing)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Metadata } from 'next';
import { ReactNode } from 'react';
import { Footer, Navbar } from '@/components/landing-page';
import { generatePageMetadata } from '@/lib/metadata';
import { GoogleOneTap } from '@/components/auth/GoogleOneTap';

// Generate metadata for the landing layout (home page)
export const metadata: Metadata = generatePageMetadata('home');
Expand All @@ -16,6 +17,7 @@ export default function LandingLayout({ children }: LandingLayoutProps) {
<Navbar />
<main className='flex-1'>{children}</main>
<Footer />
<GoogleOneTap />
</div>
);
}
148 changes: 148 additions & 0 deletions app/(landing)/notifications/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
'use client';

import { useState } from 'react';
import { useNotifications } from '@/hooks/use-notifications';
import { useNotificationPolling } from '@/hooks/use-notification-polling';
import { NotificationList } from '@/components/notifications/NotificationList';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
import { toast } from 'sonner';
import { ChevronLeft, ChevronRight } from 'lucide-react';

export default function NotificationsPage() {
const [page, setPage] = useState(1);
const limit = 20;

const notificationsHook = useNotifications({
page,
limit,
autoFetch: true,
});

const {
notifications,
loading,
error,
total,
unreadCount,
markAllAsRead,
markNotificationAsRead,
setCurrentPage,
} = notificationsHook;

// Enable polling for real-time updates
useNotificationPolling(notificationsHook, {
interval: 30000,
enabled: true,
});

const totalPages = Math.ceil(total / limit);

const handleMarkAllAsRead = async () => {
try {
await markAllAsRead();
toast.success('All notifications marked as read');
} catch {
toast.error('Failed to mark all as read');
}
};

const handlePageChange = (newPage: number) => {
setCurrentPage(newPage);
setPage(newPage);
window.scrollTo({ top: 0, behavior: 'smooth' });
};

if (error) {
return (
<div className='container mx-auto max-w-4xl p-6'>
<div className='rounded-lg border border-red-800/50 bg-red-950/20 p-8 text-center'>
<p className='text-lg font-semibold text-red-400'>
Error loading notifications
</p>
<p className='mt-2 text-sm text-zinc-400'>{error.message}</p>
<Button
onClick={() => notificationsHook.refetch()}
className='mt-4'
variant='outline'
>
Try Again
</Button>
</div>
</div>
);
}

return (
<div className='container mx-auto max-w-4xl p-6'>
<div className='mb-6 flex items-center justify-between'>
<div>
<h1 className='text-3xl font-bold text-white'>Notifications</h1>
<p className='mt-1 text-sm text-zinc-400'>
{loading ? (
<Skeleton className='h-4 w-48' />
) : (
<>
{unreadCount} unread of {total} total
</>
)}
</p>
</div>
{unreadCount > 0 && !loading && (
<Button
onClick={handleMarkAllAsRead}
variant='outline'
className='border-primary/30 text-primary hover:bg-primary/10'
>
Mark all as read
</Button>
)}
</div>

<NotificationList
notifications={notifications}
loading={loading}
onNotificationClick={notification => {
if (!notification.read) {
markNotificationAsRead([notification._id]).catch(() => {
// Silently handle error - user feedback already provided
});
}
}}
onMarkAsRead={id => {
markNotificationAsRead([id]).catch(() => {
// Silently handle error - user feedback already provided
});
}}
/>

{totalPages > 1 && !loading && (
<div className='mt-8 flex items-center justify-center gap-4'>
<Button
onClick={() => handlePageChange(page - 1)}
disabled={page === 1}
variant='outline'
size='sm'
className='border-zinc-800/50'
>
<ChevronLeft className='mr-1 h-4 w-4' />
Previous
</Button>
<span className='text-sm text-zinc-400'>
Page {page} of {totalPages}
</span>
<Button
onClick={() => handlePageChange(page + 1)}
disabled={page === totalPages}
variant='outline'
size='sm'
className='border-zinc-800/50'
>
Next
<ChevronRight className='ml-1 h-4 w-4' />
</Button>
</div>
)}
</div>
);
}
16 changes: 15 additions & 1 deletion app/(landing)/organizations/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
'use client';

import OrganizationAnalytics from '@/components/organization/OrganizationAnalytics';
import React from 'react';
import React, { useEffect } from 'react';
import { useParams } from 'next/navigation';
import { useOrganization } from '@/lib/providers/OrganizationProvider';

const OrganizationPage = () => {
const params = useParams();
const organizationId = params.id as string;
const { setActiveOrg } = useOrganization();

useEffect(() => {
if (organizationId) {
setActiveOrg(organizationId);
}
}, [organizationId, setActiveOrg]);

return (
<div className='bg-background-main-bg min-h-screen text-white'>
<OrganizationAnalytics />
Expand Down
5 changes: 3 additions & 2 deletions app/(landing)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import BeamBackground from '@/components/landing-page/BeamBackground';
import { Hero } from '@/components/landing-page';
import WhyBoundless from '@/components/landing-page/WhyBoundless';
import BackedBy from '@/components/landing-page/BackedBy';
import NewsLetter from '@/components/landing-page/NewsLetter';
import BlogSection from '@/components/landing-page/blog/BlogSection';
import Explore from '@/components/landing-page/Explore';
import CleanBanner from '@/components/landing-page/Banner';
import Hero2 from '@/components/landing-page/Hero2';

export default function LandingPage() {
return (
<div className='relative overflow-hidden'>
<BeamBackground />
<div className='relative z-10 mx-auto max-w-[1440px] space-y-[60px] px-5 py-5 md:space-y-[80px] md:px-[50px] lg:px-[100px]'>
<Hero />
{/* <Hero /> */}
<Hero2 />
<Explore />
<WhyBoundless />
<BackedBy />
Expand Down
Loading
Loading