import * as Yup from 'yup'; import { useFormik } from 'formik'; import { Navigate, useNavigate, useParams } from 'react-router'; import { useLazyQuery, useMutation, useQuery, useReactiveVar, } from '@apollo/client'; import React, { useEffect, useState } from 'react'; import { roleVar } from '../../graphql/state'; import { Box, Button, Text, SectionSelector, Input, Alert, TextArea, Select, Spinner, FeatureCard, Modal, } from '../../components'; import { Wrapper } from './styles'; import { ArrowLeft, General, Specification, Features } from '../../assets'; import { DeleteTemplateMutation, DeleteTemplateMutationVariables, FeatureOutput, GetAllCategoriesQuery, GetAllCategoriesQueryVariables, GetAllFeaturesQuery, GetAllFeaturesQueryVariables, GetTemplateByIdQuery, GetTemplateByIdQueryVariables, TemplateOutput, UpdateTemplateMutation, UpdateTemplateMutationVariables, } from '../../graphql/types'; import { DELETE_TEMPLATE, GET_TEMPLATE_BY_ID, UPDATE_TEMPLATE, } from '../../graphql/template.api'; import { GET_ALL_CATEGORIES } from '../../graphql/category.api'; import { GET_ALL_FEATURES } from '../../graphql/feature.api'; const TemplateSettings = () => { const navigate = useNavigate(); const { id } = useParams<{ id: string }>(); const role = useReactiveVar(roleVar); const [template, setTemplate] = useState({ id: '', name: '', description: '', image: { name: '', src: '', }, category: '', specification: { introduction: { purpose: '', documentConventions: '', intendedAudience: '', projectScope: '', }, overallDescription: { perspective: '', userCharacteristics: '', operatingEnvironment: '', designImplementationConstraints: '', userDocumentation: '', assemptionsDependencies: '', }, nonFunctionalRequirements: { performanceRequirements: '', safetyRequirements: '', securityRequirements: '', softwareQualityAttributes: '', }, otherRequirements: '', glossary: '', analysisModels: '', issuesList: '', }, features: [], }); const [availableFeatures, setAvailableFeatures] = useState>(); const [selectedSection, setSelectedSection] = useState< 'general' | 'specification' | 'features' >('general'); const [error, setError] = useState(''); const [success, setSuccess] = useState(false); const [deleteTemplateModal, setDeleteTemplateModal] = useState(false); const { data: categories, loading: categoriesLoading } = useQuery< GetAllCategoriesQuery, GetAllCategoriesQueryVariables >(GET_ALL_CATEGORIES); const [getFeatures, { loading: featuresLoading }] = useLazyQuery< GetAllFeaturesQuery, GetAllFeaturesQueryVariables >(GET_ALL_FEATURES, { onCompleted({ getAllFeatures }) { setAvailableFeatures(getAllFeatures); } }); const [getTemplate, { loading: templateLoading }] = useLazyQuery< GetTemplateByIdQuery, GetTemplateByIdQueryVariables >(GET_TEMPLATE_BY_ID, { onCompleted({ getTemplateById }) { setTemplate(getTemplateById); } }); const [updateTemplate, { loading }] = useMutation< UpdateTemplateMutation, UpdateTemplateMutationVariables >(UPDATE_TEMPLATE, { onCompleted({ updateTemplate: data }) { setTemplate(data); setSuccess(true); setTimeout(() => setSuccess(false), 3000); }, onError({ graphQLErrors }) { setError(graphQLErrors[0]?.extensions?.info as string); setTimeout(() => setError(''), 3000); }, }); const [deleteTemplate] = useMutation< DeleteTemplateMutation, DeleteTemplateMutationVariables >(DELETE_TEMPLATE, { onCompleted() { navigate('/template'); }, onError({ graphQLErrors }) { setError(graphQLErrors[0]?.extensions?.info as string); setTimeout(() => setError(''), 3000); }, }); useEffect(() => { getTemplate({ variables: { id: id as string } }); getFeatures(); // eslint-disable-next-line }, [id]); const generalForm = useFormik({ initialValues: { name: template.name || '', description: template.description || '', imageName: template.image.name || '', imageSource: template.image.src || '', category: template.category || '', }, validationSchema: Yup.object().shape({ name: Yup.string().required('Name is required'), description: Yup.string().required('Description is required'), imageName: Yup.string().required('Image is required'), imageSource: Yup.string().required('Image is required'), category: Yup.string().required('Category is required'), }), onSubmit: ({ name, description, category, imageName, imageSource }) => { setTemplate({ ...template, name, description, image: { name: imageName, src: imageSource }, category, }); updateTemplate({ variables: { id: id as string, template: { name, description, category, image: { name: imageName, src: imageSource, }, features: template.features?.map((feature) => feature.id), }, specification: { introduction: { purpose: template.specification?.introduction.purpose!, documentConventions: template.specification?.introduction.documentConventions!, intendedAudience: template.specification?.introduction.intendedAudience!, projectScope: template.specification?.introduction.projectScope!, }, overallDescription: { perspective: template.specification?.overallDescription.perspective!, userCharacteristics: template.specification?.overallDescription.userCharacteristics!, operatingEnvironment: template.specification?.overallDescription .operatingEnvironment!, designImplementationConstraints: template.specification?.overallDescription .designImplementationConstraints!, userDocumentation: template.specification?.overallDescription.userDocumentation!, assemptionsDependencies: template.specification?.overallDescription .assemptionsDependencies!, }, nonFunctionalRequirements: { performanceRequirements: template.specification?.nonFunctionalRequirements .performanceRequirements!, safetyRequirements: template.specification?.nonFunctionalRequirements .safetyRequirements!, securityRequirements: template.specification?.nonFunctionalRequirements .securityRequirements!, softwareQualityAttributes: template.specification?.nonFunctionalRequirements .softwareQualityAttributes!, }, otherRequirements: template.specification?.otherRequirements!, glossary: template.specification?.glossary!, analysisModels: template.specification?.analysisModels!, issuesList: template.specification?.issuesList!, }, }, }); }, enableReinitialize: true, }); const specificationForm = useFormik({ initialValues: { purpose: template.specification?.introduction.purpose || '', documentConventions: template.specification?.introduction.documentConventions || '', intendedAudience: template.specification?.introduction.intendedAudience || '', projectScope: template.specification?.introduction.projectScope || '', perspective: template.specification?.overallDescription.perspective || '', userCharacteristics: template.specification?.overallDescription.userCharacteristics || '', operatingEnvironment: template.specification?.overallDescription.operatingEnvironment || '', designImplementationConstraints: template.specification?.overallDescription .designImplementationConstraints || '', userDocumentation: template.specification?.overallDescription.userDocumentation || '', assemptionsDependencies: template.specification?.overallDescription.assemptionsDependencies || '', performanceRequirements: template.specification?.nonFunctionalRequirements .performanceRequirements || '', safetyRequirements: template.specification?.nonFunctionalRequirements.safetyRequirements || '', securityRequirements: template.specification?.nonFunctionalRequirements .securityRequirements || '', softwareQualityAttributes: template.specification?.nonFunctionalRequirements .softwareQualityAttributes || '', otherRequirements: template.specification?.otherRequirements || '', glossary: template.specification?.glossary || '', analysisModels: template.specification?.analysisModels || '', issuesList: template.specification?.issuesList || '', }, validationSchema: Yup.object().shape({ purpose: Yup.string().required('Purpose is required'), documentConventions: Yup.string().required( 'Document conventions is required' ), intendedAudience: Yup.string().required('Intented audience is required'), projectScope: Yup.string().required('Project scope is required'), perspective: Yup.string().required('Perspective is required'), userCharacteristics: Yup.string().required( 'User characteristics is required' ), operatingEnvironment: Yup.string().required( 'Operating environment is required' ), designImplementationConstraints: Yup.string().required( 'Design and implementation constraints is required' ), userDocumentation: Yup.string().required( 'User documentation is required' ), assemptionsDependencies: Yup.string().required( 'Assumptions and dependencies is required' ), performanceRequirements: Yup.string().required( 'Performance requirements is required' ), safetyRequirements: Yup.string().required( 'Safety requirements is required' ), securityRequirements: Yup.string().required( 'Security requirements is required' ), softwareQualityAttributes: Yup.string().required( 'Software quality attributes is required' ), otherRequirements: Yup.string().required( 'Other requirements is required' ), glossary: Yup.string().required('Glossary is required'), analysisModels: Yup.string().required('Analysis models is required'), issuesList: Yup.string().required('Issues list is required'), }), onSubmit: ({ purpose, documentConventions, intendedAudience, projectScope, perspective, userCharacteristics, operatingEnvironment, designImplementationConstraints, userDocumentation, assemptionsDependencies, performanceRequirements, safetyRequirements, securityRequirements, softwareQualityAttributes, otherRequirements, glossary, analysisModels, issuesList, }) => { setTemplate({ ...template, specification: { introduction: { purpose, documentConventions, intendedAudience, projectScope, }, overallDescription: { perspective, userCharacteristics, operatingEnvironment, designImplementationConstraints, userDocumentation, assemptionsDependencies, }, nonFunctionalRequirements: { performanceRequirements, safetyRequirements, securityRequirements, softwareQualityAttributes, }, otherRequirements, glossary, analysisModels, issuesList, }, }); updateTemplate({ variables: { id: id as string, template: { name: template.name, description: template.description, category: template.category, image: { name: template.image.name, src: template.image.src, }, features: template.features?.map((feature) => feature.id), }, specification: { introduction: { purpose, documentConventions, intendedAudience, projectScope, }, overallDescription: { perspective, userCharacteristics, operatingEnvironment, designImplementationConstraints, userDocumentation, assemptionsDependencies, }, nonFunctionalRequirements: { performanceRequirements, safetyRequirements, securityRequirements, softwareQualityAttributes, }, otherRequirements, glossary, analysisModels, issuesList, }, }, }); }, enableReinitialize: true, }); const featuresForm = useFormik<{ features: Array }>({ initialValues: { features: template.features?.map((feature) => feature.id) || [], }, onSubmit: ({ features }) => { updateTemplate({ variables: { id: id as string, template: { name: template.name, description: template.description, category: template.category, image: { name: template.image.name, src: template.image.src, }, features, }, specification: { introduction: { purpose: template.specification?.introduction.purpose!, documentConventions: template.specification?.introduction.documentConventions!, intendedAudience: template.specification?.introduction.intendedAudience!, projectScope: template.specification?.introduction.projectScope!, }, overallDescription: { perspective: template.specification?.overallDescription.perspective!, userCharacteristics: template.specification?.overallDescription.userCharacteristics!, operatingEnvironment: template.specification?.overallDescription .operatingEnvironment!, designImplementationConstraints: template.specification?.overallDescription .designImplementationConstraints!, userDocumentation: template.specification?.overallDescription.userDocumentation!, assemptionsDependencies: template.specification?.overallDescription .assemptionsDependencies!, }, nonFunctionalRequirements: { performanceRequirements: template.specification?.nonFunctionalRequirements .performanceRequirements!, safetyRequirements: template.specification?.nonFunctionalRequirements .safetyRequirements!, securityRequirements: template.specification?.nonFunctionalRequirements .securityRequirements!, softwareQualityAttributes: template.specification?.nonFunctionalRequirements .softwareQualityAttributes!, }, otherRequirements: template.specification?.otherRequirements!, glossary: template.specification?.glossary!, analysisModels: template.specification?.analysisModels!, issuesList: template.specification?.issuesList!, }, }, }); }, enableReinitialize: true, }); return role === 'productOwner' ? (