• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alkem-io / client-web / #7240

09 Apr 2024 02:41PM UTC coverage: 5.834%. First build
#7240

Pull #5793

travis-ci

Pull Request #5793: Spaces api: space settings replacing preferences space + challenge; account - space relationship

183 of 8908 branches covered (2.05%)

Branch coverage included in aggregate %.

25 of 164 new or added lines in 29 files covered. (15.24%)

1295 of 16426 relevant lines covered (7.88%)

0.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/domain/community/community/CommunityApplicationForm/CommunityApplicationForm.tsx
1
import { useMemo } from 'react';
2
import { Formik } from 'formik';
3
import * as yup from 'yup';
4
import { useTranslation } from 'react-i18next';
5
import { Box, IconButton, Tooltip } from '@mui/material';
6
import AddIcon from '@mui/icons-material/Add';
7
import { max, pullAt, slice, sortBy } from 'lodash';
8
import { BlockSectionTitle } from '@/core/ui/typography';
9
import {
10
  refetchRoleSetApplicationFormQuery,
11
  useRoleSetApplicationFormQuery,
12
  useUpdateApplicationFormOnRoleSetMutation,
13
} from '@/core/apollo/generated/apollo-hooks';
14
import FormikMarkdownField from '@/core/ui/forms/MarkdownInput/FormikMarkdownField';
15
import FormQuestionField, { questionSchema } from './views/FormQuestionField';
16
import FormikSubmitButton from '@/domain/shared/components/forms/FormikSubmitButton';
17
import { useNotification } from '@/core/ui/notifications/useNotification';
18
import Gutters from '@/core/ui/grid/Gutters';
19
import MarkdownValidator from '@/core/ui/forms/MarkdownInput/MarkdownValidator';
20
import { MARKDOWN_TEXT_LENGTH } from '@/core/ui/forms/field-length.constants';
21

22
interface CommunityApplicationFormProps {
23
  roleSetId: string;
24
  disabled?: boolean;
25
}
26

27
interface FormValues {
28
  description: string;
29
  questions: {
30
    question: string;
31
    required: boolean;
32
    sortOrder: number;
33
  }[];
34
}
35

36
const validationSchema = yup.object().shape({
×
37
  description: MarkdownValidator(MARKDOWN_TEXT_LENGTH, { required: true }),
38
  questions: yup.array().of(questionSchema),
39
});
40

41
// Returns a new question object with a sortOrder calculated from the other questions
42
const newQuestion = (currentQuestions: FormValues['questions']) => ({
×
43
  question: '',
44
  required: false,
45
  sortOrder: (max(currentQuestions.map(q => q.sortOrder)) ?? 0) + 1,
×
46
});
47

NEW
48
const CommunityApplicationForm = ({ roleSetId, disabled }: CommunityApplicationFormProps) => {
×
49
  const { t } = useTranslation();
×
50
  const notify = useNotification();
×
51

52
  const { data: rawData, loading: loadingQuestions } = useRoleSetApplicationFormQuery({
×
53
    variables: {
54
      roleSetId,
55
    },
56
    skip: !roleSetId,
57
  });
58

59
  const data = useMemo(
×
60
    () => ({
×
61
      description: rawData?.lookup?.roleSet?.applicationForm?.description,
NEW
62
      questions: sortBy(rawData?.lookup?.roleSet?.applicationForm?.questions, q => q.sortOrder),
×
63
    }),
64
    [roleSetId, rawData]
65
  );
66

67
  const [updateQuestions, { loading: submittingQuestions }] = useUpdateApplicationFormOnRoleSetMutation();
×
68

69
  const loading = loadingQuestions || submittingQuestions;
×
70
  const initialValues: FormValues = {
×
71
    description: data.description ?? '',
×
72
    questions: data.questions ?? [],
×
73
  };
74

75
  const onSubmit = (values: FormValues) => {
×
76
    // Recompute sortOrder and add missing properties before submitting:
77
    const questions = values.questions.map((q, index) => ({
×
78
      ...q,
79
      sortOrder: index + 1,
80
      explanation: '',
81
      maxLength: 500, // Server defaults to 500
82
    }));
83

84
    updateQuestions({
×
85
      variables: {
86
        roleSetId: roleSetId!,
87
        formData: {
88
          description: values.description,
89
          questions,
90
        },
91
      },
92
      onCompleted: () => notify(t('community.application-form.updated-successfully'), 'success'),
×
93
      awaitRefetchQueries: true,
94
      refetchQueries: [
95
        refetchRoleSetApplicationFormQuery({
96
          roleSetId: roleSetId!,
97
        }),
98
      ],
99
    });
100
  };
101

102
  return (
×
103
    <Formik initialValues={initialValues} validationSchema={validationSchema} enableReinitialize onSubmit={onSubmit}>
104
      {({ values: { questions }, setFieldValue, handleSubmit }) => {
105
        const handleAdd = () => {
×
106
          const newArray = [...questions, newQuestion(questions)];
×
107
          setFieldValue('questions', newArray);
×
108
        };
109
        const handleDelete = (index: number) => {
×
110
          const nextQuestions = [...questions];
×
111
          pullAt(nextQuestions, index);
×
112
          setFieldValue('questions', nextQuestions);
×
113
        };
114
        const handleMoveUp = (index: number) => {
×
115
          if (index === 0) return;
×
116
          // Change sorting in the array and swap sortOrder properties
117
          const previousElement = { ...questions[index - 1], sortOrder: questions[index].sortOrder };
×
118
          const element = { ...questions[index], sortOrder: questions[index - 1].sortOrder };
×
119
          const nextQuestions = [
×
120
            ...slice(questions, 0, index - 1),
121
            element,
122
            previousElement,
123
            ...slice(questions, index + 1),
124
          ];
125
          setFieldValue('questions', nextQuestions);
×
126
        };
127

128
        const handleMoveDown = (index: number) => {
×
129
          if (index >= questions.length - 1) return;
×
130
          handleMoveUp(index + 1);
×
131
        };
132

133
        return (
×
134
          <>
135
            <FormikMarkdownField
136
              title={t('common.introduction')}
137
              name="description"
138
              disabled={disabled || loading}
×
139
              maxLength={MARKDOWN_TEXT_LENGTH}
140
            />
141
            <Gutters />
142
            <BlockSectionTitle>
143
              {t('common.questions')}
144
              <Tooltip title={'Add question'} placement={'bottom'}>
145
                <span>
146
                  <IconButton
147
                    onClick={() => {
148
                      handleAdd();
×
149
                    }}
150
                    color="primary"
151
                    disabled={disabled || loading}
×
152
                    size="large"
153
                    aria-label={t('common.add')}
154
                  >
155
                    <AddIcon />
156
                  </IconButton>
157
                </span>
158
              </Tooltip>
159
            </BlockSectionTitle>
160
            {questions.map((question, index) => (
161
              <FormQuestionField
×
162
                key={index}
163
                index={index}
164
                onDelete={() => handleDelete(index)}
×
165
                disabled={disabled || loading}
×
166
                canMoveUp={index > 0}
167
                onMoveUpClick={() => handleMoveUp(index)}
×
168
                canMoveDown={index < questions.length - 1}
169
                onMoveDownClick={() => handleMoveDown(index)}
×
170
              />
171
            ))}
172
            <Box display="flex" marginY={4} justifyContent="flex-end">
173
              <FormikSubmitButton variant="contained" onClick={() => handleSubmit()} loading={loading}>
×
174
                {t('common.update')}
175
              </FormikSubmitButton>
176
            </Box>
177
          </>
178
        );
179
      }}
180
    </Formik>
181
  );
182
};
183

184
export default CommunityApplicationForm;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc