mirror of
https://github.com/hazemKrimi/crimson-quirks-ui.git
synced 2026-05-01 18:20:28 +00:00
Update add project page
This commit is contained in:
@@ -14,15 +14,30 @@ import {
|
|||||||
CategoryCard,
|
CategoryCard,
|
||||||
FeatureCard,
|
FeatureCard,
|
||||||
Input,
|
Input,
|
||||||
|
SectionSelector,
|
||||||
|
Select,
|
||||||
Spinner,
|
Spinner,
|
||||||
TemplateCard,
|
TemplateCard,
|
||||||
Text,
|
Text,
|
||||||
|
TextArea,
|
||||||
} from '../../components';
|
} from '../../components';
|
||||||
import { ArrowLeft, ArrowRight, ChevronLeft, ChevronRight } from '../../assets';
|
import {
|
||||||
|
ArrowLeft,
|
||||||
|
ArrowRight,
|
||||||
|
ChevronLeft,
|
||||||
|
ChevronRight,
|
||||||
|
Profile,
|
||||||
|
Security,
|
||||||
|
} from '../../assets';
|
||||||
import {
|
import {
|
||||||
AddProjectMutation,
|
AddProjectMutation,
|
||||||
AddProjectMutationVariables,
|
AddProjectMutationVariables,
|
||||||
|
AddProjectProposalMutation,
|
||||||
|
AddProjectProposalMutationVariables,
|
||||||
CategoryOutput,
|
CategoryOutput,
|
||||||
|
CountryPrefixModel,
|
||||||
|
CreateUserMutation,
|
||||||
|
CreateUserMutationVariables,
|
||||||
DelivrableInput,
|
DelivrableInput,
|
||||||
FeatureOutput,
|
FeatureOutput,
|
||||||
GetAllCategoriesQuery,
|
GetAllCategoriesQuery,
|
||||||
@@ -31,15 +46,22 @@ import {
|
|||||||
GetAllFeaturesQueryVariables,
|
GetAllFeaturesQueryVariables,
|
||||||
GetAllTemplatesByCategoriesIdQuery,
|
GetAllTemplatesByCategoriesIdQuery,
|
||||||
GetAllTemplatesByCategoriesIdQueryVariables,
|
GetAllTemplatesByCategoriesIdQueryVariables,
|
||||||
|
GetAllUsersQuery,
|
||||||
|
GetAllUsersQueryVariables,
|
||||||
|
GetCountryCodesQuery,
|
||||||
|
GetCountryCodesQueryVariables,
|
||||||
PaymentOptionInput,
|
PaymentOptionInput,
|
||||||
ProjectInput,
|
ProjectInput,
|
||||||
TemplateOutput,
|
TemplateOutput,
|
||||||
|
UserOutput,
|
||||||
} from '../../graphql/types';
|
} from '../../graphql/types';
|
||||||
import { theme } from '../../themes';
|
import { theme } from '../../themes';
|
||||||
import { GET_ALL_CATEGORIES } from '../../graphql/category.api';
|
import { GET_ALL_CATEGORIES } from '../../graphql/category.api';
|
||||||
import { GET_ALL_TEMPLATES_BY_CATEGORIES_ID } from '../../graphql/template.api';
|
import { GET_ALL_TEMPLATES_BY_CATEGORIES_ID } from '../../graphql/template.api';
|
||||||
import { GET_ALL_FEATURES } from '../../graphql/feature.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 AddProject = () => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@@ -68,12 +90,66 @@ const AddProject = () => {
|
|||||||
chosenDeliverables,
|
chosenDeliverables,
|
||||||
setChosenDeliverables,
|
setChosenDeliverables,
|
||||||
] = useState<DelivrableInput>();
|
] = useState<DelivrableInput>();
|
||||||
const [, setChosenPaymentOption] = useState<PaymentOptionInput>();
|
const [
|
||||||
|
chosenPaymentOption,
|
||||||
|
setChosenPaymentOption,
|
||||||
|
] = useState<PaymentOptionInput>();
|
||||||
const [chosenPlatforms, setChosenPlatforms] = useState<Array<string>>([]);
|
const [chosenPlatforms, setChosenPlatforms] = useState<Array<string>>([]);
|
||||||
const [selectedFeature, setSelectedFeature] = useState<FeatureOutput>();
|
const [selectedFeature, setSelectedFeature] = useState<FeatureOutput>();
|
||||||
const [categories, setCategories] = useState<Array<CategoryOutput>>([]);
|
const [categories, setCategories] = useState<Array<CategoryOutput>>([]);
|
||||||
const [templates, setTemplates] = useState<Array<TemplateOutput>>([]);
|
const [templates, setTemplates] = useState<Array<TemplateOutput>>([]);
|
||||||
const [features, setFeatures] = useState<Array<FeatureOutput>>([]);
|
const [features, setFeatures] = useState<Array<FeatureOutput>>([]);
|
||||||
|
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<Array<CountryPrefixModel>>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const [client, setClient] = useState<UserOutput>();
|
||||||
|
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<Array<UserOutput>>([]);
|
||||||
|
|
||||||
const [getCategories, { loading: categoriesLoading }] = useLazyQuery<
|
const [getCategories, { loading: categoriesLoading }] = useLazyQuery<
|
||||||
GetAllCategoriesQuery,
|
GetAllCategoriesQuery,
|
||||||
@@ -105,12 +181,65 @@ const AddProject = () => {
|
|||||||
fetchPolicy: 'network-only',
|
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<
|
const [addProject, { loading: addProjectLoading }] = useMutation<
|
||||||
AddProjectMutation,
|
AddProjectMutation,
|
||||||
AddProjectMutationVariables
|
AddProjectMutationVariables
|
||||||
>(ADD_PROJECT, {
|
>(ADD_PROJECT, {
|
||||||
onCompleted({ addProject: projectData }) {
|
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 }) {
|
onError({ graphQLErrors }) {
|
||||||
setError(graphQLErrors[0].extensions?.info);
|
setError(graphQLErrors[0].extensions?.info);
|
||||||
@@ -123,6 +252,8 @@ const AddProject = () => {
|
|||||||
if (step === 'template')
|
if (step === 'template')
|
||||||
getTemplates({ variables: { categories: chosenCategories } });
|
getTemplates({ variables: { categories: chosenCategories } });
|
||||||
if (step === 'features') getFeatures();
|
if (step === 'features') getFeatures();
|
||||||
|
if (step === 'client-creation') getCountryCodes();
|
||||||
|
if (step === 'project-metadata') getDevelopers();
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [step]);
|
}, [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<string>;
|
||||||
|
backendDevelopers: Array<string>;
|
||||||
|
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 = {
|
const carouselSettings = {
|
||||||
pagination: false,
|
pagination: false,
|
||||||
itemsToShow: 1,
|
itemsToShow: 1,
|
||||||
@@ -346,6 +652,8 @@ const AddProject = () => {
|
|||||||
{step === 'deliverables-platforms' &&
|
{step === 'deliverables-platforms' &&
|
||||||
'Choose Deliverables and Platforms'}
|
'Choose Deliverables and Platforms'}
|
||||||
{step === 'payment-options' && 'Choose Payment Options'}
|
{step === 'payment-options' && 'Choose Payment Options'}
|
||||||
|
{step === 'client-creation' && 'Create client'}
|
||||||
|
{step === 'project-metadata' && 'Set project metadata'}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
{error && <Alert color='error' text={error} />}
|
{error && <Alert color='error' text={error} />}
|
||||||
@@ -368,6 +676,7 @@ const AddProject = () => {
|
|||||||
if (step === 'deliverables-platforms') setStep('features');
|
if (step === 'deliverables-platforms') setStep('features');
|
||||||
if (step === 'payment-options')
|
if (step === 'payment-options')
|
||||||
setStep('deliverables-platforms');
|
setStep('deliverables-platforms');
|
||||||
|
if (step === 'project-metadata') setStep('client-creation');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -378,7 +687,11 @@ const AddProject = () => {
|
|||||||
? 'Save'
|
? 'Save'
|
||||||
: 'Next'
|
: 'Next'
|
||||||
}
|
}
|
||||||
loading={addProjectLoading}
|
loading={
|
||||||
|
role === 'client'
|
||||||
|
? addProjectLoading
|
||||||
|
: addProjectProposalLoading
|
||||||
|
}
|
||||||
color={role || 'client'}
|
color={role || 'client'}
|
||||||
variant='primary-action'
|
variant='primary-action'
|
||||||
iconRight={<ArrowRight />}
|
iconRight={<ArrowRight />}
|
||||||
@@ -391,6 +704,10 @@ const AddProject = () => {
|
|||||||
deliverablesPlatformsForm.handleSubmit();
|
deliverablesPlatformsForm.handleSubmit();
|
||||||
if (step === 'payment-options')
|
if (step === 'payment-options')
|
||||||
paymentOptionsForm.handleSubmit();
|
paymentOptionsForm.handleSubmit();
|
||||||
|
if (step === 'client-creation')
|
||||||
|
clientCreationSecurityForm.handleSubmit();
|
||||||
|
if (step === 'project-metadata')
|
||||||
|
projectMetadataForm.handleSubmit();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -1139,6 +1456,501 @@ const AddProject = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
|
{step === 'client-creation' && (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='0.5fr 2fr'
|
||||||
|
columnGap='25px'
|
||||||
|
marginTop='1rem'
|
||||||
|
>
|
||||||
|
<Box display='grid' rowGap='0.5rem' gridTemplateRows='50px'>
|
||||||
|
<SectionSelector
|
||||||
|
icon={<Profile />}
|
||||||
|
color={role || 'client'}
|
||||||
|
text='General'
|
||||||
|
selected={selectedSection === 'general'}
|
||||||
|
/>
|
||||||
|
<SectionSelector
|
||||||
|
icon={<Security />}
|
||||||
|
color={role || 'client'}
|
||||||
|
text='Security'
|
||||||
|
selected={selectedSection === 'security'}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
background='white'
|
||||||
|
boxShadow='1px 1px 10px 0px rgba(50, 59, 105, 0.25)'
|
||||||
|
borderRadius='10px'
|
||||||
|
width='100%'
|
||||||
|
padding='30px'
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='auto 1fr'
|
||||||
|
columnGap='1rem'
|
||||||
|
alignItems='center'
|
||||||
|
marginBottom='50px'
|
||||||
|
>
|
||||||
|
<Text variant='subheader' weight='bold'>
|
||||||
|
{selectedSection === 'general' ? 'General' : 'Security'}
|
||||||
|
</Text>
|
||||||
|
{error && <Alert color='error' text={error} />}
|
||||||
|
</Box>
|
||||||
|
{selectedSection === 'general' && (
|
||||||
|
<>
|
||||||
|
{!countryCodesLoading ? (
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='auto'
|
||||||
|
rowGap='0.5rem'
|
||||||
|
position='relative'
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
name='firstName'
|
||||||
|
label='First Name'
|
||||||
|
color={role || 'client'}
|
||||||
|
value={clientCreationGeneralForm.values.firstName}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.firstName &&
|
||||||
|
!!clientCreationGeneralForm.errors.firstName
|
||||||
|
}
|
||||||
|
errorMessage={
|
||||||
|
clientCreationGeneralForm.errors.firstName
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name='lastName'
|
||||||
|
label='Last Name'
|
||||||
|
color={role || 'client'}
|
||||||
|
value={clientCreationGeneralForm.values.lastName}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.lastName &&
|
||||||
|
!!clientCreationGeneralForm.errors.lastName
|
||||||
|
}
|
||||||
|
errorMessage={
|
||||||
|
clientCreationGeneralForm.errors.lastName
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name='email'
|
||||||
|
label='Email'
|
||||||
|
color={role || 'client'}
|
||||||
|
value={clientCreationGeneralForm.values.email}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.email &&
|
||||||
|
!!clientCreationGeneralForm.errors.email
|
||||||
|
}
|
||||||
|
errorMessage={clientCreationGeneralForm.errors.email}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='1fr 1.5fr'
|
||||||
|
columnGap='10px'
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
name='prefix'
|
||||||
|
label='Country Code'
|
||||||
|
color={role || 'client'}
|
||||||
|
options={
|
||||||
|
countryCodes
|
||||||
|
? countryCodes.map(({ prefix, country }) => ({
|
||||||
|
value: prefix,
|
||||||
|
label: `+${prefix} (${country})`,
|
||||||
|
}))
|
||||||
|
: [{ value: '216', label: '+216' }]
|
||||||
|
}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
value={clientCreationGeneralForm.values.prefix}
|
||||||
|
select={clientCreationGeneralForm.values.prefix}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.prefix &&
|
||||||
|
!!clientCreationGeneralForm.errors.prefix
|
||||||
|
}
|
||||||
|
errorMessage={
|
||||||
|
clientCreationGeneralForm.errors.prefix
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name='number'
|
||||||
|
type='tel'
|
||||||
|
label='Phone'
|
||||||
|
color={role || 'client'}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
value={clientCreationGeneralForm.values.number}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.number &&
|
||||||
|
!!clientCreationGeneralForm.errors.number
|
||||||
|
}
|
||||||
|
errorMessage={
|
||||||
|
clientCreationGeneralForm.errors.number
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Input
|
||||||
|
name='place'
|
||||||
|
label='Address'
|
||||||
|
color={role || 'client'}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
value={clientCreationGeneralForm.values.place}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.place &&
|
||||||
|
!!clientCreationGeneralForm.errors.place
|
||||||
|
}
|
||||||
|
errorMessage={clientCreationGeneralForm.errors.place}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name='city'
|
||||||
|
label='City'
|
||||||
|
color={role || 'client'}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
value={clientCreationGeneralForm.values.city}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.city &&
|
||||||
|
!!clientCreationGeneralForm.errors.city
|
||||||
|
}
|
||||||
|
errorMessage={clientCreationGeneralForm.errors.city}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='2fr 1fr'
|
||||||
|
columnGap='10px'
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
name='country'
|
||||||
|
label='Country'
|
||||||
|
color={role || 'client'}
|
||||||
|
options={
|
||||||
|
countryCodes
|
||||||
|
? countryCodes.map(({ country }) => ({
|
||||||
|
value: country,
|
||||||
|
label: country,
|
||||||
|
}))
|
||||||
|
: [{ value: 'Tunisia', label: 'Tunisia' }]
|
||||||
|
}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
value={clientCreationGeneralForm.values.country}
|
||||||
|
select={clientCreationGeneralForm.values.country}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.country &&
|
||||||
|
!!clientCreationGeneralForm.errors.country
|
||||||
|
}
|
||||||
|
errorMessage={
|
||||||
|
clientCreationGeneralForm.errors.country
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name='zip'
|
||||||
|
label='Zip Code'
|
||||||
|
color={role || 'client'}
|
||||||
|
onChange={clientCreationGeneralForm.handleChange}
|
||||||
|
onBlur={clientCreationGeneralForm.handleBlur}
|
||||||
|
value={clientCreationGeneralForm.values.zip}
|
||||||
|
error={
|
||||||
|
clientCreationGeneralForm.touched.zip &&
|
||||||
|
!!clientCreationGeneralForm.errors.zip
|
||||||
|
}
|
||||||
|
errorMessage={clientCreationGeneralForm.errors.zip}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
marginTop='0.5rem'
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='repeat(2, auto)'
|
||||||
|
justifyContent='flex-end'
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant='primary-action'
|
||||||
|
color={role || 'client'}
|
||||||
|
text='Next'
|
||||||
|
onClick={clientCreationGeneralForm.handleSubmit}
|
||||||
|
type='submit'
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
alignItems='center'
|
||||||
|
justifyContent='center'
|
||||||
|
>
|
||||||
|
<Spinner color={role || 'client'} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{selectedSection === 'security' && (
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='auto'
|
||||||
|
rowGap='0.5rem'
|
||||||
|
position='relative'
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
name='password'
|
||||||
|
label='Password'
|
||||||
|
color={role || 'client'}
|
||||||
|
type='password'
|
||||||
|
value={clientCreationSecurityForm.values.password}
|
||||||
|
onChange={clientCreationSecurityForm.handleChange}
|
||||||
|
onBlur={clientCreationSecurityForm.handleBlur}
|
||||||
|
error={
|
||||||
|
clientCreationSecurityForm.touched.password &&
|
||||||
|
!!clientCreationSecurityForm.errors.password
|
||||||
|
}
|
||||||
|
errorMessage={clientCreationSecurityForm.errors.password}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name='confirmPassword'
|
||||||
|
label='Confirm Password'
|
||||||
|
color={role || 'client'}
|
||||||
|
type='password'
|
||||||
|
value={clientCreationSecurityForm.values.confirmPassword}
|
||||||
|
onChange={clientCreationSecurityForm.handleChange}
|
||||||
|
onBlur={clientCreationSecurityForm.handleBlur}
|
||||||
|
error={
|
||||||
|
clientCreationSecurityForm.touched.confirmPassword &&
|
||||||
|
!!clientCreationSecurityForm.errors.confirmPassword
|
||||||
|
}
|
||||||
|
errorMessage={
|
||||||
|
clientCreationSecurityForm.errors.confirmPassword
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
marginTop='0.5rem'
|
||||||
|
display='flex'
|
||||||
|
justifyContent='flex-end'
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
marginRight='15px'
|
||||||
|
display='flex'
|
||||||
|
alignItems='center'
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
color={role || 'client'}
|
||||||
|
text='Previous'
|
||||||
|
type='submit'
|
||||||
|
onClick={() => setSelectedSection('general')}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
variant='primary-action'
|
||||||
|
color={role || 'client'}
|
||||||
|
text='Create'
|
||||||
|
type='submit'
|
||||||
|
onClick={clientCreationSecurityForm.handleSubmit}
|
||||||
|
loading={createUserLoading}
|
||||||
|
disabled={createUserLoading}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{step === 'project-metadata' && (
|
||||||
|
<>
|
||||||
|
{!developersLoading ? (
|
||||||
|
<form>
|
||||||
|
<Box>
|
||||||
|
<Box marginBottom='20px'>
|
||||||
|
<Text variant='headline' weight='bold' gutterBottom>
|
||||||
|
Assign frontend Developers
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='repeat(4, 1fr)'
|
||||||
|
alignItems='center'
|
||||||
|
columnGap='30px'
|
||||||
|
marginBottom='20px'
|
||||||
|
>
|
||||||
|
{developers &&
|
||||||
|
developers.map((developer) => (
|
||||||
|
<Box
|
||||||
|
padding='10px'
|
||||||
|
background='white'
|
||||||
|
boxShadow='1px 1px 10px rgba(50, 59, 105, 0.25)'
|
||||||
|
onClick={() => {
|
||||||
|
if (
|
||||||
|
projectMetadataForm.values.frontendDevelopers &&
|
||||||
|
!projectMetadataForm.values.frontendDevelopers.includes(
|
||||||
|
developer.id
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
projectMetadataForm.setFieldValue(
|
||||||
|
'frontendDevelopers',
|
||||||
|
projectMetadataForm.values.frontendDevelopers.concat(
|
||||||
|
developer.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
projectMetadataForm.setFieldValue(
|
||||||
|
'frontendDevelopers',
|
||||||
|
projectMetadataForm.values.frontendDevelopers &&
|
||||||
|
projectMetadataForm.values.frontendDevelopers.filter(
|
||||||
|
(id) => id !== developer.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
border={
|
||||||
|
projectMetadataForm.values.frontendDevelopers.includes(
|
||||||
|
developer.id
|
||||||
|
)
|
||||||
|
? `2px solid ${
|
||||||
|
theme.colors[role || 'client'].main
|
||||||
|
}`
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
display='grid'
|
||||||
|
gridTemplateRows='auto'
|
||||||
|
alignItems='center'
|
||||||
|
rowGap='10px'
|
||||||
|
borderRadius='10px'
|
||||||
|
cursor='pointer'
|
||||||
|
>
|
||||||
|
<Text variant='title' weight='bold'>
|
||||||
|
{developer.firstName} {developer.lastName}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Box marginBottom='20px'>
|
||||||
|
<Text variant='headline' weight='bold' gutterBottom>
|
||||||
|
Assign backend Developers
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='repeat(4, 1fr)'
|
||||||
|
alignItems='center'
|
||||||
|
columnGap='30px'
|
||||||
|
marginBottom='20px'
|
||||||
|
>
|
||||||
|
{developers &&
|
||||||
|
developers.map((developer) => (
|
||||||
|
<Box
|
||||||
|
padding='10px'
|
||||||
|
background='white'
|
||||||
|
boxShadow='1px 1px 10px rgba(50, 59, 105, 0.25)'
|
||||||
|
onClick={() => {
|
||||||
|
if (
|
||||||
|
projectMetadataForm.values.backendDevelopers &&
|
||||||
|
!projectMetadataForm.values.backendDevelopers.includes(
|
||||||
|
developer.id
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
projectMetadataForm.setFieldValue(
|
||||||
|
'backendDevelopers',
|
||||||
|
projectMetadataForm.values.backendDevelopers.concat(
|
||||||
|
developer.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
projectMetadataForm.setFieldValue(
|
||||||
|
'backendDevelopers',
|
||||||
|
projectMetadataForm.values.backendDevelopers &&
|
||||||
|
projectMetadataForm.values.backendDevelopers.filter(
|
||||||
|
(id) => id !== developer.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
border={
|
||||||
|
projectMetadataForm.values.backendDevelopers.includes(
|
||||||
|
developer.id
|
||||||
|
)
|
||||||
|
? `2px solid ${
|
||||||
|
theme.colors[role || 'client'].main
|
||||||
|
}`
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
display='grid'
|
||||||
|
gridTemplateRows='auto'
|
||||||
|
alignItems='center'
|
||||||
|
rowGap='10px'
|
||||||
|
borderRadius='10px'
|
||||||
|
cursor='pointer'
|
||||||
|
>
|
||||||
|
<Text variant='title' weight='bold'>
|
||||||
|
{developer.firstName} {developer.lastName}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Box marginBottom='20px'>
|
||||||
|
<Text variant='headline' weight='bold' gutterBottom>
|
||||||
|
Define metadata
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
display='grid'
|
||||||
|
gridTemplateColumns='1fr'
|
||||||
|
alignItems='center'
|
||||||
|
rowGap='30px'
|
||||||
|
marginBottom='20px'
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
name='purpose'
|
||||||
|
label='Purpose'
|
||||||
|
value={projectMetadataForm.values.purpose}
|
||||||
|
onChange={projectMetadataForm.handleChange}
|
||||||
|
onBlur={projectMetadataForm.handleBlur}
|
||||||
|
error={
|
||||||
|
projectMetadataForm.touched.purpose &&
|
||||||
|
!!projectMetadataForm.errors.purpose
|
||||||
|
}
|
||||||
|
errorMessage={projectMetadataForm.errors.purpose}
|
||||||
|
/>
|
||||||
|
<TextArea
|
||||||
|
name='summary'
|
||||||
|
label='Summary'
|
||||||
|
value={projectMetadataForm.values.summary}
|
||||||
|
onChange={projectMetadataForm.handleChange}
|
||||||
|
onBlur={projectMetadataForm.handleBlur}
|
||||||
|
error={
|
||||||
|
projectMetadataForm.touched.summary &&
|
||||||
|
!!projectMetadataForm.errors.summary
|
||||||
|
}
|
||||||
|
errorMessage={projectMetadataForm.errors.summary}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name='months'
|
||||||
|
label='Months'
|
||||||
|
value={projectMetadataForm.values.months}
|
||||||
|
onChange={projectMetadataForm.handleChange}
|
||||||
|
onBlur={projectMetadataForm.handleBlur}
|
||||||
|
error={
|
||||||
|
projectMetadataForm.touched.months &&
|
||||||
|
!!projectMetadataForm.errors.months
|
||||||
|
}
|
||||||
|
errorMessage={projectMetadataForm.errors.months}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<Spinner fullScreen color={role} />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user