From 05d09335b5a246ca058146bd32827c9fd7f475e0 Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Fri, 16 Aug 2024 03:58:46 +0100 Subject: [PATCH] Add projects tip popup --- src/components/Modal.tsx | 4 +- src/components/OpenSourceStat.astro | 2 +- src/components/Projects/StartProjectModal.tsx | 176 +++++++++++++++--- .../Projects/StatusStepper/ProjectStepper.tsx | 66 ++++++- 4 files changed, 214 insertions(+), 34 deletions(-) diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index ac28c9e7c..d8167ff7a 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -33,7 +33,7 @@ export function Modal(props: ModalProps) { return (
@@ -46,7 +46,7 @@ export function Modal(props: ModalProps) {
diff --git a/src/components/OpenSourceStat.astro b/src/components/OpenSourceStat.astro index a7eee8ed1..97cf0bd95 100644 --- a/src/components/OpenSourceStat.astro +++ b/src/components/OpenSourceStat.astro @@ -44,7 +44,7 @@ const isDiscordMembers = text.toLowerCase() === 'discord members'; }

{value}

diff --git a/src/components/Projects/StartProjectModal.tsx b/src/components/Projects/StartProjectModal.tsx index b6a30bf78..b9d6a6294 100644 --- a/src/components/Projects/StartProjectModal.tsx +++ b/src/components/Projects/StartProjectModal.tsx @@ -1,57 +1,175 @@ -import { X } from 'lucide-react'; +import { + Check, + CheckCircle, + CheckCircle2, + CopyCheck, + CopyIcon, + ServerCrash, + X, +} from 'lucide-react'; import { Modal } from '../Modal'; import { getRelativeTimeString } from '../../lib/date'; +import { useEffect, useState } from 'react'; +import { Spinner } from '../ReactIcons/Spinner.tsx'; +import { httpPost } from '../../lib/http.ts'; +import { ErrorIcon } from '../ReactIcons/ErrorIcon.tsx'; +import { CheckIcon } from '../ReactIcons/CheckIcon.tsx'; +import { useCopyText } from '../../hooks/use-copy-text.ts'; + +type StepLabelProps = { + label: string; +}; + +function StepLabel(props: StepLabelProps) { + const { label } = props; + + return ( + + {label} + + ); +} type StartProjectModalProps = { + projectId: string; onClose: () => void; startedAt?: Date; + onStarted: (startedAt: Date) => void; }; export function StartProjectModal(props: StartProjectModalProps) { - const { onClose, startedAt } = props; + const { onClose, startedAt, onStarted, projectId } = props; + + const [isStartingProject, setIsStartingProject] = useState(true); + const [error, setError] = useState(); + + const { isCopied, copyText } = useCopyText(); + + const projectUrl = `${import.meta.env.PUBLIC_APP_URL}/projects/${projectId}`; 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.', + '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() { + if (!projectId || startedAt) { + return; + } + + setIsStartingProject(true); + const { response, error } = await httpPost<{ + startedAt: Date; + }>(`${import.meta.env.PUBLIC_API_URL}/v1-start-project/${projectId}`, {}); + + if (error || !response) { + setError(error?.message || 'Failed to start project'); + setIsStartingProject(false); + return; + } + + onStarted(response.startedAt); + } + + useEffect(() => { + handleStartProject().finally(() => setIsStartingProject(false)); + }, []); + + if (error) { + return ( + +
+ +

{error}

+
+
+ ); + } + + if (isStartingProject) { + return ( + +
+ +

Starting project ..

+
+
+ ); + } + return ( - -

- Started working... - {formattedStartedAt ? ( - - {formattedStartedAt} - - ) : null} + +

+ + Project started{' '} + {formattedStartedAt} +

+

+ Start Building

-

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

+ Follow these steps to complete the project.

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

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. Make + sure to include the{' '} + {' '} + in the readme file. +

+
+
+ +

+ Submit your repository URL to help others learn and get feedback + from the community. +

+
+
-

Happy coding!

+
+

If you get stuck, you can always ask for help in the community chat on discord.

+
); diff --git a/src/components/Projects/StatusStepper/ProjectStepper.tsx b/src/components/Projects/StatusStepper/ProjectStepper.tsx index 8bb0f7e54..130b8fa64 100644 --- a/src/components/Projects/StatusStepper/ProjectStepper.tsx +++ b/src/components/Projects/StatusStepper/ProjectStepper.tsx @@ -5,7 +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 } from '../../../lib/http.ts'; +import { httpGet, httpPost } 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'; type ProjectStatusResponse = { id?: string; @@ -28,6 +33,7 @@ export function ProjectStepper(props: ProjectStepperProps) { const stickyElRef = useRef(null); const isSticky = useStickyStuck(stickyElRef, 8); + const [isStartingProject, setIsStartingProject] = useState(false); const [error, setError] = useState(null); const [activeStep, setActiveStep] = useState(0); const [isLoadingStatus, setIsLoadingStatus] = useState(true); @@ -80,6 +86,26 @@ export function ProjectStepper(props: ProjectStepperProps) { }, )} > + {isStartingProject && ( + { + setProjectStatus({ + ...projectStatus, + startedAt, + }); + setActiveStep(1); + }} + startedAt={projectStatus?.startedAt} + onClose={() => setIsStartingProject(false)} + /> + )} + + {error && ( +
+ {error} +
+ )} {isLoadingStatus && (
)} @@ -91,7 +117,35 @@ export function ProjectStepper(props: ProjectStepperProps) { }, )} > - Start building, submit solution and get feedback from the community. + {activeStep === 0 && ( + <> + Start building, submit solution and get feedback from the community. + + )} + {activeStep === 1 && ( + <> + Started working{' '} + + {getRelativeTimeString(projectStatus.startedAt!)} + + . Follow{' '} + {' '} + to get most out of it. + + )}
@@ -101,6 +155,14 @@ export function ProjectStepper(props: ProjectStepperProps) { icon={Play} text={activeStep > 0 ? 'Started Working' : 'Start Working'} number={1} + onClick={() => { + if (!isLoggedIn()) { + showLoginPopup(); + return; + } + + setIsStartingProject(true); + }} /> 0} />