Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4a01740
feat: implement comprehensive comment system with real-time features
0xdevcollins Dec 9, 2025
df8841c
feat: update project and profile components with new features and opt…
0xdevcollins Dec 11, 2025
0c9e03f
chore: update Next.js and related dependencies to version 16.0.10
0xdevcollins Dec 11, 2025
e08fb3c
fix: update socket connection URLs to use BETTER_AUTH_URL
0xdevcollins Dec 12, 2025
a4ebc24
feat: add CheckEmail component for email verification flow
0xdevcollins Dec 13, 2025
49ef6f8
feat: implement invitation acceptance layout and loading states
0xdevcollins Dec 14, 2025
affdd4d
refactor: standardize ID usage and improve component logic
0xdevcollins Dec 20, 2025
35df20f
feat: enhance hackathon participant management and UI
0xdevcollins Dec 23, 2025
4c448ae
feat: add console logs for debugging and update API response handling
0xdevcollins Dec 24, 2025
4d4291e
fix: update background class to use gradient for HackathonStickyCard
0xdevcollins Dec 24, 2025
4198686
feat: Refactor submission and discussion handling
0xdevcollins Dec 26, 2025
60be244
feat(metadata): Enhance SEO metadata generation and add utility funct…
0xdevcollins Dec 27, 2025
a6d8be3
feat(blog): refactor BlogCard and BlogSection components for improved…
0xdevcollins Dec 27, 2025
672d47a
feat: add hackathon participants, resources, rewards, and teams API
0xdevcollins Dec 27, 2025
6fc101e
fix: update tag handling in UploadService to use JSON.stringify for s…
0xdevcollins Dec 27, 2025
b74be6d
fix: update tag handling in UploadService to append tags individually
0xdevcollins Dec 27, 2025
4c58fd8
feat: enhance navigation in StreamingBlogGrid with transition handlin…
0xdevcollins Dec 27, 2025
00cc09f
feat: update styles and improve responsiveness across AboutUsHero, Ou…
0xdevcollins Dec 27, 2025
6d05d05
feat: Implement code changes to enhance functionality and improve per…
0xdevcollins Dec 27, 2025
14c37a4
feat: Refactor blog components and API for improved data handling and…
0xdevcollins Jan 1, 2026
f24f5e6
Update components/organization/tabs/ProfileTab.tsx
0xdevcollins Jan 1, 2026
ff80fbc
Update components/organization/hackathons/details/HackathonSidebar.tsx
0xdevcollins Jan 1, 2026
889c7c6
Update components/landing-page/blog/BlogSectionClient.tsx
0xdevcollins Jan 1, 2026
b114afe
Update components/organization/hackathons/new/NewHackathonTab.tsx
0xdevcollins Jan 1, 2026
7e5cbd9
Update components/notifications/NotificationDropdown.tsx
0xdevcollins Jan 1, 2026
ce5a834
Update components/organization/hackathons/new/NewHackathonSidebar.tsx
0xdevcollins Jan 1, 2026
7296ce5
Update components/landing-page/hackathon/HackathonCard.tsx
0xdevcollins Jan 1, 2026
52759d6
Update components/landing-page/blog/BlogCard.tsx
0xdevcollins Jan 1, 2026
01c4996
Update components/profile/update/Settings.tsx
0xdevcollins Jan 1, 2026
ca8b596
fix: Fix typo in updateNotificationsSettings function name
0xdevcollins Jan 1, 2026
7c1f912
merge: github.com:boundlessfi/boundless into nest-switch
0xdevcollins Jan 1, 2026
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
571 changes: 571 additions & 0 deletions COMMENT_SYSTEM_README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions app/(landing)/about/AboutUsHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export default function AboutUsHero() {
return (
<div
ref={heroRef}
className='relative flex h-full min-h-[95vh] items-center justify-center overflow-hidden bg-[#030303]'
className='bg-background-main-bg relative flex h-full min-h-[95vh] items-center justify-center overflow-hidden'
>
<div
className='absolute bottom-0 z-10 h-[772px] w-full'
Expand All @@ -87,7 +87,7 @@ export default function AboutUsHero() {
}}
/>
<div className='border-20px] absolute inset-0 top-1/2 left-1/2 h-[383px] w-[383px] -translate-x-1/2 -translate-y-1/2 rounded-full border-[#DBFFB7] opacity-[0.3] mix-blend-overlay blur-[25px]' />
<div className='absolute inset-0 top-1/2 left-1/2 h-[397px] w-[397px] -translate-x-1/2 -translate-y-1/2 rounded-full border-[100px] border-[#6DC01A] opacity-[0.2] mix-blend-hard-light blur-[100px]' />
<div className='absolute inset-0 top-1/2 left-1/2 h-[397px] w-[397px] -translate-x-1/2 -translate-y-1/2 rounded-full border-100 border-[#6DC01A] opacity-[0.2] mix-blend-hard-light blur-[100px]' />
<div className='absolute inset-0 top-1/2 left-1/2 h-[560px] w-[560px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-[#A7F9503D] blur-[400px]' />

<div
Expand Down
8 changes: 4 additions & 4 deletions app/(landing)/about/AboutUsHero2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function AboutUsHero() {
}, []);

return (
<div className='relative flex min-h-[100vh] flex-col justify-between overflow-hidden bg-[#030303] sm:min-h-[95vh] sm:justify-center'>
<div className='bg-background-main-bg relative flex min-h-screen flex-col justify-between overflow-hidden sm:min-h-[95vh] sm:justify-center'>
<BeamBackground />
<div
ref={contentRef}
Expand Down Expand Up @@ -60,7 +60,7 @@ export default function AboutUsHero() {
size='lg'
fullWidth
aria-label='Explore featured projects and campaigns'
className='min-h-[48px] touch-manipulation sm:min-h-[44px]'
className='min-h-12 touch-manipulation sm:min-h-11'
>
Explore Projects
</BoundlessButton>
Expand All @@ -71,15 +71,15 @@ export default function AboutUsHero() {
size='lg'
fullWidth
aria-label='Submit your project idea for funding'
className='min-h-[48px] touch-manipulation sm:min-h-[44px]'
className='min-h-12 touch-manipulation sm:min-h-11'
>
Submit Your Idea
</BoundlessButton>
</Link>
</nav>
</div>
<div className='relative right-0 bottom-20 left-0 z-0 mt-auto sm:absolute sm:bottom-0 sm:mt-0'>
<div className='absolute right-0 bottom-0 left-0 h-[120px] w-full bg-gradient-to-t from-[#030303] to-transparent opacity-80 sm:h-[100px] sm:opacity-50' />
<div className='from-background-main-bg absolute right-0 bottom-0 left-0 h-[120px] w-full bg-linear-to-t to-transparent opacity-80 sm:h-[100px] sm:opacity-50' />
<Image
src='/about-map.svg'
alt=''
Expand Down
8 changes: 4 additions & 4 deletions app/(landing)/about/OurTeam.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const OurTeam = () => {
<div className='grid grid-cols-1 gap-8 md:gap-12 lg:grid-cols-2 lg:gap-16 xl:gap-20'>
{/* Team Member 1 */}
<div className='flex w-full flex-col items-center gap-4 sm:flex-row sm:items-start md:gap-6'>
<div className='h-48 w-48 flex-shrink-0 cursor-pointer rounded-xl bg-[#D9D9D9] transition duration-300 hover:scale-105 sm:h-56 sm:w-56 md:h-60 md:w-60 lg:h-64 lg:w-64 xl:h-72 xl:w-72'></div>
<div className='h-48 w-48 shrink-0 cursor-pointer rounded-xl bg-[#D9D9D9] transition duration-300 hover:scale-105 sm:h-56 sm:w-56 md:h-60 md:w-60 lg:h-64 lg:w-64 xl:h-72 xl:w-72'></div>
<div className='w-full flex-1 text-center sm:text-left'>
<h3 className='mb-2 text-xl font-medium text-white md:text-2xl'>
Collins Ikechukwu
Expand All @@ -45,7 +45,7 @@ const OurTeam = () => {
Blockchain Developer
</p>
<hr
className='mb-4 h-[1px] w-full border-0 md:mb-6'
className='mb-4 h-px w-full border-0 md:mb-6'
style={{
background:
'radial-gradient(113.1% 103.23% at 45.52% -1.51%, rgba(255, 255, 255, 0.4704) 0%, rgba(255, 255, 255, 0.0784) 100%)',
Expand Down Expand Up @@ -95,7 +95,7 @@ const OurTeam = () => {

{/* Team Member 2 */}
<div className='flex w-full flex-col items-center gap-4 sm:flex-row sm:items-start md:gap-6'>
<div className='h-48 w-48 flex-shrink-0 cursor-pointer rounded-xl bg-[#D9D9D9] transition duration-300 hover:scale-105 sm:h-56 sm:w-56 md:h-60 md:w-60 lg:h-64 lg:w-64 xl:h-72 xl:w-72'></div>
<div className='h-48 w-48 shrink-0 cursor-pointer rounded-xl bg-[#D9D9D9] transition duration-300 hover:scale-105 sm:h-56 sm:w-56 md:h-60 md:w-60 lg:h-64 lg:w-64 xl:h-72 xl:w-72'></div>
<div className='w-full flex-1 text-center sm:text-left'>
<h3 className='mb-2 text-xl font-medium text-white md:text-2xl'>
Nnaji Benjamin
Expand All @@ -104,7 +104,7 @@ const OurTeam = () => {
Full-Stack & Blockchain Developer
</p>
<hr
className='mb-4 h-[1px] w-full border-0 md:mb-6'
className='mb-4 h-px w-full border-0 md:mb-6'
style={{
background:
'radial-gradient(113.1% 103.23% at 45.52% -1.51%, rgba(255, 255, 255, 0.4704) 0%, rgba(255, 255, 255, 0.0784) 100%)',
Expand Down
2 changes: 1 addition & 1 deletion app/(landing)/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const metadata: Metadata = generatePageMetadata('about');
const AboutPage = () => {
return (
<section>
<div className='relative z-10 mx-auto max-w-[1440px] space-y-[23px] md:space-y-[80px]'>
<div className='relative z-10 mx-auto max-w-[1440px] space-y-[23px] md:space-y-20'>
<AboutUsHero2 />
<Missionpage />
<AboutUsDifferent />
Expand Down
49 changes: 38 additions & 11 deletions app/(landing)/accept-invitation/[invitationId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ import { useEffect, useState } from 'react';
import { useParams, useRouter } from 'next/navigation';
import { authClient } from '@/lib/auth-client';
import { toast } from 'sonner';
import { Loader2, CheckCircle2, XCircle } from 'lucide-react';
import { CheckCircle2, XCircle } from 'lucide-react';
import LoadingSpinner from '@/components/LoadingSpinner';
import { BoundlessButton } from '@/components/buttons';

export default function AcceptInvitationPage() {
const params = useParams();
const router = useRouter();
const [status, setStatus] = useState<'loading' | 'success' | 'error'>(
'loading'
);
const [errorMessage, setErrorMessage] = useState<string>('');
const invitationId = params.invitationId as string;

useEffect(() => {
const acceptInvitation = async () => {
if (!invitationId) {
setStatus('error');
setErrorMessage('No invitation ID provided');
return;
}

Expand Down Expand Up @@ -54,9 +54,6 @@ export default function AcceptInvitationPage() {
throw new Error('Failed to accept invitation');
}
} catch {
setErrorMessage(
'Failed to accept invitation. It may be expired or invalid.'
);
toast.error(
'Failed to accept invitation. It may be expired or invalid.'
);
Expand All @@ -68,9 +65,38 @@ export default function AcceptInvitationPage() {
}, [invitationId, router]);

return (
<div className='flex min-h-screen items-center justify-center bg-black'>
<div className='w-full max-w-md rounded-xl border border-zinc-800 bg-zinc-900/50 p-8 text-center backdrop-blur-sm'>
{status === 'loading' && (
<div className='relative z-9999999 flex min-h-screen flex-col items-center justify-center gap-4 backdrop-blur-lg'>
{status === 'loading' && (
<>
<LoadingSpinner variant='spinner' size='xl' color='primary' />
<p className='text-sm text-white'>Accepting invitation...</p>
</>
)}
{status === 'success' && (
<>
<CheckCircle2 className='mx-auto h-12 w-12 text-green-500' />
<p className='text-sm text-white'>
Invitation accepted! Redirecting...
</p>
</>
)}
{status === 'error' && (
<>
<XCircle className='mx-auto h-12 w-12 text-red-500' />
<p className='text-sm text-white'>
Failed to accept invitation. It may be expired or invalid.
</p>
<BoundlessButton
onClick={() => router.push('/')}
size='xl'
className='bg-primary hover:bg-primary/90 text-black'
>
Go to Home
</BoundlessButton>
</>
)}
{/* <div className='w-full max-w-md rounded-xl border border-zinc-800 bg-zinc-900/50 p-8 text-center backdrop-blur-sm'> */}
{/* {status === 'loading' && (
<div className='space-y-4'>
<Loader2 className='text-primary mx-auto h-12 w-12 animate-spin' />
<h1 className='text-2xl font-semibold text-white'>
Expand All @@ -81,6 +107,7 @@ export default function AcceptInvitationPage() {
</p>
</div>
)}


{status === 'success' && (
<div className='space-y-4'>
Expand Down Expand Up @@ -110,8 +137,8 @@ export default function AcceptInvitationPage() {
Go to Organizations
</button>
</div>
)}
</div>
)} */}
{/* </div> */}
</div>
);
}
22 changes: 22 additions & 0 deletions app/(landing)/accept-invitation/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import AnimatedAuthLayout from '@/components/auth/AnimatedAuthLayout';
import { Metadata } from 'next';
import React from 'react';

export const metadata: Metadata = {
title: 'Authentication - Boundless',
description: 'Sign in or create an account to access Boundless platform',
robots: 'noindex, nofollow',
};

interface AuthLayoutProps {
children: React.ReactNode;
}

export default function AuthLayoutWrapper({ children }: AuthLayoutProps) {
return (
<div className='absolute inset-0 z-50 flex min-h-screen items-center justify-center'>
<div className='absolute z-9999999 h-screen w-screen backdrop-blur-lg' />
<AnimatedAuthLayout>{children}</AnimatedAuthLayout>
</div>
);
}
2 changes: 1 addition & 1 deletion app/(landing)/blog/[slug]/not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Button } from '@/components/ui/button';

export default function BlogNotFound() {
return (
<div className='flex min-h-[80vh] items-center justify-center bg-[#030303]'>
<div className='bg-background-main-bg flex min-h-[80vh] items-center justify-center'>
<div className='mx-auto max-w-md px-6 text-center'>
<div className='mb-8'>
<h1 className='mb-4 text-6xl font-bold text-white'>404</h1>
Expand Down
104 changes: 77 additions & 27 deletions app/(landing)/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import React from 'react';
import { Metadata } from 'next';
import { notFound } from 'next/navigation';
import BlogPostDetails from '../../../../components/landing-page/blog/BlogPostDetails';
import BlogPostDetails from '@/components/landing-page/blog/BlogPostDetails';
import { getBlogPost, getBlogPosts } from '@/lib/api/blog';
import { generateBlogPostMetadata } from '@/lib/metadata';

export async function generateStaticParams() {
interface BlogPostPageProps {
params: Promise<{ slug: string }>;
}

interface StaticParams {
slug: string;
}

const STATIC_GENERATION_LIMIT = 100;

export async function generateStaticParams(): Promise<StaticParams[]> {
try {
// For static generation, we'll need to fetch all posts
// This might need to be adjusted based on your backend implementation
const { posts } = await getBlogPosts({ page: 1, limit: 50 });
const response = await getBlogPosts({
page: 1,
limit: STATIC_GENERATION_LIMIT,
status: 'PUBLISHED',
});

const data = response.data;

if (!data || data.length === 0) {
return [];
}

return posts.map(post => ({
return data.map(post => ({
slug: post.slug,
}));
} catch {
Expand All @@ -21,48 +39,80 @@ export async function generateStaticParams() {

export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;

}: BlogPostPageProps): Promise<Metadata> {
try {
const { slug } = await params;

if (!slug || typeof slug !== 'string') {
return getDefaultMetadata();
}

const post = await getBlogPost(slug);

if (!post) {
return {
title: 'Blog Post Not Found',
description: 'The requested blog post could not be found.',
};
return getNotFoundMetadata();
}

return generateBlogPostMetadata(post);
} catch {
return {
title: 'Blog Post Not Found',
description: 'The requested blog post could not be found.',
};
return getDefaultMetadata();
}
}

const BlogPostPage = async ({
params,
}: {
params: Promise<{ slug: string }>;
}) => {
const { slug } = await params;

const BlogPostPage = async ({ params }: BlogPostPageProps) => {
try {
const { slug } = await params;

if (!slug || typeof slug !== 'string') {
notFound();
}

const post = await getBlogPost(slug);

if (!post) {
notFound();
}

if (!post.id || !post.title || !post.content) {
notFound();
}

return <BlogPostDetails post={post} />;
} catch {
} catch (error) {
if (error instanceof Error) {
if (
error.message.includes('404') ||
error.message.includes('not found')
) {
notFound();
}
}

notFound();
}
};

function getDefaultMetadata(): Metadata {
return {
title: 'Blog Post | Boundless',
description: 'Read our latest blog posts and insights.',
robots: {
index: false,
follow: true,
},
};
}

function getNotFoundMetadata(): Metadata {
return {
title: 'Blog Post Not Found | Boundless',
description:
'The requested blog post could not be found. Please check the URL or browse our other posts.',
robots: {
index: false,
follow: true,
},
};
}

export default BlogPostPage;
Loading
Loading