Skip to content

Commit

Permalink
Track welcome modal changes (#7183)
Browse files Browse the repository at this point in the history
* Adjust width of modal

* Add WhoIsThisTrackForView, pass down seniority level

* Set up logic around showing bootcamp recommendation view

* Add Views, rearrange things

* Add bootcamp landing path

* Commit changes in track_welcome_modal

* Add tests

* Change HasLearningModeStep copy

* Tweak copy

* Adjust tests and copy

---------

Co-authored-by: Jeremy Walker <jez.walker@gmail.com>
  • Loading branch information
dem4ron and iHiD authored Dec 4, 2024
1 parent a5f3914 commit 35edaea
Show file tree
Hide file tree
Showing 15 changed files with 262 additions and 25 deletions.
2 changes: 1 addition & 1 deletion app/css/modals/track-welcome-modal.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
@apply shadow-lgZ1 rounded-16;
@apply overflow-hidden;
width: 100%;
max-width: 1100px;
max-width: 1120px;
}

.lhs {
Expand Down
6 changes: 4 additions & 2 deletions app/helpers/react_components/modals/track_welcome_modal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ def to_s
cli_walkthrough: Exercism::Routes.cli_walkthrough_path,
track_tooling: Exercism::Routes.track_doc_path(track, 'installation'),
learning_resources: Exercism::Routes.track_doc_path(track, 'learning'),
download_cmd: Exercise.for(track.slug, 'hello-world').download_cmd
download_cmd: Exercise.for(track.slug, 'hello-world').download_cmd,
bootcamp_landing: Exercism::Routes.bootcamp_path
},
track:
track:,
user_seniority: current_user.seniority
}
)
end
Expand Down
1 change: 1 addition & 0 deletions app/images/bootcamp/certificate.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/images/bootcamp/complete.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useContext } from 'react'
import { TrackContext } from '../TrackWelcomeModal'
import { GraphicalIcon } from '@/components/common'

export function BootcampRecommendationView() {
const { hideBootcampRecommendationView, links } = useContext(TrackContext)
return (
<>
<h4
data-capy-element="bootcamp-recommendation-header"
className="text-h4 mb-8"
>
Our Bootcamp might be better for you…
</h4>

<p className="mb-8">
Exercism's tracks are designed for people who{' '}
<strong className="font-medium">already know how to code</strong> and
are practicing or learning new languages.
</p>
<p className="mb-8">
If you're just starting out on your coding journey,{' '}
<strong className="font-semibold">
our Bootcamp might be a better fit for you.
</strong>{' '}
It offers:
</p>
<ul className="flex flex-col gap-2 text-14 font-medium mb-8">
<li className="flex items-center">
<GraphicalIcon
icon="wave"
category="bootcamp"
className="mr-8 w-[20px]"
/>
Expert teaching and mentoring support
</li>
<li className="flex items-center">
<GraphicalIcon
icon="fun"
category="bootcamp"
className="mr-8 w-[20px]"
/>
Hands-on project based learning
</li>
<li className="flex items-center">
<GraphicalIcon
icon="complete"
category="bootcamp"
className="mr-8 w-[20px]"
/>
A complete Learn to Code syllabus
</li>
<li className="flex items-center">
<GraphicalIcon
icon="certificate"
category="bootcamp"
className="mr-8 w-[20px]"
/>
A formal certificate on completion
</li>
</ul>
<p className="mb-16">
It's part time, remote, and priced affordably, with discounts available
for students, people who are unemployed, and those living in emerging
economies.
</p>

<div className="flex gap-12 items-center w-full">
<a
href={links.bootcampLanding}
data-capy-element="go-to-bootcamp-button"
className="btn-m btn-primary flex-grow"
>
Check out the Bootcamp
</a>
<button
onClick={hideBootcampRecommendationView}
className="btn-m btn-secondary"
data-capy-element="continue-anyway-button"
>
Continue anyway
</button>
</div>
</>
)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assign, createMachine } from 'xstate'
import { createMachine } from 'xstate'

export type StateEvent =
| 'HAS_LEARNING_MODE'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export function HasLearningModeStep({
return (
<>
<h3 className="text-h3 mb-8">Here to learn or practice?</h3>
<p className="mb-12">
<p data-capy-element="welcome-modal-track-info" className="mb-12">
This track can be used for learning {track.title} (Learning Mode) or for
practicing your existing {track.title} knowledge (Practice Mode).{' '}
practicing your {track.title} skills (Practice Mode).{' '}
</p>
<p className="mb-12">
We recommend Learning Mode if you're new to {track.title}, and Practice
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useContext } from 'react'
import { TrackContext } from '../../TrackWelcomeModal'
import { StepButton } from './components/StepButton'
import { ButtonContainer } from './components/ButtonContainer'
import { BootcampRecommendationView } from '../BootcampRecommendationView'

export function LearningEnvironmentSelectorStep({
onSelectLocalMachine,
Expand All @@ -10,7 +10,13 @@ export function LearningEnvironmentSelectorStep({
'onSelectLocalMachine' | 'onSelectOnlineEditor',
() => void
>): JSX.Element {
const { track } = useContext(TrackContext)
const { track, shouldShowBootcampRecommendationView } =
useContext(TrackContext)

if (shouldShowBootcampRecommendationView) {
return <BootcampRecommendationView />
}

return (
<>
<h3 className="text-h3 mb-8">Online or on your computer?</h3>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { useContext } from 'react'
import { TrackContext } from '../TrackWelcomeModal'
import { VideoRHS } from './VideoRHS'
import { WhoIsThisTrackForRHS } from './WhoIsThisTrackForRHS'

export function TrackWelcomeModalRHS(): JSX.Element {
const { track, currentState, shouldShowBootcampRecommendationView } =
useContext(TrackContext)

if (
currentState.matches('learningEnvironmentSelector') &&
shouldShowBootcampRecommendationView
) {
return <WhoIsThisTrackForRHS track={track} />
}

return <VideoRHS track={track} />
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React, { useContext } from 'react'
import React from 'react'
import VimeoEmbed from '@/components/common/VimeoEmbed'
import { TrackContext } from './TrackWelcomeModal'
import { Track } from '@/components/types'

export function TrackWelcomeModalRHS(): JSX.Element {
const { track } = useContext(TrackContext)
export function VideoRHS({ track }: { track: Track }): JSX.Element {
return (
<div className="rhs">
<div className="rounded-8 p-20 bg-backgroundColorD border-1 border-borderColor7">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { GraphicalIcon, Icon } from '@/components/common'
import VimeoEmbed from '@/components/common/VimeoEmbed'
import { Track } from '@/components/types'
import React from 'react'

export function WhoIsThisTrackForRHS({ track }: { track: Track }): JSX.Element {
return (
<div className="rhs" data-capy-element="who-is-this-track-for-rhs">
<div className="rounded-8 p-20 bg-backgroundColorD border-1 border-borderColor7 mb-16">
<div className="flex flex-row gap-8 items-center justify-center text-16 text-textColor1 mb-16">
<Icon
icon="exercism-face"
className="filter-textColor1"
alt="exercism-face"
height={16}
width={16}
/>
<div>
<strong className="font-semibold"> Exercism </strong>
Bootcamp
</div>
</div>
<VimeoEmbed className="rounded-8 mb-16" id="1024390839?h=c2b3bdce14" />
<span className="text-16 leading-150 text-textColor2">
<strong className="font-medium">
🗓️ The Bootcamp starts in January.{' '}
</strong>
Check out our introduction video (☝️) to see how it will work and if
it's the right fit for you!
</span>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { createContext } from 'react'

import { Track } from '@/components/types'
import { Modal, ModalProps } from '../Modal'
import { TrackWelcomeModalRHS as RHS } from './TrackWelcomeModalRHS'
import { TrackWelcomeModalRHS as RHS } from './RHS/TrackWelcomeModalRHS'
import { TrackWelcomeModalLHS as LHS } from './LHS/TrackWelcomeModalLHS'
import { useTrackWelcomeModal } from './useTrackWelcomeModal'
import {
Expand All @@ -12,6 +12,7 @@ import {
} from './TrackWelcomeModal.types'
import { ErrorBoundary, ErrorMessage } from '@/components/ErrorBoundary'
import { ErrorFallback } from '@/components/common/ErrorFallback'
import { SeniorityLevel } from '../welcome-modal/WelcomeModal'

const DEFAULT_ERROR = new Error('Unable to dismiss modal')

Expand All @@ -20,24 +21,33 @@ export const TrackContext = createContext<{
currentState: CurrentState
send: any
links: TrackWelcomeModalLinks
userSeniority: SeniorityLevel
shouldShowBootcampRecommendationView: boolean
hideBootcampRecommendationView: () => void
}>({
track: {} as Track,
currentState: {} as CurrentState,
send: () => {},
links: {} as TrackWelcomeModalLinks,
userSeniority: '' as SeniorityLevel,
shouldShowBootcampRecommendationView: false,
hideBootcampRecommendationView: () => {},
})

export const TrackWelcomeModal = ({
links,
track,
userSeniority,
}: Omit<ModalProps, 'className' | 'open' | 'onClose'> &
TrackWelcomeModalProps): JSX.Element => {
const {
open,
currentState,
send,
error: modalDismissalError,
} = useTrackWelcomeModal(links)
shouldShowBootcampRecommendationView,
hideBootcampRecommendationView,
} = useTrackWelcomeModal(links, userSeniority)

return (
<Modal
Expand All @@ -46,7 +56,17 @@ export const TrackWelcomeModal = ({
onClose={() => null}
className="m-track-welcome-modal"
>
<TrackContext.Provider value={{ track, currentState, send, links }}>
<TrackContext.Provider
value={{
track,
currentState,
send,
links,
userSeniority,
shouldShowBootcampRecommendationView,
hideBootcampRecommendationView,
}}
>
<div className="flex">
<LHS />
<RHS />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { State, ResolveTypegenMeta, BaseActionObject, ServiceMap } from 'xstate'
import { StateEvent } from './LHS/TrackWelcomeModal.machine'
import { Typegen0 } from './LHS/TrackWelcomeModal.machine.typegen'
import { Track } from '@/components/types'
import { SeniorityLevel } from '../welcome-modal/WelcomeModal'

export type TrackWelcomeModalProps = {
track: Track
links: TrackWelcomeModalLinks
userSeniority: SeniorityLevel
}

export type TrackWelcomeModalLinks = Record<
Expand All @@ -15,7 +17,8 @@ export type TrackWelcomeModalLinks = Record<
| 'editHelloWorld'
| 'cliWalkthrough'
| 'trackTooling'
| 'learningResources',
| 'learningResources'
| 'bootcampLanding',
string
>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import { redirectTo } from '@/utils'
import { sendRequest } from '@/utils/send-request'
import { useMachine } from '@xstate/react'
import { useState } from 'react'
import { useCallback, useState } from 'react'
import { useMutation } from '@tanstack/react-query'
import { machine } from './LHS/TrackWelcomeModal.machine'
import { TrackWelcomeModalLinks } from './TrackWelcomeModal.types'
import { SeniorityLevel } from '../welcome-modal/WelcomeModal'

export function useTrackWelcomeModal(links: TrackWelcomeModalLinks) {
export function useTrackWelcomeModal(
links: TrackWelcomeModalLinks,
userSeniority: SeniorityLevel
) {
const [open, setOpen] = useState(true)
const {
mutate: hideModal,
status,
error,
} = useMutation(

const [
shouldShowBootcampRecommendationView,
setShouldShowBootcampRecommendationView,
] = useState(userSeniority.includes('beginner'))

const hideBootcampRecommendationView = useCallback(() => {
setShouldShowBootcampRecommendationView(false)
}, [])

const { mutate: hideModal, error } = useMutation(
() => {
const { fetch } = sendRequest({
endpoint: links.hideModal,
Expand Down Expand Up @@ -67,5 +77,12 @@ export function useTrackWelcomeModal(links: TrackWelcomeModalLinks) {
},
})

return { open, currentState, send, error }
return {
open,
currentState,
send,
error,
shouldShowBootcampRecommendationView,
hideBootcampRecommendationView,
}
}
Loading

0 comments on commit 35edaea

Please sign in to comment.