From 20902903d3dcd244b045a71f49b9bf8c289d4cda Mon Sep 17 00:00:00 2001 From: Hazem Krimi Date: Tue, 15 Jun 2021 02:04:13 +0100 Subject: [PATCH] Add project creation page --- src/pages/AddProject/index.tsx | 1150 ++++++++++++++++++++++++++++++++ src/pages/AddProject/styles.ts | 18 + src/pages/index.tsx | 2 + 3 files changed, 1170 insertions(+) create mode 100644 src/pages/AddProject/index.tsx create mode 100644 src/pages/AddProject/styles.ts diff --git a/src/pages/AddProject/index.tsx b/src/pages/AddProject/index.tsx new file mode 100644 index 0000000..ea1c21e --- /dev/null +++ b/src/pages/AddProject/index.tsx @@ -0,0 +1,1150 @@ +// @ts-ignore +import Carousel, { consts } from 'react-elastic-carousel'; +import * as Yup from 'yup'; +import { useFormik } from 'formik'; +import { useHistory } from 'react-router'; +import { useLazyQuery, useMutation, useReactiveVar } from '@apollo/client'; +import { useState, useEffect } from 'react'; +import { roleVar, userVar } from '../../graphql/state'; +import { Wrapper } from './styles'; +import { + Alert, + Box, + Button, + CategoryCard, + FeatureCard, + Input, + Spinner, + TemplateCard, + Text, +} from '../../components'; +import { ArrowLeft, ArrowRight, ChevronLeft, ChevronRight } from '../../assets'; +import { + AddProjectMutation, + AddProjectMutationVariables, + CategoryOutput, + DelivrableInput, + FeatureOutput, + GetAllCategoriesQuery, + GetAllCategoriesQueryVariables, + GetAllFeaturesQuery, + GetAllFeaturesQueryVariables, + GetAllTemplatesByCategoriesIdQuery, + GetAllTemplatesByCategoriesIdQueryVariables, + PaymentOptionInput, + ProjectInput, + TemplateOutput, +} from '../../graphql/types'; +import { theme } from '../../themes'; +import { GET_ALL_CATEGORIES } from '../../graphql/category.api'; +import { GET_ALL_TEMPLATES_BY_CATEGORIES_ID } from '../../graphql/template.api'; +import { GET_ALL_FEATURES } from '../../graphql/feature.api'; +import { ADD_PROJECT } from '../../graphql/project.api'; + +const AddProject = () => { + const history = useHistory(); + const role = useReactiveVar(roleVar); + const currentUser = useReactiveVar(userVar); + const [error, setError] = useState(''); + const [step, setStep] = useState< + | 'basic-info' + | 'categories' + | 'template' + | 'features' + | 'deliverables-platforms' + | 'payment-options' + | 'client-creation' + | 'project-metadata' + >('basic-info'); + const [project, setProject] = useState>(); + const [chosenCategories, setChosenCategories] = useState>([]); + const [chosenTemplate, setChosenTemplate] = useState< + TemplateOutput | undefined + >(); + const [chosenFeatures, setChosenFeatures] = useState>( + [] + ); + const [ + chosenDeliverables, + setChosenDeliverables, + ] = useState(); + const [ + chosenPaymentOption, + setChosenPaymentOption, + ] = useState(); + const [chosenPlatforms, setChosenPlatforms] = useState>([]); + const [selectedFeature, setSelectedFeature] = useState(); + const [categories, setCategories] = useState>([]); + const [templates, setTemplates] = useState>([]); + const [features, setFeatures] = useState>([]); + + const [getCategories, { loading: categoriesLoading }] = useLazyQuery< + GetAllCategoriesQuery, + GetAllCategoriesQueryVariables + >(GET_ALL_CATEGORIES, { + onCompleted({ getAllCategories }) { + setCategories(getAllCategories); + }, + fetchPolicy: 'network-only', + }); + + const [getTemplates, { loading: templatesLoading }] = useLazyQuery< + GetAllTemplatesByCategoriesIdQuery, + GetAllTemplatesByCategoriesIdQueryVariables + >(GET_ALL_TEMPLATES_BY_CATEGORIES_ID, { + onCompleted({ getAllTemplatesByCategoriesId }) { + setTemplates(getAllTemplatesByCategoriesId); + }, + fetchPolicy: 'network-only', + }); + + const [getFeatures, { loading: featuresLoading }] = useLazyQuery< + GetAllFeaturesQuery, + GetAllFeaturesQueryVariables + >(GET_ALL_FEATURES, { + onCompleted({ getAllFeatures }) { + setFeatures(getAllFeatures); + }, + fetchPolicy: 'network-only', + }); + + const [addProject, { loading: addProjectLoading }] = useMutation< + AddProjectMutation, + AddProjectMutationVariables + >(ADD_PROJECT, { + onCompleted({ addProject: projectData }) { + history.push(`/project/${projectData.id}`); + }, + onError({ graphQLErrors }) { + setError(graphQLErrors[0].extensions?.info); + setTimeout(() => setError(''), 3000); + }, + }); + + useEffect(() => { + if (step === 'categories') getCategories(); + if (step === 'template') + getTemplates({ variables: { categories: chosenCategories } }); + if (step === 'features') getFeatures(); + + // eslint-disable-next-line + }, [step]); + + const basicInfoForm = useFormik({ + initialValues: { + name: '', + imageName: '', + imageSource: '', + }, + validationSchema: Yup.object().shape({ + name: Yup.string().required('Name is required'), + imageName: Yup.string().required('Image is required'), + imageSource: Yup.string().required('Image is required'), + }), + onSubmit: ({ name, imageName, imageSource }) => { + setProject({ + ...project, + clientId: currentUser?.id, + name, + image: { name: imageName, src: imageSource }, + }); + setStep('categories'); + }, + }); + + const categoriesForm = useFormik<{ selectedCategories: Array }>({ + initialValues: { + selectedCategories: [], + }, + onSubmit: ({ selectedCategories }) => { + if (selectedCategories.length === 0) { + setError('Select at least one category'); + setTimeout(() => setError(''), 3000); + return; + } + setChosenCategories(selectedCategories); + setStep('template'); + }, + }); + + const templateForm = useFormik<{ + selectedTemplate: TemplateOutput | undefined; + }>({ + initialValues: { + selectedTemplate: undefined, + }, + onSubmit: ({ selectedTemplate }) => { + if (!selectedTemplate) { + setError('You must select one template'); + setTimeout(() => setError(''), 3000); + return; + } + setChosenTemplate(selectedTemplate); + setStep('features'); + }, + }); + + const featuresForm = useFormik<{ + selectedFeatures: Array; + }>({ + initialValues: { + selectedFeatures: [], + }, + onSubmit: ({ selectedFeatures }) => { + if (selectedFeatures.length === 0) { + setError('Select at least one feature'); + setTimeout(() => setError(''), 3000); + return; + } + setChosenFeatures(selectedFeatures); + setStep('deliverables-platforms'); + }, + }); + + const deliverablesPlatformsForm = useFormik<{ + selectedDeliverables: DelivrableInput; + selectedPlatforms: Array; + }>({ + initialValues: { + selectedDeliverables: { + specification: false, + design: false, + mvp: false, + fullBuild: false, + }, + selectedPlatforms: [], + }, + onSubmit: ({ selectedDeliverables, selectedPlatforms }) => { + if ( + Object.values(selectedDeliverables) + .slice(0, 4) + .filter((value) => value === true).length === 0 + ) { + setError('Select at least one deliverable'); + setTimeout(() => setError(''), 3000); + return; + } + if (selectedPlatforms.length === 0) { + setError('Select at least one platform'); + setTimeout(() => setError(''), 3000); + return; + } + setChosenPlatforms(selectedPlatforms); + setChosenDeliverables(selectedDeliverables); + setStep('payment-options'); + }, + }); + + const paymentOptionsForm = useFormik<{ + optOne: number; + optTwo: number; + optThree: number; + }>({ + initialValues: { + optOne: 0, + optTwo: 0, + optThree: 0, + }, + onSubmit: ({ optOne, optTwo, optThree }) => { + if (!optOne && !optTwo && !optThree) { + setError('You must choose one payment option'); + setTimeout(() => setError(''), 3000); + return; + } + setChosenPaymentOption({ optOne, optTwo, optThree }); + if (role === 'client') + addProject({ + variables: { + project: { + name: project?.name!, + image: { + name: project?.image?.name!, + src: project?.image?.src!, + }, + features: chosenFeatures.map((feature) => feature.id)!, + template: chosenTemplate?.id!, + clientId: currentUser?.id!, + platforms: chosenPlatforms, + delivrable: chosenDeliverables, + paymentOption: { + optOne, + optTwo, + optThree, + }!, + totalPrice: chosenFeatures.reduce( + (accumulator, feature) => accumulator + feature.price, + 0 + ), + }, + }, + }); + + if (role === 'productOwner') setStep('client-creation'); + }, + }); + + const carouselSettings = { + pagination: false, + itemsToShow: 1, + enableSwipe: true, + isRTL: false, + disableArrowsOnEnd: true, + enableTilt: false, + renderArrow: ({ + type, + onClick, + isEdge, + }: { + type: string; + onClick: () => void; + isEdge: boolean; + }) => ( + <> + {type !== consts.PREV ? ( + + ) : ( + + )} + + ), + transitionMs: 0, + }; + + return ( + + + + +