Skip to content

Commit 9d7dd0f

Browse files
Nest switch (#362)
* feat: implement comprehensive comment system with real-time features - Added a new README for the comment system detailing features, architecture, and usage. - Integrated socket.io for real-time comment updates and reactions. - Created hooks for managing comments, reactions, and real-time interactions. - Developed UI components for comment threads, moderation dashboard, and user interactions. - Updated project and API types to support new comment system functionalities. - Implemented validation and content filtering for comments to enhance moderation capabilities. * feat: update project and profile components with new features and optimizations - Updated project components to utilize new CrowdfundingProject type for better type safety. - Enhanced profile components with public views and improved data handling. - Introduced new hooks for managing follow statistics and user interactions. - Refactored various components to streamline data flow and improve performance. - Removed deprecated components and optimized existing ones for better maintainability. - Added new utility functions for handling user activities and project interactions. * chore: update Next.js and related dependencies to version 16.0.10 - Upgraded Next.js and its associated packages in package.json and package-lock.json to version 16.0.10 for improved features and performance. - Ensured compatibility across all relevant modules by synchronizing version updates. * fix: update socket connection URLs to use BETTER_AUTH_URL - Changed socket connection URLs in useCommentRealtime, useVoteRealtime, and useSocket hooks to utilize NEXT_PUBLIC_BETTER_AUTH_URL for improved configuration management. * feat: add CheckEmail component for email verification flow - Introduced a new CheckEmail component to inform users about the verification email sent to their address. - Updated SignupForm to redirect users to the CheckEmail page after sending the verification email. - Refactored AuthPage to streamline mode handling and state synchronization with query parameters. - Removed unused state management in SignupForm for improved clarity and performance. * feat: implement invitation acceptance layout and loading states - Added a new AuthLayoutWrapper component for the accept invitation page, providing a consistent layout with animated transitions. - Enhanced the AcceptInvitationPage component to include a loading spinner and improved user feedback during the invitation acceptance process. - Updated various organization-related components to use the new 'id' field instead of '_id' for better consistency across the application. - Refactored organization-related API calls and state management to align with the new data structure. * refactor: standardize ID usage and improve component logic - Replaced instances of '_id' with 'id' across various components and hooks for consistency. - Updated the Hackathon API and related types to reflect the new data structure. - Simplified resource handling in Hackathon components by removing unnecessary nesting. - Enhanced the organization-related components to utilize the new 'organizationId' field. - Cleaned up unused code and improved overall readability in several files. * feat: enhance hackathon participant management and UI - Introduced the HackathonParticipants component to display participant details. - Updated HackathonPage to integrate participant data and improve tab management. - Refactored participant data handling in useParticipants hook for better type safety and clarity. - Enhanced loading states and error handling in various components. - Cleaned up unused code and improved overall readability in related files. * feat: add console logs for debugging and update API response handling * fix: update background class to use gradient for HackathonStickyCard * feat: Refactor submission and discussion handling - Updated CreateSubmissionModal to include participationType and set default values. - Modified submission handling in useSubmission hook to accommodate new data structure. - Removed deprecated discussions API and related hooks, transitioning to a more streamlined comment system. - Updated CommentItem component to reflect changes in comment structure and user data. - Adjusted API calls in lib/api to align with new backend requirements for submissions and comments. - Enhanced type definitions for comments and submissions to improve type safety and clarity. - Cleaned up unused code and comments related to discussions, focusing on the new comment structure. * feat(metadata): Enhance SEO metadata generation and add utility functions - Updated default Open Graph image URLs to use absolute paths. - Introduced utility functions for generating absolute image URLs, slugs, and truncating descriptions for SEO. - Enhanced page and blog metadata generation with additional fields for Open Graph, Twitter Card, and structured data. - Added JSON-LD structured data generation for blog posts and breadcrumbs. - Updated blog post type definitions to reflect changes in metadata structure. fix(organization): Remove debug trace from OrganizationProvider - Removed console.trace statement for organization data to clean up logs. refactor(blog): Update blog post structure and request types - Changed 'content' and 'image' fields to 'description' and 'coverImage' in BlogPost interface. - Added new fields for categories and updated request types to include filtering options for blog posts. * feat(blog): refactor BlogCard and BlogSection components for improved navigation and data fetching * feat: add hackathon participants, resources, rewards, and teams API - Implemented participants API with registration, submission, and voting functionalities. - Created resources API to fetch hackathon resources. - Added rewards API for assigning ranks and managing escrow details. - Developed teams API for team recruitment posts and management. - Refactored hackathon types into core, draft, participant, judging, rewards, and team modules for better organization and maintainability. - Enhanced upload service to support multiple tags. * fix: update tag handling in UploadService to use JSON.stringify for single uploads * fix: update tag handling in UploadService to append tags individually * feat: enhance navigation in StreamingBlogGrid with transition handling and loading state * feat: update styles and improve responsiveness across AboutUsHero, OurTeam, and Blog components * feat: Implement code changes to enhance functionality and improve performance * feat: Refactor blog components and API for improved data handling and metadata generation * Update components/organization/tabs/ProfileTab.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/organization/hackathons/details/HackathonSidebar.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/landing-page/blog/BlogSectionClient.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/organization/hackathons/new/NewHackathonTab.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/notifications/NotificationDropdown.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/organization/hackathons/new/NewHackathonSidebar.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/landing-page/hackathon/HackathonCard.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/landing-page/blog/BlogCard.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/profile/update/Settings.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: Fix typo in updateNotificationsSettings function name --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 47fb664 commit 9d7dd0f

289 files changed

Lines changed: 19235 additions & 14824 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

COMMENT_SYSTEM_README.md

Lines changed: 571 additions & 0 deletions
Large diffs are not rendered by default.

app/(landing)/about/AboutUsHero.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export default function AboutUsHero() {
6666
return (
6767
<div
6868
ref={heroRef}
69-
className='relative flex h-full min-h-[95vh] items-center justify-center overflow-hidden bg-[#030303]'
69+
className='bg-background-main-bg relative flex h-full min-h-[95vh] items-center justify-center overflow-hidden'
7070
>
7171
<div
7272
className='absolute bottom-0 z-10 h-[772px] w-full'
@@ -87,7 +87,7 @@ export default function AboutUsHero() {
8787
}}
8888
/>
8989
<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]' />
90-
<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]' />
90+
<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]' />
9191
<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]' />
9292

9393
<div

app/(landing)/about/AboutUsHero2.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default function AboutUsHero() {
2323
}, []);
2424

2525
return (
26-
<div className='relative flex min-h-[100vh] flex-col justify-between overflow-hidden bg-[#030303] sm:min-h-[95vh] sm:justify-center'>
26+
<div className='bg-background-main-bg relative flex min-h-screen flex-col justify-between overflow-hidden sm:min-h-[95vh] sm:justify-center'>
2727
<BeamBackground />
2828
<div
2929
ref={contentRef}
@@ -60,7 +60,7 @@ export default function AboutUsHero() {
6060
size='lg'
6161
fullWidth
6262
aria-label='Explore featured projects and campaigns'
63-
className='min-h-[48px] touch-manipulation sm:min-h-[44px]'
63+
className='min-h-12 touch-manipulation sm:min-h-11'
6464
>
6565
Explore Projects
6666
</BoundlessButton>
@@ -71,15 +71,15 @@ export default function AboutUsHero() {
7171
size='lg'
7272
fullWidth
7373
aria-label='Submit your project idea for funding'
74-
className='min-h-[48px] touch-manipulation sm:min-h-[44px]'
74+
className='min-h-12 touch-manipulation sm:min-h-11'
7575
>
7676
Submit Your Idea
7777
</BoundlessButton>
7878
</Link>
7979
</nav>
8080
</div>
8181
<div className='relative right-0 bottom-20 left-0 z-0 mt-auto sm:absolute sm:bottom-0 sm:mt-0'>
82-
<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' />
82+
<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' />
8383
<Image
8484
src='/about-map.svg'
8585
alt=''

app/(landing)/about/OurTeam.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const OurTeam = () => {
3636
<div className='grid grid-cols-1 gap-8 md:gap-12 lg:grid-cols-2 lg:gap-16 xl:gap-20'>
3737
{/* Team Member 1 */}
3838
<div className='flex w-full flex-col items-center gap-4 sm:flex-row sm:items-start md:gap-6'>
39-
<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>
39+
<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>
4040
<div className='w-full flex-1 text-center sm:text-left'>
4141
<h3 className='mb-2 text-xl font-medium text-white md:text-2xl'>
4242
Collins Ikechukwu
@@ -45,7 +45,7 @@ const OurTeam = () => {
4545
Blockchain Developer
4646
</p>
4747
<hr
48-
className='mb-4 h-[1px] w-full border-0 md:mb-6'
48+
className='mb-4 h-px w-full border-0 md:mb-6'
4949
style={{
5050
background:
5151
'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%)',
@@ -95,7 +95,7 @@ const OurTeam = () => {
9595

9696
{/* Team Member 2 */}
9797
<div className='flex w-full flex-col items-center gap-4 sm:flex-row sm:items-start md:gap-6'>
98-
<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>
98+
<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>
9999
<div className='w-full flex-1 text-center sm:text-left'>
100100
<h3 className='mb-2 text-xl font-medium text-white md:text-2xl'>
101101
Nnaji Benjamin
@@ -104,7 +104,7 @@ const OurTeam = () => {
104104
Full-Stack & Blockchain Developer
105105
</p>
106106
<hr
107-
className='mb-4 h-[1px] w-full border-0 md:mb-6'
107+
className='mb-4 h-px w-full border-0 md:mb-6'
108108
style={{
109109
background:
110110
'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%)',

app/(landing)/about/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const metadata: Metadata = generatePageMetadata('about');
1717
const AboutPage = () => {
1818
return (
1919
<section>
20-
<div className='relative z-10 mx-auto max-w-[1440px] space-y-[23px] md:space-y-[80px]'>
20+
<div className='relative z-10 mx-auto max-w-[1440px] space-y-[23px] md:space-y-20'>
2121
<AboutUsHero2 />
2222
<Missionpage />
2323
<AboutUsDifferent />

app/(landing)/accept-invitation/[invitationId]/page.tsx

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@ import { useEffect, useState } from 'react';
44
import { useParams, useRouter } from 'next/navigation';
55
import { authClient } from '@/lib/auth-client';
66
import { toast } from 'sonner';
7-
import { Loader2, CheckCircle2, XCircle } from 'lucide-react';
7+
import { CheckCircle2, XCircle } from 'lucide-react';
8+
import LoadingSpinner from '@/components/LoadingSpinner';
9+
import { BoundlessButton } from '@/components/buttons';
810

911
export default function AcceptInvitationPage() {
1012
const params = useParams();
1113
const router = useRouter();
1214
const [status, setStatus] = useState<'loading' | 'success' | 'error'>(
1315
'loading'
1416
);
15-
const [errorMessage, setErrorMessage] = useState<string>('');
1617
const invitationId = params.invitationId as string;
1718

1819
useEffect(() => {
1920
const acceptInvitation = async () => {
2021
if (!invitationId) {
2122
setStatus('error');
22-
setErrorMessage('No invitation ID provided');
2323
return;
2424
}
2525

@@ -54,9 +54,6 @@ export default function AcceptInvitationPage() {
5454
throw new Error('Failed to accept invitation');
5555
}
5656
} catch {
57-
setErrorMessage(
58-
'Failed to accept invitation. It may be expired or invalid.'
59-
);
6057
toast.error(
6158
'Failed to accept invitation. It may be expired or invalid.'
6259
);
@@ -68,9 +65,38 @@ export default function AcceptInvitationPage() {
6865
}, [invitationId, router]);
6966

7067
return (
71-
<div className='flex min-h-screen items-center justify-center bg-black'>
72-
<div className='w-full max-w-md rounded-xl border border-zinc-800 bg-zinc-900/50 p-8 text-center backdrop-blur-sm'>
73-
{status === 'loading' && (
68+
<div className='relative z-9999999 flex min-h-screen flex-col items-center justify-center gap-4 backdrop-blur-lg'>
69+
{status === 'loading' && (
70+
<>
71+
<LoadingSpinner variant='spinner' size='xl' color='primary' />
72+
<p className='text-sm text-white'>Accepting invitation...</p>
73+
</>
74+
)}
75+
{status === 'success' && (
76+
<>
77+
<CheckCircle2 className='mx-auto h-12 w-12 text-green-500' />
78+
<p className='text-sm text-white'>
79+
Invitation accepted! Redirecting...
80+
</p>
81+
</>
82+
)}
83+
{status === 'error' && (
84+
<>
85+
<XCircle className='mx-auto h-12 w-12 text-red-500' />
86+
<p className='text-sm text-white'>
87+
Failed to accept invitation. It may be expired or invalid.
88+
</p>
89+
<BoundlessButton
90+
onClick={() => router.push('/')}
91+
size='xl'
92+
className='bg-primary hover:bg-primary/90 text-black'
93+
>
94+
Go to Home
95+
</BoundlessButton>
96+
</>
97+
)}
98+
{/* <div className='w-full max-w-md rounded-xl border border-zinc-800 bg-zinc-900/50 p-8 text-center backdrop-blur-sm'> */}
99+
{/* {status === 'loading' && (
74100
<div className='space-y-4'>
75101
<Loader2 className='text-primary mx-auto h-12 w-12 animate-spin' />
76102
<h1 className='text-2xl font-semibold text-white'>
@@ -81,6 +107,7 @@ export default function AcceptInvitationPage() {
81107
</p>
82108
</div>
83109
)}
110+
84111
85112
{status === 'success' && (
86113
<div className='space-y-4'>
@@ -110,8 +137,8 @@ export default function AcceptInvitationPage() {
110137
Go to Organizations
111138
</button>
112139
</div>
113-
)}
114-
</div>
140+
)} */}
141+
{/* </div> */}
115142
</div>
116143
);
117144
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import AnimatedAuthLayout from '@/components/auth/AnimatedAuthLayout';
2+
import { Metadata } from 'next';
3+
import React from 'react';
4+
5+
export const metadata: Metadata = {
6+
title: 'Authentication - Boundless',
7+
description: 'Sign in or create an account to access Boundless platform',
8+
robots: 'noindex, nofollow',
9+
};
10+
11+
interface AuthLayoutProps {
12+
children: React.ReactNode;
13+
}
14+
15+
export default function AuthLayoutWrapper({ children }: AuthLayoutProps) {
16+
return (
17+
<div className='absolute inset-0 z-50 flex min-h-screen items-center justify-center'>
18+
<div className='absolute z-9999999 h-screen w-screen backdrop-blur-lg' />
19+
<AnimatedAuthLayout>{children}</AnimatedAuthLayout>
20+
</div>
21+
);
22+
}

app/(landing)/blog/[slug]/not-found.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Button } from '@/components/ui/button';
44

55
export default function BlogNotFound() {
66
return (
7-
<div className='flex min-h-[80vh] items-center justify-center bg-[#030303]'>
7+
<div className='bg-background-main-bg flex min-h-[80vh] items-center justify-center'>
88
<div className='mx-auto max-w-md px-6 text-center'>
99
<div className='mb-8'>
1010
<h1 className='mb-4 text-6xl font-bold text-white'>404</h1>

app/(landing)/blog/[slug]/page.tsx

Lines changed: 77 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
import React from 'react';
22
import { Metadata } from 'next';
33
import { notFound } from 'next/navigation';
4-
import BlogPostDetails from '../../../../components/landing-page/blog/BlogPostDetails';
4+
import BlogPostDetails from '@/components/landing-page/blog/BlogPostDetails';
55
import { getBlogPost, getBlogPosts } from '@/lib/api/blog';
66
import { generateBlogPostMetadata } from '@/lib/metadata';
77

8-
export async function generateStaticParams() {
8+
interface BlogPostPageProps {
9+
params: Promise<{ slug: string }>;
10+
}
11+
12+
interface StaticParams {
13+
slug: string;
14+
}
15+
16+
const STATIC_GENERATION_LIMIT = 100;
17+
18+
export async function generateStaticParams(): Promise<StaticParams[]> {
919
try {
10-
// For static generation, we'll need to fetch all posts
11-
// This might need to be adjusted based on your backend implementation
12-
const { posts } = await getBlogPosts({ page: 1, limit: 50 });
20+
const response = await getBlogPosts({
21+
page: 1,
22+
limit: STATIC_GENERATION_LIMIT,
23+
status: 'PUBLISHED',
24+
});
25+
26+
const data = response.data;
27+
28+
if (!data || data.length === 0) {
29+
return [];
30+
}
1331

14-
return posts.map(post => ({
32+
return data.map(post => ({
1533
slug: post.slug,
1634
}));
1735
} catch {
@@ -21,48 +39,80 @@ export async function generateStaticParams() {
2139

2240
export async function generateMetadata({
2341
params,
24-
}: {
25-
params: Promise<{ slug: string }>;
26-
}): Promise<Metadata> {
27-
const { slug } = await params;
28-
42+
}: BlogPostPageProps): Promise<Metadata> {
2943
try {
44+
const { slug } = await params;
45+
46+
if (!slug || typeof slug !== 'string') {
47+
return getDefaultMetadata();
48+
}
49+
3050
const post = await getBlogPost(slug);
3151

3252
if (!post) {
33-
return {
34-
title: 'Blog Post Not Found',
35-
description: 'The requested blog post could not be found.',
36-
};
53+
return getNotFoundMetadata();
3754
}
3855

3956
return generateBlogPostMetadata(post);
4057
} catch {
41-
return {
42-
title: 'Blog Post Not Found',
43-
description: 'The requested blog post could not be found.',
44-
};
58+
return getDefaultMetadata();
4559
}
4660
}
4761

48-
const BlogPostPage = async ({
49-
params,
50-
}: {
51-
params: Promise<{ slug: string }>;
52-
}) => {
53-
const { slug } = await params;
54-
62+
const BlogPostPage = async ({ params }: BlogPostPageProps) => {
5563
try {
64+
const { slug } = await params;
65+
66+
if (!slug || typeof slug !== 'string') {
67+
notFound();
68+
}
69+
5670
const post = await getBlogPost(slug);
5771

5872
if (!post) {
5973
notFound();
6074
}
6175

76+
if (!post.id || !post.title || !post.content) {
77+
notFound();
78+
}
79+
6280
return <BlogPostDetails post={post} />;
63-
} catch {
81+
} catch (error) {
82+
if (error instanceof Error) {
83+
if (
84+
error.message.includes('404') ||
85+
error.message.includes('not found')
86+
) {
87+
notFound();
88+
}
89+
}
90+
6491
notFound();
6592
}
6693
};
6794

95+
function getDefaultMetadata(): Metadata {
96+
return {
97+
title: 'Blog Post | Boundless',
98+
description: 'Read our latest blog posts and insights.',
99+
robots: {
100+
index: false,
101+
follow: true,
102+
},
103+
};
104+
}
105+
106+
function getNotFoundMetadata(): Metadata {
107+
return {
108+
title: 'Blog Post Not Found | Boundless',
109+
description:
110+
'The requested blog post could not be found. Please check the URL or browse our other posts.',
111+
robots: {
112+
index: false,
113+
follow: true,
114+
},
115+
};
116+
}
117+
68118
export default BlogPostPage;

0 commit comments

Comments
 (0)