Skip to content

Commit edbfe1a

Browse files
committed
feat: updated the org
1 parent df10310 commit edbfe1a

9 files changed

Lines changed: 254 additions & 46 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import OrganizationAnalytics from '@/components/organization/OrganizationAnalytics';
2+
import React from 'react';
3+
4+
const OrganizationPage = () => {
5+
return (
6+
<div className='bg-background-main-bg min-h-screen text-white'>
7+
<OrganizationAnalytics />
8+
</div>
9+
);
10+
};
11+
12+
export default OrganizationPage;

app/(landing)/organizations/layout.tsx

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@ import type React from 'react';
55
import OrganizationHeader from '@/components/organization/OrganizationHeader';
66
import OrganizationSidebar from '@/components/organization/OrganizationSidebar';
77
import { usePathname } from 'next/navigation';
8-
import { OrganizationProvider } from '@/lib/providers';
8+
import {
9+
OrganizationProvider,
10+
NavigationLoadingProvider,
11+
useNavigationLoading,
12+
} from '@/lib/providers';
913
import NewHackathonSidebar from '@/components/organization/hackathons/new/NewHackathonSidebar';
1014
import HackathonSidebar from '@/components/organization/hackathons/details/HackathonSidebar';
15+
import HackathonNavigationLoader from '@/components/organization/hackathons/details/HackathonNavigationLoader';
1116
export default function OrganizationsLayout({
1217
children,
1318
}: {
@@ -39,26 +44,59 @@ export default function OrganizationsLayout({
3944

4045
return (
4146
<OrganizationProvider initialOrgId={initialOrgId || undefined}>
42-
<div className='bg-background-main-bg relative min-h-screen text-white'>
43-
<OrganizationHeader />
44-
{showOrganizationSidebar ? (
45-
<div className='relative border-t border-t-zinc-800'>
46-
{showOrganizationSidebar &&
47-
!showNewHackathonSidebar &&
48-
!showNewGrantSidebar &&
49-
!showHackathonSidebar && <OrganizationSidebar />}
50-
{showNewHackathonSidebar && <NewHackathonSidebar />}
51-
{showHackathonSidebar && (
52-
<HackathonSidebar organizationId={initialOrgId || undefined} />
53-
)}
54-
{/* {showNewGrantSidebar && <NewGrantSidebar />} */}
55-
56-
<main className='md:ml-[350px]'>{children}</main>
57-
</div>
58-
) : (
59-
<main>{children}</main>
60-
)}
61-
</div>
47+
<NavigationLoadingProvider>
48+
<OrganizationsLayoutContent
49+
showOrganizationSidebar={showOrganizationSidebar}
50+
showNewHackathonSidebar={showNewHackathonSidebar}
51+
showNewGrantSidebar={showNewGrantSidebar}
52+
showHackathonSidebar={showHackathonSidebar}
53+
initialOrgId={initialOrgId}
54+
>
55+
{children}
56+
</OrganizationsLayoutContent>
57+
</NavigationLoadingProvider>
6258
</OrganizationProvider>
6359
);
6460
}
61+
62+
function OrganizationsLayoutContent({
63+
children,
64+
showOrganizationSidebar,
65+
showNewHackathonSidebar,
66+
showNewGrantSidebar,
67+
showHackathonSidebar,
68+
initialOrgId,
69+
}: {
70+
children: React.ReactNode;
71+
showOrganizationSidebar: boolean;
72+
showNewHackathonSidebar: boolean;
73+
showNewGrantSidebar: boolean;
74+
showHackathonSidebar: boolean;
75+
initialOrgId: string | null;
76+
}) {
77+
const { isNavigating } = useNavigationLoading();
78+
79+
return (
80+
<div className='bg-background-main-bg relative min-h-screen text-white'>
81+
{isNavigating && <HackathonNavigationLoader />}
82+
<OrganizationHeader />
83+
{showOrganizationSidebar ? (
84+
<div className='relative border-t border-t-zinc-800'>
85+
{showOrganizationSidebar &&
86+
!showNewHackathonSidebar &&
87+
!showNewGrantSidebar &&
88+
!showHackathonSidebar && <OrganizationSidebar />}
89+
{showNewHackathonSidebar && <NewHackathonSidebar />}
90+
{showHackathonSidebar && (
91+
<HackathonSidebar organizationId={initialOrgId || undefined} />
92+
)}
93+
{/* {showNewGrantSidebar && <NewGrantSidebar />} */}
94+
95+
<main className='md:ml-[350px]'>{children}</main>
96+
</div>
97+
) : (
98+
<main>{children}</main>
99+
)}
100+
</div>
101+
);
102+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
3+
const OrganizationAnalytics = () => {
4+
return (
5+
<div className='bg-background-main-bg text-white'>
6+
<div className='flex flex-col gap-4'>
7+
<h1 className='text-2xl font-bold'>Analytics</h1>
8+
<div className='flex flex-col gap-4'>
9+
<div className='flex flex-col gap-2'>
10+
<h2 className='text-lg font-bold'>Total Participants</h2>
11+
<p className='text-sm text-gray-400'>1,234</p>
12+
</div>
13+
</div>
14+
<div className='flex flex-col gap-4'>
15+
<div className='flex flex-col gap-2'>
16+
<h2 className='text-lg font-bold'>Total Participants</h2>
17+
<p className='text-sm text-gray-400'>1,234</p>
18+
</div>
19+
</div>
20+
</div>
21+
</div>
22+
);
23+
};
24+
25+
export default OrganizationAnalytics;

components/organization/cards/OrganizationSelector.tsx

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from '@/components/ui/dropdown-menu';
1313
import { Button } from '@/components/ui/button';
1414
import { OrganizationSummary } from '@/lib/providers/organization-types';
15+
import { useNavigationLoading } from '@/lib/providers';
1516

1617
interface OrganizationSelectorProps {
1718
organizations?: OrganizationSummary[];
@@ -28,6 +29,7 @@ export default function OrganizationSelector({
2829
}: OrganizationSelectorProps) {
2930
const router = useRouter();
3031
const pathname = usePathname();
32+
const { setIsNavigating } = useNavigationLoading();
3133
const [selectedOrg, setSelectedOrg] = useState<OrganizationSummary | null>(
3234
currentOrganization || organizations[0] || null
3335
);
@@ -61,32 +63,14 @@ export default function OrganizationSelector({
6163
setIsOpen(false);
6264
onToggle?.(false);
6365

64-
const currentPath = pathname;
65-
const orgId = org._id;
66-
6766
// Don't navigate if we're on the /organizations/new page
68-
if (currentPath === '/organizations/new') {
67+
if (pathname === '/organizations/new') {
6968
return;
7069
}
7170

72-
if (currentPath.startsWith('/organizations/')) {
73-
const pathSegments = currentPath.split('/').filter(Boolean);
74-
75-
// Check if second segment is an org ID (MongoDB ObjectId pattern or UUID)
76-
if (pathSegments[1] && pathSegments[1].match(/^[a-f0-9]{24}$/i)) {
77-
// Replace the org ID in the path
78-
const pathAfterOrgId = pathSegments.slice(2).join('/');
79-
const newPath = pathAfterOrgId
80-
? `/organizations/${orgId}/${pathAfterOrgId}`
81-
: `/organizations/${orgId}`;
82-
router.push(newPath);
83-
} else {
84-
// If no org ID in path, just navigate to the org
85-
router.push(`/organizations/${orgId}`);
86-
}
87-
} else if (currentPath === '/organizations') {
88-
router.push(`/organizations/${orgId}`);
89-
}
71+
// Always navigate to the root organization page
72+
setIsNavigating(true);
73+
router.push(`/organizations/${org._id}`);
9074
};
9175

9276
const handleOpenChange = (open: boolean) => {
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
'use client';
2+
3+
import { motion } from 'framer-motion';
4+
import { cn } from '@/lib/utils';
5+
6+
interface HackathonNavigationLoaderProps {
7+
className?: string;
8+
}
9+
10+
const HackathonNavigationLoader = ({
11+
className,
12+
}: HackathonNavigationLoaderProps) => {
13+
return (
14+
<div
15+
className={cn(
16+
'fixed inset-0 z-[999998] flex items-center justify-center',
17+
'bg-[rgba(28,28,28,0.52)] backdrop-blur-[50px]',
18+
className
19+
)}
20+
>
21+
<div className='absolute inset-0 overflow-hidden'>
22+
<div className='absolute top-0 right-0 h-96 w-96 rounded-full bg-green-500/5 blur-3xl' />
23+
<div className='absolute bottom-0 left-0 h-80 w-80 rounded-full bg-green-400/5 blur-3xl' />
24+
<div className='absolute right-1/3 bottom-1/3 h-64 w-64 rounded-full bg-green-600/5 blur-3xl' />
25+
</div>
26+
27+
<div className='relative z-10 flex flex-col items-center'>
28+
<div className='relative mb-4 flex h-10 items-center space-x-2 sm:mb-6 sm:h-12 sm:space-x-3'>
29+
<motion.div
30+
className='h-2 w-2 rounded-full sm:h-2.5 sm:w-2.5'
31+
animate={{
32+
height: ['8px', '32px', '8px', '40px', '8px'],
33+
backgroundColor: [
34+
'rgba(167, 249, 80, 0.08)',
35+
'#a7f950',
36+
'rgba(167, 249, 80, 0.08)',
37+
],
38+
alignSelf: ['center', 'end', 'center', 'end', 'center'],
39+
}}
40+
transition={{
41+
duration: 2.5,
42+
repeat: Infinity,
43+
ease: 'easeInOut',
44+
delay: 0,
45+
}}
46+
/>
47+
48+
<motion.div
49+
className='h-2 w-2 rounded-full sm:h-2.5 sm:w-2.5'
50+
animate={{
51+
height: ['8px', '32px', '8px', '40px', '8px'],
52+
backgroundColor: [
53+
'rgba(167, 249, 80, 0.08)',
54+
'#a7f950',
55+
'rgba(167, 249, 80, 0.08)',
56+
],
57+
alignSelf: ['center', 'end', 'center', 'end', 'center'],
58+
}}
59+
transition={{
60+
duration: 2.5,
61+
repeat: Infinity,
62+
ease: 'easeInOut',
63+
delay: 1.0,
64+
}}
65+
/>
66+
67+
<motion.div
68+
className='h-2 w-2 rounded-full sm:h-2.5 sm:w-2.5'
69+
animate={{
70+
height: ['8px', '32px', '8px', '40px', '8px'],
71+
backgroundColor: [
72+
'rgba(167, 249, 80, 0.08)',
73+
'#a7f950',
74+
'rgba(167, 249, 80, 0.08)',
75+
],
76+
alignSelf: ['center', 'end', 'center', 'end', 'center'],
77+
}}
78+
transition={{
79+
duration: 2.5,
80+
repeat: Infinity,
81+
ease: 'easeInOut',
82+
delay: 2.0,
83+
}}
84+
/>
85+
</div>
86+
87+
<motion.h2
88+
className='px-4 text-center text-base font-normal tracking-wide text-white sm:text-lg'
89+
initial={{ opacity: 0, y: 10 }}
90+
animate={{ opacity: 1, y: 0 }}
91+
transition={{ delay: 0.2, duration: 0.5 }}
92+
>
93+
Loading...
94+
</motion.h2>
95+
</div>
96+
</div>
97+
);
98+
};
99+
100+
export default HackathonNavigationLoader;

components/organization/hackathons/details/HackathonSelector.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
DropdownMenuTrigger,
1111
} from '@/components/ui/dropdown-menu';
1212
import { Button } from '@/components/ui/button';
13+
import { useNavigationLoading } from '@/lib/providers';
1314

1415
interface Hackathon {
1516
id: string;
@@ -32,6 +33,7 @@ export default function HackathonSelector({
3233
onToggle,
3334
}: HackathonSelectorProps) {
3435
const router = useRouter();
36+
const { setIsNavigating } = useNavigationLoading();
3537
const [selectedHackathon, setSelectedHackathon] = useState<Hackathon | null>(
3638
currentHackathon || hackathons[0] || null
3739
);
@@ -66,6 +68,7 @@ export default function HackathonSelector({
6668
onToggle?.(false);
6769

6870
if (hackathon.href && hackathon.href !== '#') {
71+
setIsNavigating(true);
6972
router.push(hackathon.href);
7073
}
7174
};

components/organization/hackathons/details/HackathonSidebar.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,7 @@ export default function HackathonSidebar({
9494
// The information field might be null/undefined, or title might be empty
9595
let title = 'Untitled Hackathon';
9696

97-
if (hackathon.information) {
98-
title = hackathon.information.title || title;
99-
}
97+
title = hackathon.title || title;
10098

10199
// Fallback: if information doesn't exist, keep default title
102100
// Note: Hackathon type requires information field, but we handle edge cases
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use client';
2+
3+
import React, { createContext, useContext, useState, useEffect } from 'react';
4+
import { usePathname } from 'next/navigation';
5+
6+
interface NavigationLoadingContextValue {
7+
isNavigating: boolean;
8+
setIsNavigating: (value: boolean) => void;
9+
}
10+
11+
const NavigationLoadingContext = createContext<
12+
NavigationLoadingContextValue | undefined
13+
>(undefined);
14+
15+
export const NavigationLoadingProvider: React.FC<{
16+
children: React.ReactNode;
17+
}> = ({ children }) => {
18+
const [isNavigating, setIsNavigating] = useState(false);
19+
const pathname = usePathname();
20+
21+
// Clear loading state when pathname changes (navigation completes)
22+
useEffect(() => {
23+
setIsNavigating(false);
24+
}, [pathname]);
25+
26+
return (
27+
<NavigationLoadingContext.Provider
28+
value={{ isNavigating, setIsNavigating }}
29+
>
30+
{children}
31+
</NavigationLoadingContext.Provider>
32+
);
33+
};
34+
35+
export const useNavigationLoading = (): NavigationLoadingContextValue => {
36+
const context = useContext(NavigationLoadingContext);
37+
if (!context) {
38+
throw new Error(
39+
'useNavigationLoading must be used within NavigationLoadingProvider'
40+
);
41+
}
42+
return context;
43+
};

lib/providers/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ export {
44
OrganizationContext,
55
} from './OrganizationProvider';
66

7+
export {
8+
NavigationLoadingProvider,
9+
useNavigationLoading,
10+
} from './NavigationLoadingProvider';
11+
712
export {
813
TrustlessWorkProvider,
914
useTrustlessWorkConfig,

0 commit comments

Comments
 (0)