From d7e81bd13a871930023c43bc514c71d05d802ef5 Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Fri, 16 Aug 2024 12:40:29 +0100 Subject: [PATCH] Submission requirement modalg --- src/components/Projects/StartProjectModal.tsx | 7 --- .../Projects/StatusStepper/ProjectStepper.tsx | 32 +++++++++- .../Projects/SubmissionRequirement.tsx | 31 ++++++++++ .../Projects/SubmitProjectModal.tsx | 60 +++++++++++++++---- 4 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 src/components/Projects/SubmissionRequirement.tsx diff --git a/src/components/Projects/StartProjectModal.tsx b/src/components/Projects/StartProjectModal.tsx index ec5630cd0..97a592af7 100644 --- a/src/components/Projects/StartProjectModal.tsx +++ b/src/components/Projects/StartProjectModal.tsx @@ -38,13 +38,6 @@ export function StartProjectModal(props: StartProjectModalProps) { const projectUrl = `${import.meta.env.PUBLIC_APP_URL}/projects/${projectId}`; - const projectTips = [ - 'Create a repository on GitHub', - 'Complete the task and push it to GitHub', - 'Add a readme file with instructions on how to run the project', - 'Submit your project once you are done to get feedback from the community', - ]; - const formattedStartedAt = startedAt ? getRelativeTimeString(startedAt) : ''; async function handleStartProject() { diff --git a/src/components/Projects/StatusStepper/ProjectStepper.tsx b/src/components/Projects/StatusStepper/ProjectStepper.tsx index 130b8fa64..ab9271a70 100644 --- a/src/components/Projects/StatusStepper/ProjectStepper.tsx +++ b/src/components/Projects/StatusStepper/ProjectStepper.tsx @@ -5,12 +5,12 @@ import { useStickyStuck } from '../../../hooks/use-sticky-stuck.tsx'; import { StepperAction } from './StepperAction.tsx'; import { StepperStepSeparator } from './StepperStepSeparator.tsx'; import { MilestoneStep } from './MilestoneStep.tsx'; -import { httpGet, httpPost } from '../../../lib/http.ts'; +import { httpGet } from '../../../lib/http.ts'; import { StartProjectModal } from '../StartProjectModal.tsx'; -import { pageProgressMessage } from '../../../stores/page.ts'; import { getRelativeTimeString } from '../../../lib/date.ts'; import { isLoggedIn } from '../../../lib/jwt.ts'; import { showLoginPopup } from '../../../lib/popup.ts'; +import { SubmitProjectModal } from '../SubmitProjectModal.tsx'; type ProjectStatusResponse = { id?: string; @@ -34,6 +34,8 @@ export function ProjectStepper(props: ProjectStepperProps) { const isSticky = useStickyStuck(stickyElRef, 8); const [isStartingProject, setIsStartingProject] = useState(false); + const [isSubmittingProject, setIsSubmittingProject] = useState(false); + const [error, setError] = useState(null); const [activeStep, setActiveStep] = useState(0); const [isLoadingStatus, setIsLoadingStatus] = useState(true); @@ -86,6 +88,24 @@ export function ProjectStepper(props: ProjectStepperProps) { }, )} > + {isSubmittingProject && ( + setIsSubmittingProject(false)} + projectId={projectId} + onSubmit={(response) => { + const { repositoryUrl, submittedAt } = response; + + setProjectStatus({ + ...projectStatus, + repositoryUrl, + submittedAt, + }); + + setActiveStep(2); + }} + repositoryUrl={projectStatus.repositoryUrl} + /> + )} {isStartingProject && ( 1} icon={Send} + onClick={() => { + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + + setIsSubmittingProject(true); + }} text={activeStep > 1 ? 'Submitted' : 'Submit Solution'} number={2} /> diff --git a/src/components/Projects/SubmissionRequirement.tsx b/src/components/Projects/SubmissionRequirement.tsx new file mode 100644 index 000000000..a8946aaff --- /dev/null +++ b/src/components/Projects/SubmissionRequirement.tsx @@ -0,0 +1,31 @@ +import type { ReactNode } from 'react'; +import { cn } from '../../lib/classname.ts'; +import { CheckIcon, CircleDashed } from 'lucide-react'; + +type SubmissionRequirementProps = { + status: 'pending' | 'success' | 'error'; + children: ReactNode; +}; + +export function SubmissionRequirement(props: SubmissionRequirementProps) { + const { status, children } = props; + + return ( +
+ {status === 'pending' ? ( + + ) : status === 'success' ? ( + + ) : ( + + )} + {children} +
+ ); +} diff --git a/src/components/Projects/SubmitProjectModal.tsx b/src/components/Projects/SubmitProjectModal.tsx index 5f6a2c8fd..c9f271eb4 100644 --- a/src/components/Projects/SubmitProjectModal.tsx +++ b/src/components/Projects/SubmitProjectModal.tsx @@ -1,8 +1,11 @@ -import { X } from 'lucide-react'; +import { CheckIcon, CircleDashed, X } from 'lucide-react'; import { Modal } from '../Modal'; -import { useState, type FormEvent } from 'react'; +import { useState, type FormEvent, type ReactNode } from 'react'; import { useToast } from '../../hooks/use-toast'; import { httpPost } from '../../lib/http'; +import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx'; +import { cn } from '../../lib/classname.ts'; +import { SubmissionRequirement } from './SubmissionRequirement.tsx'; type SubmitProjectResponse = { repositoryUrl: string; @@ -36,6 +39,10 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) { setError(''); setSuccessMessage(''); + if (!repoUrl) { + throw new Error('Repository URL is required'); + } + const repoUrlParts = repoUrl .replace(/https?:\/\/(www\.)?github\.com/, '') .split('/'); @@ -51,9 +58,10 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) { const allContentsUrl = `${mainApiUrl}/contents`; const allContentsResponse = await fetch(allContentsUrl); if (!allContentsResponse.ok) { - const errorData = await allContentsResponse.json(); - if (errorData?.status === 404) { - throw new Error('Repository not found'); + if (allContentsResponse?.status === 404) { + throw new Error( + 'Repository not found. Make sure it exists and is public.', + ); } throw new Error('Failed to fetch repository contents'); @@ -108,21 +116,47 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) { } }; + const verificationChecks = { + valid_url: { + status: 'pending', + message: 'URL must point to a public GitHub repository', + }, + valid_repo: { + status: 'pending', + message: 'Repository must contain a readme file', + }, + valid_readme: { + status: 'pending', + message: 'Readme file must contain the project URL', + }, + }; + return ( -

- Submit Link to the GitHub repository +

+ Submit Solution URL

-

- Make sure to have a readme file in your project repository containing - the link to this project page. +

+ Submit the URL of your GitHub repository with the solution.

+
+ + URL must point to a public GitHub repository + + + Repository must contain a README file + + + README file must contain the project URL + +
+
setRepoUrl(e.target.value)} /> @@ -142,7 +176,7 @@ export function SubmitProjectModal(props: SubmitProjectModalProps) { className="mt-2 w-full rounded-lg bg-black p-2 font-medium text-white disabled:opacity-50" disabled={isLoading} > - {isLoading ? 'Verifying...' : 'Verify'} + {isLoading ? 'Verifying...' : 'Verify Submission'}