Skip to content

Commit b9d770d

Browse files
authored
UI fixes (#458)
* fix: improve timeline input , ui improvement and fixes for participation tab * fix: implement 2fa for email and password login * fix: fix conflict * fix: fix submission form * fix: fix hackathon submission and participant page * fix: fix hackathon submission and participant page * fix: fix auto refresh ib submission page * fix: hackathon submission fixes * fix: fix coderabbit corrections * fix: fix coderabbit corrections * chore: write boundless on x challenge blog * fix: remove blog
1 parent 098b3c3 commit b9d770d

16 files changed

Lines changed: 279 additions & 112 deletions

File tree

app/(landing)/hackathons/[slug]/submit/page.tsx

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { use, useEffect } from 'react';
3+
import { use, useEffect, useState } from 'react';
44
import { useRouter } from 'next/navigation';
55
import { useHackathonData } from '@/lib/providers/hackathonProvider';
66
import { useAuthStatus } from '@/hooks/use-auth';
@@ -70,15 +70,34 @@ export default function SubmitProjectPage({
7070
router.push(`/hackathons/${hackathonSlug}?tab=submission`);
7171
};
7272

73-
if (
74-
isLoading ||
75-
hackathonLoading ||
76-
isLoadingMySubmission ||
77-
!currentHackathon
78-
) {
73+
const [hasInitialLoaded, setHasInitialLoaded] = useState(false);
74+
75+
useEffect(() => {
76+
if (!isLoading && !hackathonLoading && !isLoadingMySubmission) {
77+
setHasInitialLoaded(true);
78+
}
79+
}, [isLoading, hackathonLoading, isLoadingMySubmission]);
80+
81+
if (!hasInitialLoaded) {
7982
return <LoadingScreen />;
8083
}
8184

85+
if (!currentHackathon) {
86+
return (
87+
<div className='flex min-h-screen flex-col items-center justify-center bg-black px-5 py-5 text-white'>
88+
<h1 className='mb-4 text-2xl font-bold'>Hackathon Not Found</h1>
89+
<Button
90+
onClick={handleClose}
91+
variant='ghost'
92+
className='text-gray-400 hover:text-white'
93+
>
94+
<ArrowLeft className='mr-2 h-4 w-4' />
95+
Go Back
96+
</Button>
97+
</div>
98+
);
99+
}
100+
82101
return (
83102
<div className='min-h-screen bg-black px-5 py-5 text-white md:px-[50px] lg:px-[100px]'>
84103
<div className='mx-auto max-w-[1200px] pb-10'>
@@ -107,6 +126,8 @@ export default function SubmitProjectPage({
107126
introduction: mySubmission.introduction,
108127
links: mySubmission.links,
109128
participationType: (mySubmission as any).participationType,
129+
teamName: (mySubmission as any).teamName,
130+
teamMembers: (mySubmission as any).teamMembers,
110131
}
111132
: undefined
112133
}

app/me/projects/page.tsx

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -102,32 +102,36 @@ export default function MyProjectsPage() {
102102
</Card>
103103
) : (
104104
<div className='grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3'>
105-
{sortedProjects.map(project => (
106-
<ProjectCard
107-
isFullWidth
108-
key={project.id}
109-
data={
110-
{
111-
id: project.id,
112-
slug: project.id,
105+
{sortedProjects.map(project => {
106+
// Find if this project is a hackathon submission
107+
const submission =
108+
meData.user.hackathonSubmissionsAsParticipant?.find(
109+
s => s.projectId === project.id
110+
);
111+
112+
// If it's a submission, use the submission ID for the slug to ensure correct redirection from ProjectCard
113+
const displayId = submission?.id || project.id;
114+
115+
return (
116+
<ProjectCard
117+
isFullWidth
118+
key={project.id}
119+
data={{
120+
id: displayId,
121+
slug: displayId,
113122
project: {
114123
...project,
115124
creator: {
116125
name: authUser?.name || 'You',
117126
image: authUser?.image || '/user.png',
118127
},
119128
},
120-
fundingGoal: 0,
121-
fundingRaised: 0,
122-
fundingCurrency: 'USDC',
123-
fundingEndDate: null,
124-
milestones: [],
125-
voteGoal: 0,
126-
voteProgress: 0,
127-
} as any
128-
}
129-
/>
130-
))}
129+
isSubmission: !!submission,
130+
submissionStatus: submission?.status,
131+
}}
132+
/>
133+
);
134+
})}
131135
</div>
132136
)}
133137
</div>

components/hackathons/submissions/SubmissionForm.tsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
ExpandableScreenContent,
3535
ExpandableScreenTrigger,
3636
useExpandableScreen,
37+
useOptionalExpandableScreen,
3738
} from '@/components/ui/expandable-screen';
3839
import Stepper from '@/components/stepper/Stepper';
3940
import { uploadService } from '@/lib/api/upload';
@@ -201,16 +202,9 @@ const SubmissionFormContent: React.FC<SubmissionFormContentProps> = ({
201202
onSuccess,
202203
onClose,
203204
}) => {
204-
// Use context carefully since it might not be available when used standalone
205-
let collapse = () => {};
206-
let open = true;
207-
try {
208-
const expandableCtx = useExpandableScreen();
209-
collapse = expandableCtx.collapse;
210-
open = expandableCtx.isExpanded;
211-
} catch (e) {
212-
// Standalone mode, not in ExpandableScreen
213-
}
205+
const expandableCtx = useOptionalExpandableScreen();
206+
const collapse = expandableCtx?.collapse ?? (() => {});
207+
const open = expandableCtx?.isExpanded ?? true;
214208

215209
const { currentHackathon } = useHackathonData();
216210
const { user } = useAuthStatus();
@@ -416,7 +410,7 @@ const SubmissionFormContent: React.FC<SubmissionFormContentProps> = ({
416410
description:
417411
'An intelligent task management application that uses machine learning to prioritize tasks...',
418412
logo: '',
419-
videoUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
413+
videoUrl: 'https://youtu.be/rOSZhhblE_8?si=Hf_YvPTMmyWTUOKQ',
420414
introduction: 'This project leverages advanced AI algorithms...',
421415
links: [
422416
{ type: 'github', url: 'https://github.com/example/ai-task-manager' },
@@ -785,12 +779,14 @@ const SubmissionFormContent: React.FC<SubmissionFormContentProps> = ({
785779
} else {
786780
await create(submissionData);
787781
}
788-
if (onClose) {
782+
783+
if (onSuccess) {
784+
onSuccess();
785+
} else if (onClose) {
789786
onClose();
790787
} else {
791788
collapse();
792789
}
793-
onSuccess?.();
794790
} catch {
795791
// Error handled in hook
796792
}

components/hackathons/submissions/submissionCard.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ const SubmissionCard = ({
127127
return formatDistanceToNow(new Date(dateString), { addSuffix: true });
128128
};
129129

130+
const handleEditSelect = (e: Event) => {
131+
e.stopPropagation();
132+
onEditClick?.();
133+
};
134+
135+
const handleDeleteSelect = (e: Event) => {
136+
e.stopPropagation();
137+
onDeleteClick?.();
138+
};
139+
130140
return (
131141
<div
132142
onClick={onViewClick}
@@ -171,6 +181,7 @@ const SubmissionCard = ({
171181
<Button
172182
variant='ghost'
173183
size='sm'
184+
aria-label='More options'
174185
className='h-8 w-8 p-0 text-gray-400 hover:text-white'
175186
>
176187
<MoreHorizontal className='h-4 w-4' />
@@ -181,14 +192,14 @@ const SubmissionCard = ({
181192
className='border-gray-800 bg-black text-white'
182193
>
183194
<DropdownMenuItem
184-
onSelect={() => onEditClick?.()}
195+
onSelect={handleEditSelect}
185196
className='cursor-pointer text-gray-300 focus:bg-gray-800 focus:text-white'
186197
>
187198
<Edit className='mr-2 h-4 w-4' />
188199
Edit Submission
189200
</DropdownMenuItem>
190201
<DropdownMenuItem
191-
onSelect={() => onDeleteClick?.()}
202+
onSelect={handleDeleteSelect}
192203
className='cursor-pointer text-red-500 focus:bg-red-900/20 focus:text-red-400'
193204
>
194205
<Trash className='mr-2 h-4 w-4' />

components/hackathons/submissions/submissionTab.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ const SubmissionTabContent: React.FC<SubmissionTabContentProps> = ({
8383
setSelectedSort,
8484
setSelectedCategory,
8585
} = useSubmissions();
86+
8687
const { currentHackathon, loading: isHackathonDataLoading } =
8788
useHackathonData();
8889
const { status } = useHackathonStatus(
@@ -276,6 +277,7 @@ const SubmissionTabContent: React.FC<SubmissionTabContentProps> = ({
276277

277278
{/* Submissions Grid with Create Button if no submission */}
278279
{!isLoadingMySubmission &&
280+
!isHackathonDataLoading &&
279281
!mySubmission &&
280282
isAuthenticated &&
281283
isRegistered &&

components/organization/hackathons/settings/GeneralSettingsTab.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ interface GeneralSettingsTabProps {
5555
isPublished?: boolean;
5656
}
5757

58+
import TurndownService from 'turndown';
59+
5860
export default function GeneralSettingsTab({
5961
organizationId,
6062
hackathonId,
@@ -78,14 +80,32 @@ export default function GeneralSettingsTab({
7880
address: string;
7981
} | null>(null);
8082

83+
// Normalize HTML to Markdown for existing descriptions
84+
const normalizedDescription = React.useMemo(() => {
85+
let desc = initialData?.description || '';
86+
if (desc && /<[a-z][\\s\\S]*>/i.test(desc)) {
87+
try {
88+
const turndownService = new TurndownService({
89+
headingStyle: 'atx',
90+
codeBlockStyle: 'fenced',
91+
bulletListMarker: '-',
92+
});
93+
desc = turndownService.turndown(desc);
94+
} catch (err) {
95+
console.error('Failed to convert HTML to Markdown', err);
96+
}
97+
}
98+
return desc;
99+
}, [initialData?.description]);
100+
81101
const form = useForm<InfoFormData>({
82102
resolver: zodResolver(infoSchema),
83103
defaultValues: {
84104
name: initialData?.name || '',
85105
tagline: initialData?.tagline || '',
86106
slug: initialData?.slug || '',
87107
banner: initialData?.banner || '',
88-
description: initialData?.description || '',
108+
description: normalizedDescription,
89109
categories: Array.isArray(initialData?.categories)
90110
? initialData.categories
91111
: [],

components/profile/ProjectsTab.tsx

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -100,38 +100,47 @@ export default function ProjectsTab({ user }: ProjectsTabProps) {
100100
onScrollCapture={handleScroll}
101101
>
102102
<div className='grid gap-4 pr-4 md:grid-cols-2 lg:grid-cols-1 2xl:grid-cols-2'>
103-
{projects.map(project => (
104-
<Link
105-
key={project.id}
106-
href={`/projects/${project.id}`}
107-
target='_blank'
108-
>
109-
<ProjectCard
110-
newTab={true}
111-
isFullWidth={true}
112-
data={
113-
{
114-
id: project.id,
115-
slug: project.id,
103+
{projects.map(project => {
104+
// Find if this project is a hackathon submission
105+
// We need to check if the user object has submissions
106+
const submission =
107+
user.user.hackathonSubmissionsAsParticipant?.find(
108+
s => s.projectId === project.id
109+
);
110+
111+
// If it's a submission, use the submission ID for the URL and add ?type=submission
112+
const displayId = submission?.id || project.id;
113+
const href = submission
114+
? `/projects/${displayId}?type=submission`
115+
: `/projects/${displayId}`;
116+
117+
return (
118+
<Link
119+
key={project.id}
120+
href={href}
121+
target='_blank'
122+
rel='noopener noreferrer'
123+
>
124+
<ProjectCard
125+
newTab={true}
126+
isFullWidth={true}
127+
data={{
128+
id: displayId,
129+
slug: displayId,
116130
project: {
117131
...project,
118132
creator: {
119133
name: user.user.name || 'User',
120134
image: user.user.image || '/avatar.png',
121135
},
122-
} as any,
123-
fundingGoal: 0,
124-
fundingRaised: 0,
125-
fundingCurrency: 'USDC',
126-
fundingEndDate: null,
127-
milestones: [],
128-
voteGoal: 0,
129-
voteProgress: 0,
130-
} as any
131-
}
132-
/>
133-
</Link>
134-
))}
136+
},
137+
isSubmission: !!submission,
138+
submissionStatus: submission?.status,
139+
}}
140+
/>
141+
</Link>
142+
);
143+
})}
135144

136145
{!hasMore && projects.length > 0 && (
137146
<div className='col-span-full py-4 text-center'>

0 commit comments

Comments
 (0)