diff --git a/src/components/Projects/ProjectMilestoneStrip.tsx b/src/components/Projects/ProjectMilestoneStrip.tsx new file mode 100644 index 000000000..39c17d241 --- /dev/null +++ b/src/components/Projects/ProjectMilestoneStrip.tsx @@ -0,0 +1,102 @@ +import { useState } from 'react'; +import { cn } from '../../lib/classname'; +import { StartProjectModal } from './StartProjectModal'; +import { SubmitProjectModal } from './SubmitProjectModal'; + +type ProjectMilestoneStripProps = { + projectId: string; +}; + +export function ProjectMilestoneStrip(props: ProjectMilestoneStripProps) { + const { projectId } = props; + + const [stepIndex, setStepIndex] = useState(0); + const [isStartProjectModalOpen, setIsStartProjectModalOpen] = useState(false); + const [isSubmitProjectModalOpen, setIsSubmitProjectModalOpen] = + useState(false); + + const startProjectModal = isStartProjectModalOpen ? ( + setIsStartProjectModalOpen(false)} /> + ) : null; + const submitProjectModal = isSubmitProjectModalOpen ? ( + setIsSubmitProjectModalOpen(false)} + projectId={projectId} + onSubmit={() => setStepIndex(2)} + /> + ) : null; + + return ( + <> + {startProjectModal} + {submitProjectModal} + +
+
+
+ + + +
+
+ + + +
+
+ + + + Get 5 Likes + +
+
+ + + + Get 10 Likes + +
+
+
+ + ); +} + +type MilestoneStepProps = { + isActive: boolean; + position?: 'start' | 'middle' | 'end'; +}; + +function MilestoneStep(props: MilestoneStepProps) { + const { isActive = false, position = 'start' } = props; + + return ( +
+ +
+ ); +} diff --git a/src/components/Projects/StartProjectModal.tsx b/src/components/Projects/StartProjectModal.tsx new file mode 100644 index 000000000..5872bf481 --- /dev/null +++ b/src/components/Projects/StartProjectModal.tsx @@ -0,0 +1,47 @@ +import { X } from 'lucide-react'; +import { Modal } from '../Modal'; + +type StartProjectModalProps = { + onClose: () => void; +}; + +export function StartProjectModal(props: StartProjectModalProps) { + const { onClose } = props; + + const projectTips = [ + 'Create a repository on GitHub', + 'Develop the required functionality', + 'Add a readme and make sure to link to the project page', + 'Once you are done, make sure to come back and submit your solution to get feedback from others.', + 'Feel free to join our discord and ask for help if you get stuck.', + ]; + + return ( + +

Started working...

+

+ You have started working on the project. Here are some tips to get most + out of it. +

+ +
    + {projectTips.map((tip) => { + return ( +
  • + {tip} +
  • + ); + })} +
+ +

Happy coding!

+ + +
+ ); +} diff --git a/src/components/Projects/SubmitProjectModal.tsx b/src/components/Projects/SubmitProjectModal.tsx new file mode 100644 index 000000000..c463dc259 --- /dev/null +++ b/src/components/Projects/SubmitProjectModal.tsx @@ -0,0 +1,136 @@ +import { X } from 'lucide-react'; +import { Modal } from '../Modal'; +import { useState, type FormEvent } from 'react'; +import { useToast } from '../../hooks/use-toast'; + +type SubmitProjectModalProps = { + onClose: () => void; + projectId: string; + onSubmit: () => void; +}; + +export function SubmitProjectModal(props: SubmitProjectModalProps) { + const { onClose, projectId, onSubmit } = props; + + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); + const [repoUrl, setRepoUrl] = useState(''); + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + try { + setIsLoading(true); + setError(''); + setSuccessMessage(''); + + const repoUrlParts = repoUrl + .replace(/https?:\/\/(www\.)?github\.com/, '') + .split('/'); + const username = repoUrlParts[1]; + const repoName = repoUrlParts[2]; + + if (!username || !repoName) { + throw new Error('Invalid GitHub repository URL'); + } + + const mainApiUrl = `https://api.github.com/repos/${username}/${repoName}`; + + 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'); + } + + throw new Error('Failed to fetch repository contents'); + } + + const allContentsData = await allContentsResponse.json(); + if (!Array.isArray(allContentsData)) { + throw new Error('Failed to fetch repository contents'); + } + + const readmeFile = allContentsData.find( + (file) => file.name.toLowerCase() === 'readme.md', + ); + if (!readmeFile || !readmeFile.url) { + throw new Error('Readme file not found'); + } + + const readmeUrl = readmeFile.url; + const response = await fetch(readmeUrl); + if (!response.ok || response.status === 404) { + throw new Error('Readme file not found'); + } + + const data = await response.json(); + if (!data.content) { + throw new Error('Readme file not found'); + } + + const readmeContent = window.atob(data.content); + const projectUrl = `${window.location.origin}/projects/${projectId}`; + if (!readmeContent.includes(projectUrl)) { + throw new Error('Project URL not found in the readme file'); + } + + // TODO: Make API call to update the project status + setSuccessMessage('Repository verified successfully'); + setIsLoading(false); + onSubmit(); + } catch (error: any) { + console.error(error); + setError(error?.message || 'Failed to verify repository'); + setIsLoading(false); + } + }; + + return ( + +

+ Submit Link to the GitHub repository +

+

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

+ +
+ setRepoUrl(e.target.value)} + /> + + {error && ( +

{error}

+ )} + + {successMessage && ( +

+ {successMessage} +

+ )} + + +
+ + +
+ ); +} diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index f7912f35c..6dd31190c 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -109,7 +109,10 @@ const gaPageIdentifier = Astro.url.pathname /> - +