From 1a8f6be1487cb7021caab705230daff2c489e07d Mon Sep 17 00:00:00 2001 From: Hazem Krimi Date: Wed, 16 Jun 2021 02:39:46 +0100 Subject: [PATCH] Update add project page --- src/pages/AddProject/index.tsx | 822 ++++++++++++++++++++++++++++++++- 1 file changed, 817 insertions(+), 5 deletions(-) diff --git a/src/pages/AddProject/index.tsx b/src/pages/AddProject/index.tsx index 778ca38..ea8e961 100644 --- a/src/pages/AddProject/index.tsx +++ b/src/pages/AddProject/index.tsx @@ -14,15 +14,30 @@ import { CategoryCard, FeatureCard, Input, + SectionSelector, + Select, Spinner, TemplateCard, Text, + TextArea, } from '../../components'; -import { ArrowLeft, ArrowRight, ChevronLeft, ChevronRight } from '../../assets'; +import { + ArrowLeft, + ArrowRight, + ChevronLeft, + ChevronRight, + Profile, + Security, +} from '../../assets'; import { AddProjectMutation, AddProjectMutationVariables, + AddProjectProposalMutation, + AddProjectProposalMutationVariables, CategoryOutput, + CountryPrefixModel, + CreateUserMutation, + CreateUserMutationVariables, DelivrableInput, FeatureOutput, GetAllCategoriesQuery, @@ -31,15 +46,22 @@ import { GetAllFeaturesQueryVariables, GetAllTemplatesByCategoriesIdQuery, GetAllTemplatesByCategoriesIdQueryVariables, + GetAllUsersQuery, + GetAllUsersQueryVariables, + GetCountryCodesQuery, + GetCountryCodesQueryVariables, PaymentOptionInput, ProjectInput, TemplateOutput, + UserOutput, } 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'; +import { ADD_PROJECT, ADD_PROJECT_PROPOSAL } from '../../graphql/project.api'; +import { CREATE_USER, GET_ALL_USERS } from '../../graphql/admin.api'; +import { GET_COUNTRY_CODES } from '../../graphql/auth.api'; const AddProject = () => { const history = useHistory(); @@ -68,12 +90,66 @@ const AddProject = () => { chosenDeliverables, setChosenDeliverables, ] = useState(); - const [, setChosenPaymentOption] = 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 [newUser, setNewUser] = useState<{ + firstName: string; + lastName: string; + email: string; + password: string; + phone: { + prefix: string; + number: string; + }; + address: { + place: string; + city: string; + country: string; + zip: string; + }; + role: 'Client' | 'ProductOwner' | 'Developer'; + }>({ + firstName: '', + lastName: '', + email: '', + password: '', + phone: { + prefix: '', + number: '', + }, + address: { + place: '', + city: '', + country: '', + zip: '', + }, + role: 'Client', + }); + const [selectedSection, setSelectedSection] = useState< + 'general' | 'security' + >('general'); + const [countryCodes, setCountryCodes] = useState>( + [] + ); + const [client, setClient] = useState(); + const [proposal, setProposal] = useState<{ + devtime: { + months: number; + days: number; + hours: number; + }; + summary: string; + purpose: string; + resources: Array<{ resourceType: string; developers: number }>; + }>(); + const [developers, setDevelopers] = useState>([]); const [getCategories, { loading: categoriesLoading }] = useLazyQuery< GetAllCategoriesQuery, @@ -105,12 +181,65 @@ const AddProject = () => { fetchPolicy: 'network-only', }); + const [getDevelopers, { loading: developersLoading }] = useLazyQuery< + GetAllUsersQuery, + GetAllUsersQueryVariables + >(GET_ALL_USERS, { + onCompleted({ getAllUsers }) { + setDevelopers(getAllUsers.filter((user) => user.role === 'Developer')); + }, + fetchPolicy: 'network-only', + }); + + const [createUser, { loading: createUserLoading }] = useMutation< + CreateUserMutation, + CreateUserMutationVariables + >(CREATE_USER, { + onCompleted({ createUser: createdUser }) { + setClient(createdUser); + setStep('project-metadata'); + }, + onError({ graphQLErrors }) { + setError(graphQLErrors[0]?.extensions?.info); + setTimeout(() => setError(''), 3000); + }, + }); + + const [ + addProjectProposal, + { loading: addProjectProposalLoading }, + ] = useMutation< + AddProjectProposalMutation, + AddProjectProposalMutationVariables + >(ADD_PROJECT_PROPOSAL, { + onCompleted({ addProjectProposal: proposalData }) { + history.push(`/project/${proposalData.id}`); + }, + onError({ graphQLErrors }) { + setError(graphQLErrors[0].extensions?.info); + setTimeout(() => setError(''), 3000); + }, + }); + const [addProject, { loading: addProjectLoading }] = useMutation< AddProjectMutation, AddProjectMutationVariables >(ADD_PROJECT, { onCompleted({ addProject: projectData }) { - history.push(`/project/${projectData.id}`); + if (role === 'client') history.push(`/project/${projectData.id}`); + else { + addProjectProposal({ + variables: { + id: projectData.id, + proposal: { + devtime: proposal?.devtime!, + resources: proposal?.resources!, + summary: proposal?.summary!, + purpose: proposal?.summary!, + }, + }, + }); + } }, onError({ graphQLErrors }) { setError(graphQLErrors[0].extensions?.info); @@ -123,6 +252,8 @@ const AddProject = () => { if (step === 'template') getTemplates({ variables: { categories: chosenCategories } }); if (step === 'features') getFeatures(); + if (step === 'client-creation') getCountryCodes(); + if (step === 'project-metadata') getDevelopers(); // eslint-disable-next-line }, [step]); @@ -280,6 +411,181 @@ const AddProject = () => { }, }); + const clientCreationGeneralForm = useFormik({ + initialValues: { + firstName: '', + lastName: '', + email: '', + prefix: '', + number: '', + place: '', + city: '', + zip: '', + country: '', + }, + validationSchema: Yup.object().shape({ + firstName: Yup.string().required('First Name is required'), + lastName: Yup.string().required('Last Name is required'), + email: Yup.string() + .required('Email is required') + .email('Email is invalid'), + prefix: Yup.string().required('Prefix is required'), + // prettier-ignore + number: Yup.number().typeError('Phone must be a number').required('Phone is required'), + place: Yup.string().required('Address is required'), + city: Yup.string().required('City is required'), + country: Yup.string().required('Country is required'), + // prettier-ignore + zip: Yup.number().typeError('Zip must be a number').required('Zip is required'), + }), + onSubmit: ({ + firstName, + lastName, + email, + prefix, + number, + place, + city, + country, + zip, + }) => { + setNewUser({ + ...newUser, + firstName, + lastName, + email, + phone: { prefix, number }, + address: { place, city, country, zip }, + }); + setSelectedSection('security'); + }, + }); + + const [getCountryCodes, { loading: countryCodesLoading }] = useLazyQuery< + GetCountryCodesQuery, + GetCountryCodesQueryVariables + >(GET_COUNTRY_CODES, { + onCompleted({ getCountryCode }) { + setCountryCodes(getCountryCode); + clientCreationGeneralForm.setFieldValue( + 'prefix', + getCountryCode[0].prefix + ); + clientCreationGeneralForm.setFieldValue( + 'country', + getCountryCode[0].country + ); + }, + fetchPolicy: 'network-only', + }); + + const clientCreationSecurityForm = useFormik({ + initialValues: { + password: '', + confirmPassword: '', + }, + validationSchema: Yup.object().shape({ + password: Yup.string() + .required('Password is required') + .min(6, 'Password is 6 characters minimum'), + confirmPassword: Yup.string() + .required('Confirm password is required') + .oneOf( + [Yup.ref('password')], + "Confirm new password doesn't match with new password" + ), + }), + onSubmit: ({ password }) => { + setNewUser({ ...newUser, password }); + createUser({ variables: { user: { ...newUser, password } } }); + }, + }); + + const projectMetadataForm = useFormik<{ + frontendDevelopers: Array; + backendDevelopers: Array; + months: string; + summary: string; + purpose: string; + }>({ + initialValues: { + frontendDevelopers: [], + backendDevelopers: [], + months: '', + summary: '', + purpose: '', + }, + validationSchema: Yup.object().shape({ + summary: Yup.string().required('Summary is required'), + purpose: Yup.string().required('Purpose is required'), + // prettier-ignore + months: Yup.number().typeError('Months must be a number').required('Months is required'), + }), + onSubmit: ({ + frontendDevelopers, + backendDevelopers, + months, + summary, + purpose, + }) => { + if ( + !frontendDevelopers || + frontendDevelopers.length === 0 || + !backendDevelopers || + backendDevelopers.length === 0 + ) { + setError('You must select developers for your project'); + setTimeout(() => setError(''), 3000); + return; + } + setProposal({ + ...proposal, + devtime: { + months: parseInt(months, 10), + days: 0, + hours: 0, + }, + resources: [ + { + resourceType: 'frontend-developers', + developers: frontendDevelopers.length, + }, + { + resourceType: 'backend-developers', + developers: backendDevelopers.length, + }, + ], + summary, + purpose, + }); + 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: client?.id!, + platforms: chosenPlatforms, + delivrable: chosenDeliverables, + paymentOption: { + optOne: chosenPaymentOption?.optOne!, + optTwo: chosenPaymentOption?.optTwo!, + optThree: chosenPaymentOption?.optThree!, + }!, + totalPrice: chosenFeatures.reduce( + (accumulator, feature) => accumulator + feature.price, + 0 + ), + }, + }, + }); + }, + }); + const carouselSettings = { pagination: false, itemsToShow: 1, @@ -346,6 +652,8 @@ const AddProject = () => { {step === 'deliverables-platforms' && 'Choose Deliverables and Platforms'} {step === 'payment-options' && 'Choose Payment Options'} + {step === 'client-creation' && 'Create client'} + {step === 'project-metadata' && 'Set project metadata'} {error && } @@ -368,6 +676,7 @@ const AddProject = () => { if (step === 'deliverables-platforms') setStep('features'); if (step === 'payment-options') setStep('deliverables-platforms'); + if (step === 'project-metadata') setStep('client-creation'); }} /> @@ -378,7 +687,11 @@ const AddProject = () => { ? 'Save' : 'Next' } - loading={addProjectLoading} + loading={ + role === 'client' + ? addProjectLoading + : addProjectProposalLoading + } color={role || 'client'} variant='primary-action' iconRight={} @@ -391,6 +704,10 @@ const AddProject = () => { deliverablesPlatformsForm.handleSubmit(); if (step === 'payment-options') paymentOptionsForm.handleSubmit(); + if (step === 'client-creation') + clientCreationSecurityForm.handleSubmit(); + if (step === 'project-metadata') + projectMetadataForm.handleSubmit(); }} /> @@ -1139,6 +1456,501 @@ const AddProject = () => { )} + {step === 'client-creation' && ( + <> + + + } + color={role || 'client'} + text='General' + selected={selectedSection === 'general'} + /> + } + color={role || 'client'} + text='Security' + selected={selectedSection === 'security'} + /> + + + + + {selectedSection === 'general' ? 'General' : 'Security'} + + {error && } + + {selectedSection === 'general' && ( + <> + {!countryCodesLoading ? ( + + + + + + + + + + + + + +