Skip to content

Commit

Permalink
Merge pull request #1632 from geyserfund/sajal/gys-8666-make-countryr…
Browse files Browse the repository at this point in the history
…egion-mandatory-in-project-creation-flow

hotfix: make Country/Region mandatory in project creation flow
  • Loading branch information
sajald77 authored Sep 18, 2024
2 parents 4a21acd + 8ecc0aa commit 708aba8
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 7 deletions.
19 changes: 18 additions & 1 deletion src/modules/project/forms/ProjectRegion.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQuery } from '@apollo/client'
import { HStack, IconButton, StackProps, useDisclosure, VStack } from '@chakra-ui/react'
import { useAtom } from 'jotai'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { PiX } from 'react-icons/pi'
Expand All @@ -15,6 +16,7 @@ import { FieldContainer } from '../../../shared/components/form/FieldContainer'
import { SkeletonLayout } from '../../../shared/components/layouts'
import { Country, Location, Maybe, Project, ProjectCountriesGetResult, ProjectRegionsGetResult } from '../../../types'
import { ProjectState } from '../state/projectAtom'
import { projectFormErrorAtom } from '../state/projectFormAtom'

const useStyles = createUseStyles(({ colors }: AppTheme) => ({
container: {
Expand Down Expand Up @@ -51,6 +53,8 @@ export const ProjectRegion = ({ location, updateProject, ...rest }: ProjectRegio
const { t } = useTranslation()
const classes = useStyles()

const [projectFormError, setProjectFormError] = useAtom(projectFormErrorAtom)

const [inputValue, setInputValue] = useState('')
const { isOpen, onOpen, onClose } = useDisclosure()

Expand Down Expand Up @@ -98,7 +102,12 @@ export const ProjectRegion = ({ location, updateProject, ...rest }: ProjectRegio
}
}

const clearLocationError = () => {
setProjectFormError((prev) => ({ ...prev, location: undefined }))
}

const removeRegion = () => {
clearLocationError()
updateProject({
location: { region: '', country: { code: '', name: '' } },
})
Expand All @@ -114,7 +123,7 @@ export const ProjectRegion = ({ location, updateProject, ...rest }: ProjectRegio

return (
<FieldContainer
title={t('Region')}
title={`${t('Region')}*`}
subtitle={
<span>{t('Get found more easily by putting your project on the map. Select a country or region')}</span>
}
Expand All @@ -139,8 +148,11 @@ export const ProjectRegion = ({ location, updateProject, ...rest }: ProjectRegio
inputValue={inputValue}
onMenuOpen={onOpen}
onMenuClose={onClose}
isInvalid={Boolean(projectFormError.location)}
onFocus={clearLocationError}
/>
)}

<HStack width="100%" spacing="10px" flexWrap={'wrap'}>
{displayLocation && (
<HStack borderRadius="4px" paddingLeft="8px" backgroundColor="neutral1.2">
Expand All @@ -160,6 +172,11 @@ export const ProjectRegion = ({ location, updateProject, ...rest }: ProjectRegio
)}
</HStack>
</VStack>
{projectFormError.location && (
<Body size="xs" color="error.9" w="full" textAlign={'start'}>
{projectFormError.location}
</Body>
)}
</FieldContainer>
)
}
2 changes: 2 additions & 0 deletions src/modules/project/pages1/projectCreation/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,5 @@ export const tagToRewardCategoryMapping: { [key: string]: RewardCategory[] } = {
homeschooling: [RewardCategory.Shoutout, RewardCategory.Course, RewardCategory.Experience],
minecraft: [RewardCategory.Game],
}

export const ProjectCountryCodesThatAreRestricted = ['UA', 'PSE', 'YE', 'RU']
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useEffect } from 'react'
import { useNavigate } from 'react-router'

import { useProjectAtom } from '@/modules/project/hooks/useProjectAtom'
import { getPath } from '@/shared/constants'

export const useLocationMandatoryRedirect = () => {
const navigate = useNavigate()
const { project, loading } = useProjectAtom()

useEffect(() => {
if (project && !loading && !project.location?.country?.code) {
navigate(getPath('launchProjectDetails', project?.id))
}
}, [loading, project, navigate])
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { dimensions, getPath } from '../../../../../shared/constants'
import { ProjectStoryForm } from '../../../forms/ProjectStoryForm'
import { FormContinueButton } from '../components/FormContinueButton'
import { ProjectCreateLayout } from '../components/ProjectCreateLayout'
import { useLocationMandatoryRedirect } from '../hooks/useLocationMandatoryRedirect'
import { useProjectStoryForm } from '../hooks/useProjectStoryForm'

export const ProjectCreateStory = () => {
Expand All @@ -25,6 +26,8 @@ export const ProjectCreateStory = () => {

const form = useProjectStoryForm({ project })

useLocationMandatoryRedirect()

const onLeave = () => {
if (!project) {
return navigate(-1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useNotification } from '../../../../../utils'
import { ProjectCreationWalletConnectionForm } from '..'
import { FormContinueButton } from '../components/FormContinueButton'
import { ProjectCreateLayout } from '../components/ProjectCreateLayout'
import { useLocationMandatoryRedirect } from '../hooks/useLocationMandatoryRedirect'
import { ConnectionOption, useWalletForm } from '../hooks/useWalletForm'
import { ProjectCreateCompletionPage } from './ProjectCreateCompletionPage'

Expand All @@ -27,6 +28,8 @@ export const ProjectCreationWalletConnectionPage = () => {
const { project, loading } = useProjectAtom()
const { createWallet } = useProjectWalletAPI()

useLocationMandatoryRedirect()

const [isReadyForLaunch, setReadyForLaunch] = useState(false)

const handleNext = (createWalletInput: CreateWalletInput | null) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { VStack } from '@chakra-ui/react'
import { useSetAtom } from 'jotai'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'

import { useProjectDetailsAPI } from '@/modules/project/API/useProjectDetailsAPI'
import { projectFormErrorAtom } from '@/modules/project/state/projectFormAtom'

import TitleWithProgressBar from '../../../../../components/molecules/TitleWithProgressBar'
import { getPath } from '../../../../../shared/constants'
Expand All @@ -12,27 +14,47 @@ import { ProjectRegion } from '../../../forms/ProjectRegion'
import { ProjectTagsCreateEdit } from '../../../forms/ProjectTagsCreateEdit'
import { FormContinueButton } from '../components/FormContinueButton'
import { ProjectCreateLayout } from '../components/ProjectCreateLayout'
import { ProjectCountryCodesThatAreRestricted } from '../constants'
import { useProjectDetailsForm } from '../hooks/useProjectDetailsForm'

export const ProjectDetails = () => {
const { t } = useTranslation()
const navigate = useNavigate()

const { toast, unexpected } = useNotification()
const toast = useNotification()

const { queryProjectDetails } = useProjectDetailsAPI(true)

const { updateProject, saveProject, saveTags, setLinks, setTags, project, tags, linkError, tagsLoading, isDirty } =
const { updateProject, saveProject, saveTags, setLinks, setTags, project, tags, linkError, tagsLoading } =
useProjectDetailsForm()

const setProjectFormError = useSetAtom(projectFormErrorAtom)

const onSubmit = async () => {
if (!project) {
return
}

if (!project.location || !project.location.country || !project.location.country.code) {
toast.error({
title: 'Please select a region',
description: 'Project region is required to proceed',
})
setProjectFormError((prev) => ({ ...prev, location: 'Project region is required' }))
return
}

if (ProjectCountryCodesThatAreRestricted.includes(project.location.country.code)) {
toast.error({
title: 'Country not supported',
description: 'We are not able to support projects from this country',
})
setProjectFormError((prev) => ({ ...prev, location: 'Country not supported' }))
return
}

if (linkError.includes(true)) {
toast({
status: 'warning',
toast.warning({
title: 'failed to update project',
description: 'please enter a valid url for project links',
})
Expand All @@ -45,7 +67,7 @@ export const ProjectDetails = () => {

navigate(getPath('launchProjectStory', project.id))
} catch (e) {
unexpected()
toast.unexpected()
}
}

Expand All @@ -66,7 +88,7 @@ export const ProjectDetails = () => {
return (
<>
<ProjectCreateLayout
continueButton={<FormContinueButton isSkip={!isDirty} flexGrow={1} {...nextProps} />}
continueButton={<FormContinueButton flexGrow={1} {...nextProps} />}
onBackClick={onBackClick}
title={<TitleWithProgressBar title={t('Links & tags')} subtitle={t('Create a project')} index={2} length={5} />}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import TitleWithProgressBar from '../../../../../../components/molecules/TitleWi
import { getPath } from '../../../../../../shared/constants'
import { FormContinueButton } from '../../components/FormContinueButton'
import { ProjectCreateLayout } from '../../components/ProjectCreateLayout'
import { useLocationMandatoryRedirect } from '../../hooks/useLocationMandatoryRedirect'

export const ProjectCreateRewards = () => {
const { t } = useTranslation()
Expand All @@ -18,6 +19,8 @@ export const ProjectCreateRewards = () => {
const { project } = useProjectAtom()
const { rewards } = useRewardsAtom()

useLocationMandatoryRedirect()

const isNew = useMatch(getPath('launchProjectRewardsCreate', project?.id))
const isEdit = useMatch(getPath('launchProjectRewardsEdit', project?.id, ':rewardId'))
const isCreatingOrEditing = isNew || isEdit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Button, ButtonProps, VStack } from '@chakra-ui/react'
import { useSetAtom } from 'jotai'
import { useTranslation } from 'react-i18next'

import { useProjectDetailsAPI } from '@/modules/project/API/useProjectDetailsAPI'
import { ProjectLinks } from '@/modules/project/forms/ProjectLinks'
import { ProjectRegion } from '@/modules/project/forms/ProjectRegion'
import { ProjectTagsCreateEdit } from '@/modules/project/forms/ProjectTagsCreateEdit'
import { projectFormErrorAtom } from '@/modules/project/state/projectFormAtom'
import { useNotification } from '@/utils'

import { ProjectCountryCodesThatAreRestricted } from '../../projectCreation/constants'
import { useProjectDetailsForm } from '../../projectCreation/hooks/useProjectDetailsForm'
import { DashboardLayout } from '../common'
import { ProjectUnsavedModal, useProjectUnsavedModal } from '../common/ProjectUnsavedModal'
Expand All @@ -19,12 +22,31 @@ export const ProjectDashboardDetails = () => {

const { project, isDirty, linkError, saveProject, saving, saveTags, setLinks, setTags, tags, updateProject } =
useProjectDetailsForm()
const setProjectFormError = useSetAtom(projectFormErrorAtom)

const unsavedModal = useProjectUnsavedModal({
hasUnsaved: isDirty,
})

const onSubmit = async () => {
if (!project.location || !project.location.country || !project.location.country.code) {
toast.error({
title: 'Please select a region',
description: 'Project region is required to proceed',
})
setProjectFormError((prev) => ({ ...prev, location: 'Project region is required' }))
return
}

if (ProjectCountryCodesThatAreRestricted.includes(project.location.country.code)) {
toast.error({
title: 'Country not supported',
description: 'We are not able to support projects from this country',
})
setProjectFormError((prev) => ({ ...prev, location: 'Country not supported' }))
return
}

if (linkError.includes(true)) {
toast.warning({
title: 'failed to update project',
Expand Down
5 changes: 5 additions & 0 deletions src/modules/project/state/projectFormAtom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ export const diffProjectAtom = atom((get) => {
])
})

type ProjectFormError = { [key in keyof ProjectState]: string }
/** Project form error state */
export const projectFormErrorAtom = atom<ProjectFormError>({} as ProjectFormError)

/** Reset all real-atoms in this file to it's initial State */
export const projectFormAtomReset = atom(null, (get, set) => {
set(formProjectAtom, {} as ProjectState)
set(projectFormErrorAtom, {} as ProjectFormError)
})

0 comments on commit 708aba8

Please sign in to comment.