-
Notifications
You must be signed in to change notification settings - Fork 95
UI fixes #454
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UI fixes #454
Changes from all commits
076ee4e
6a457cd
f660875
5460d20
7b8308d
31adf9f
b6122c4
7e57ddb
156b0a8
a6599eb
f24e050
222cd45
acad424
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| 'use client'; | ||
|
|
||
| import { use, useEffect } from 'react'; | ||
| import { useRouter } from 'next/navigation'; | ||
| import { useHackathonData } from '@/lib/providers/hackathonProvider'; | ||
| import { useAuthStatus } from '@/hooks/use-auth'; | ||
| import { useSubmission } from '@/hooks/hackathon/use-submission'; | ||
| import { SubmissionFormContent } from '@/components/hackathons/submissions/SubmissionForm'; | ||
| import LoadingScreen from '@/features/projects/components/CreateProjectModal/LoadingScreen'; | ||
| import { Button } from '@/components/ui/button'; | ||
| import { ArrowLeft } from 'lucide-react'; | ||
| import { toast } from 'sonner'; | ||
|
|
||
| export default function SubmitProjectPage({ | ||
| params, | ||
| }: { | ||
| params: Promise<{ slug: string }>; | ||
| }) { | ||
| const router = useRouter(); | ||
| const { isAuthenticated, isLoading } = useAuthStatus(); | ||
|
|
||
| const resolvedParams = use(params); | ||
| const hackathonSlug = resolvedParams.slug; | ||
|
|
||
| const { | ||
| currentHackathon, | ||
| loading: hackathonLoading, | ||
| setCurrentHackathon, | ||
| } = useHackathonData(); | ||
|
|
||
| useEffect(() => { | ||
| if (hackathonSlug) { | ||
| setCurrentHackathon(hackathonSlug); | ||
| } | ||
| }, [hackathonSlug, setCurrentHackathon]); | ||
|
|
||
| const hackathonId = currentHackathon?.id || ''; | ||
| const orgId = currentHackathon?.organizationId || undefined; | ||
|
|
||
| const { | ||
| submission: mySubmission, | ||
| isFetching: isLoadingMySubmission, | ||
| fetchMySubmission, | ||
| } = useSubmission({ | ||
| hackathonSlugOrId: hackathonId || '', | ||
| autoFetch: isAuthenticated && !!hackathonId, | ||
| }); | ||
|
Comment on lines
+31
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gate this page on the requested hackathon, not just any hackathon in context.
Suggested fix const {
currentHackathon,
loading: hackathonLoading,
setCurrentHackathon,
} = useHackathonData();
+
+ const isCurrentHackathonReady =
+ currentHackathon?.slug === hackathonSlug;
const hackathonId = currentHackathon?.id || '';
const orgId = currentHackathon?.organizationId || undefined;
const {
submission: mySubmission,
isFetching: isLoadingMySubmission,
fetchMySubmission,
} = useSubmission({
hackathonSlugOrId: hackathonId || '',
- autoFetch: isAuthenticated && !!hackathonId,
+ autoFetch: isAuthenticated && isCurrentHackathonReady && !!hackathonId,
});
@@
- if (
- isLoading ||
- hackathonLoading ||
- isLoadingMySubmission ||
- !currentHackathon
- ) {
+ if (
+ isLoading ||
+ hackathonLoading ||
+ isLoadingMySubmission ||
+ !isCurrentHackathonReady
+ ) {
return <LoadingScreen />;
}Also applies to: 73-80 🤖 Prompt for AI Agents |
||
|
|
||
| // Authentication check | ||
| useEffect(() => { | ||
| if (!isLoading && !isAuthenticated) { | ||
| toast.error('You must be logged in to submit a project'); | ||
| router.push( | ||
| `/auth?mode=signin&callbackUrl=/hackathons/${hackathonSlug}/submit` | ||
| ); | ||
| } | ||
| }, [isAuthenticated, isLoading, router, hackathonSlug]); | ||
|
|
||
| const handleClose = () => { | ||
| router.push(`/hackathons/${hackathonSlug}`); | ||
| }; | ||
|
|
||
| const handleSuccess = () => { | ||
| fetchMySubmission(); | ||
| toast.success( | ||
| mySubmission | ||
| ? 'Submission updated successfully!' | ||
| : 'Project submitted successfully!' | ||
| ); | ||
| router.push(`/hackathons/${hackathonSlug}?tab=submission`); | ||
|
Comment on lines
+63
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the extra success toast.
🤖 Prompt for AI Agents |
||
| }; | ||
|
|
||
| if ( | ||
| isLoading || | ||
| hackathonLoading || | ||
| isLoadingMySubmission || | ||
| !currentHackathon | ||
| ) { | ||
| return <LoadingScreen />; | ||
| } | ||
|
|
||
| return ( | ||
| <div className='min-h-screen bg-black px-5 py-5 text-white md:px-[50px] lg:px-[100px]'> | ||
| <div className='mx-auto max-w-[1200px] pb-10'> | ||
| <Button | ||
| variant='ghost' | ||
| className='mb-6 pl-0 text-gray-400 hover:text-white' | ||
| onClick={handleClose} | ||
| > | ||
| <ArrowLeft className='mr-2 h-4 w-4' /> | ||
| Back to Hackathon | ||
| </Button> | ||
|
|
||
| <div className='min-h-[700px] overflow-hidden rounded-xl border border-gray-800 bg-gray-900/50 shadow-2xl'> | ||
| <SubmissionFormContent | ||
| hackathonSlugOrId={hackathonId} | ||
| organizationId={orgId} | ||
| submissionId={mySubmission?.id} | ||
| initialData={ | ||
| mySubmission | ||
| ? { | ||
| projectName: mySubmission.projectName, | ||
| category: mySubmission.category, | ||
| description: mySubmission.description, | ||
| logo: mySubmission.logo, | ||
| videoUrl: mySubmission.videoUrl, | ||
| introduction: mySubmission.introduction, | ||
| links: mySubmission.links, | ||
| participationType: (mySubmission as any).participationType, | ||
| } | ||
| : undefined | ||
| } | ||
| onSuccess={handleSuccess} | ||
| onClose={handleClose} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -125,6 +125,7 @@ interface SubmissionFormContentProps { | |
| initialData?: Partial<SubmissionFormDataLocal>; | ||
| submissionId?: string; | ||
| onSuccess?: () => void; | ||
| onClose?: () => void; | ||
| } | ||
|
|
||
| const INITIAL_STEPS: Step[] = [ | ||
|
|
@@ -198,8 +199,19 @@ const SubmissionFormContent: React.FC<SubmissionFormContentProps> = ({ | |
| initialData, | ||
| submissionId, | ||
| onSuccess, | ||
| onClose, | ||
| }) => { | ||
| const { collapse, isExpanded: open } = useExpandableScreen(); | ||
| // Use context carefully since it might not be available when used standalone | ||
| let collapse = () => {}; | ||
| let open = true; | ||
| try { | ||
| const expandableCtx = useExpandableScreen(); | ||
| collapse = expandableCtx.collapse; | ||
| open = expandableCtx.isExpanded; | ||
| } catch (e) { | ||
| // Standalone mode, not in ExpandableScreen | ||
| } | ||
|
Comment on lines
+204
to
+213
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: fd -t f "SubmissionForm.tsx" -o "submission" --maxdepth 5Repository: boundlessfi/boundless Length of output: 204 🏁 Script executed: find . -name "SubmissionForm.tsx" -o -name "*page.tsx" | grep -E "(submit|submission)" | head -20Repository: boundlessfi/boundless Length of output: 291 🏁 Script executed: git ls-files | grep -i submission | head -20Repository: boundlessfi/boundless Length of output: 1340 🏁 Script executed: wc -l components/hackathons/submissions/SubmissionForm.tsxRepository: boundlessfi/boundless Length of output: 122 🏁 Script executed: sed -n '200,220p' components/hackathons/submissions/SubmissionForm.tsxRepository: boundlessfi/boundless Length of output: 740 🏁 Script executed: sed -n '780,800p' components/hackathons/submissions/SubmissionForm.tsxRepository: boundlessfi/boundless Length of output: 505 🏁 Script executed: cat -n components/hackathons/submissions/SubmissionForm.tsx | head -50Repository: boundlessfi/boundless Length of output: 1571 🏁 Script executed: cat -n app/'(landing)'/hackathons/'[slug]'/submit/page.tsxRepository: boundlessfi/boundless Length of output: 4564 🏁 Script executed: grep -n "SubmissionForm\|SubmissionFormContent" app/'(landing)'/hackathons/'[slug]'/submit/page.tsx -B 5 -A 10Repository: boundlessfi/boundless Length of output: 1500 🏁 Script executed: grep -n "export\|SubmissionFormContent" components/hackathons/submissions/SubmissionForm.tsx | head -30Repository: boundlessfi/boundless Length of output: 405 🏁 Script executed: sed -n '1598,1617p' components/hackathons/submissions/SubmissionForm.tsxRepository: boundlessfi/boundless Length of output: 648 🏁 Script executed: sed -n '190,250p' components/hackathons/submissions/SubmissionForm.tsxRepository: boundlessfi/boundless Length of output: 1819 🏁 Script executed: grep -r "SubmissionScreenWrapper\|SubmissionFormContent" --include="*.tsx" --include="*.ts" | grep -v node_modules | head -20Repository: boundlessfi/boundless Length of output: 1112 🏁 Script executed: grep -n "useExpandableScreen" components/hackathons/submissions/SubmissionForm.tsxRepository: boundlessfi/boundless Length of output: 143 🏁 Script executed: cat -n biome.json 2>/dev/null || cat -n biomejs.json 2>/dev/null || echo "No Biome config found"Repository: boundlessfi/boundless Length of output: 2350 Move The try/catch around The safe solution: Since Additionally, the post-submit callback sequence at lines 788–793 calls both 🧰 Tools🪛 Biome (2.4.4)[error] 208-208: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render. (lint/correctness/useHookAtTopLevel) 🤖 Prompt for AI Agents |
||
|
|
||
| const { currentHackathon } = useHackathonData(); | ||
| const { user } = useAuthStatus(); | ||
|
|
||
|
|
@@ -773,7 +785,11 @@ const SubmissionFormContent: React.FC<SubmissionFormContentProps> = ({ | |
| } else { | ||
| await create(submissionData); | ||
| } | ||
| collapse(); | ||
| if (onClose) { | ||
| onClose(); | ||
| } else { | ||
| collapse(); | ||
| } | ||
| onSuccess?.(); | ||
|
Comment on lines
+788
to
793
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't call
Suggested fix- if (onClose) {
- onClose();
- } else {
- collapse();
- }
- onSuccess?.();
+ if (onSuccess) {
+ onSuccess();
+ } else if (onClose) {
+ onClose();
+ } else {
+ collapse();
+ }🤖 Prompt for AI Agents |
||
| } catch { | ||
| // Error handled in hook | ||
|
|
@@ -1503,22 +1519,31 @@ const SubmissionFormContent: React.FC<SubmissionFormContentProps> = ({ | |
| <Form {...form}> | ||
| <form | ||
| onSubmit={form.handleSubmit(onSubmit)} | ||
| className='flex flex-1 gap-8 overflow-y-auto px-10 py-6' | ||
| className='flex flex-1 flex-col gap-6 overflow-y-auto px-4 py-6 sm:px-10 md:flex-row md:gap-8' | ||
| > | ||
| <div className='sticky top-0 h-fit'> | ||
| <div className='mt-4 h-fit w-full md:sticky md:top-0 md:mt-0 md:w-auto'> | ||
| <Stepper steps={steps} /> | ||
| </div> | ||
| <div className='flex flex-1 flex-col space-y-6'> | ||
| <div className='flex w-full flex-1 flex-col space-y-6'> | ||
| {renderStepContent()} | ||
| <div className='mt-auto flex justify-between pt-6 pb-6'> | ||
| <Button | ||
| type='button' | ||
| variant='outline' | ||
| onClick={handleBack} | ||
| disabled={currentStep === 0} | ||
| onClick={() => { | ||
| if (currentStep > 0) { | ||
| handleBack(); | ||
| } else { | ||
| if (onClose) { | ||
| onClose(); | ||
| } else { | ||
| collapse(); | ||
| } | ||
| } | ||
| }} | ||
| className='border-gray-700 text-white hover:bg-gray-800' | ||
| > | ||
| Back | ||
| {currentStep === 0 ? 'Cancel' : 'Back'} | ||
| </Button> | ||
| {currentStep < steps.length - 1 ? ( | ||
| <Button | ||
|
|
@@ -1568,6 +1593,8 @@ const SubmissionFormContent: React.FC<SubmissionFormContentProps> = ({ | |
| ); | ||
| }; | ||
|
|
||
| export { SubmissionFormContent }; | ||
|
|
||
| interface SubmissionScreenWrapperProps extends SubmissionFormContentProps { | ||
| children: React.ReactNode; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isInitializingis cleared before the requested hackathon is actually aligned.await setCurrentHackathon(hackathonId)does not synchronize the provider state here, so the newuseSubmissionhook can still auto-fetch against whatevercurrentHackathonwas already in context. On route-to-route transitions, that makeshasSubmittedvulnerable to the previous hackathon's submission until the provider catches up.Also applies to: 322-341
🤖 Prompt for AI Agents