();
+ return (
+ <>
+
+
+ Set the target
+
+
+
+
+
+
+
+ Set the maximum candidates capacity
+
+
+
+ {({ field, form }: FieldProps) => (
+ {
+ setFieldValue("checkboxCap", e.target.checked);
+ if (!e.target.checked) setFieldValue("targetCap", "");
+ }}
+ />
+ )}
+
+
+
+ >
+ );
+};
+
+export default TargetSize;
diff --git a/src/pages/campaigns/components/campaignForm/index.tsx b/src/pages/campaigns/components/campaignForm/index.tsx
index 04bb258b..c0146940 100644
--- a/src/pages/campaigns/components/campaignForm/index.tsx
+++ b/src/pages/campaigns/components/campaignForm/index.tsx
@@ -40,6 +40,8 @@ import CsmSelect from "./fields/roles/CsmSelect";
import PmSelect from "./fields/roles/PMSelect";
import ResearcherSelect from "./fields/roles/ResearcherSelect";
import TlSelect from "./fields/roles/TLSelect";
+import { SurveyButton } from "./SurveyButton";
+import TargetSize from "./fields/TargetSize";
interface FormProps {
dossier?: GetDossiersByCampaignApiResponse;
@@ -129,6 +131,7 @@ const CampaignFormContent = ({ dossier, isEdit, duplicate }: FormProps) => {
@@ -225,11 +228,13 @@ const CampaignFormContent = ({ dossier, isEdit, duplicate }: FormProps) => {
name="goal"
label="Test Perimeter"
placeholder="The test will cover..."
+ resize="vertical"
/>
@@ -248,6 +253,7 @@ const CampaignFormContent = ({ dossier, isEdit, duplicate }: FormProps) => {
@@ -259,15 +265,9 @@ const CampaignFormContent = ({ dossier, isEdit, duplicate }: FormProps) => {
id="who"
>
-
- Set the target
-
-
+
+
+
@@ -279,8 +279,12 @@ const CampaignFormContent = ({ dossier, isEdit, duplicate }: FormProps) => {
+ {dossier && dossier.id && (
+
+ )}
@@ -295,6 +299,7 @@ const CampaignFormContent = ({ dossier, isEdit, duplicate }: FormProps) => {
diff --git a/src/pages/campaigns/preselectionForm/index.tsx b/src/pages/campaigns/preselectionForm/index.tsx
deleted file mode 100644
index aae23036..00000000
--- a/src/pages/campaigns/preselectionForm/index.tsx
+++ /dev/null
@@ -1,327 +0,0 @@
-import {
- BSCol,
- BSGrid,
- Formik,
- Form,
- Card,
- PageTitle,
-} from "@appquality/appquality-design-system";
-import { useParams, useHistory } from "react-router-dom";
-import { useEffect, useState } from "react";
-import { OpsUserContainer } from "src/features/AuthorizedOnlyContainer";
-import { FieldsSelectors } from "src/pages/campaigns/preselectionForm/fieldsSelectors";
-import { FormConfigurator } from "src/pages/campaigns/preselectionForm/formConfigurator";
-import * as Yup from "yup";
-import {
- PostCampaignsFormsApiArg,
- PreselectionFormQuestion,
- PutCampaignsFormsByFormIdApiArg,
- useGetCampaignsFormsByFormIdQuery,
- useGetCustomUserFieldsQuery,
- usePostCampaignsFormsMutation,
- usePutCampaignsFormsByFormIdMutation,
-} from "src/services/tryberApi";
-import useCufData from "src/pages/campaigns/preselectionForm/useCufData";
-import { useAppDispatch } from "src/store";
-import siteWideMessageStore from "src/redux/siteWideMessages";
-
-import { setLoadedForm } from "./preselectionSlice";
-import { v4 as uuidv4 } from "uuid";
-import { getCustomQuestionTypeLabel } from "./getCustomQuestionTypeLabel";
-import { CopyLinkButton } from "src/pages/campaigns/preselectionFormList/CopyLinkButton";
-import { getProfileTypeLabel } from "./getProfileTypeLabel";
-import { PageTemplate } from "src/features/PageTemplate";
-
-const PreselectionForm = () => {
- const history = useHistory();
- const { add } = siteWideMessageStore();
-
- const [createForm] = usePostCampaignsFormsMutation();
- const [editForm] = usePutCampaignsFormsByFormIdMutation();
- const { getAllOptions } = useCufData();
- const { id } = useParams<{ id: string }>();
- const dispatch = useAppDispatch();
- const { data } = useGetCustomUserFieldsQuery();
- const savedData = useGetCampaignsFormsByFormIdQuery(
- { formId: id },
- { skip: !id }
- );
- const [cufList, setCufList] = useState<
- ApiComponents["schemas"]["CustomUserFieldsData"][]
- >([]);
- const [saveEdit, setSaveEdit] = useState(false);
-
- const initialFieldValue: (AdditionalField | CustomUserField)[] = [];
- savedData.data?.fields.forEach((f) => {
- switch (f.type) {
- case "gender":
- case "phone_number":
- case "address":
- case "text":
- initialFieldValue.push({
- questionId: f.id,
- fieldId: f.type,
- question: f.question,
- shortTitle: f.short_name,
- type: f.type,
- name:
- f.type === "text"
- ? `Custom ${getCustomQuestionTypeLabel(f.type)}`
- : getProfileTypeLabel(f.type),
- });
- break;
- case "radio":
- case "select":
- case "multiselect":
- initialFieldValue.push({
- questionId: f.id,
- fieldId: uuidv4(),
- question: f.question,
- shortTitle: f.short_name,
- type: f.type,
- options: f.options?.map((o) =>
- typeof o === "string" ? o : o.toString()
- ),
- name: `Custom ${getCustomQuestionTypeLabel(f.type)}`,
- });
- break;
- default:
- if (f.type.startsWith("cuf_")) {
- const cufId = parseInt(f.type.replace("cuf_", ""));
- const cufToAdd = cufList.find((cuf) => cuf.id === cufId);
- const selectedOptions: { label: string; value: string }[] = [];
- // @ts-ignore
- if (cufToAdd?.options?.length === f.options?.length) {
- selectedOptions.push({ label: "All options", value: "-1" });
- } else {
- // @ts-ignore
- f.options?.forEach((selected) => {
- const opt = cufToAdd?.options?.find((all) => all.id === selected);
- opt &&
- selectedOptions.push({
- label: opt.name,
- value: opt.id.toString(),
- });
- });
- }
- initialFieldValue.push({
- questionId: f.id,
- cufId,
- cufType: cufToAdd?.type,
- fieldId: f.type,
- question: f.question,
- shortTitle: f.short_name,
- type: f.type,
- name: `${cufToAdd?.name.it} - ${f.type}`,
- availableOptions: cufToAdd?.options,
- selectedOptions,
- });
- }
- }
- });
-
- const validationSchema = Yup.object({
- formTitle: Yup.string().required(),
- fields: Yup.array().of(
- Yup.object().shape({
- question: Yup.string().required("This is a required field"),
- type: Yup.string().required(),
- options: Yup.array().when("type", {
- is: (type: string) =>
- type === "radio" || type === "select" || type === "multiselect",
- then: Yup.array()
- .of(Yup.string().required("This is a required field"))
- .min(2, "This field must have at least 2 items"),
- }),
- })
- ),
- });
- const initialValues: PreselectionFormValues = {
- formTitle: savedData.data?.name || "",
- fields: initialFieldValue,
- campaign: savedData.data?.campaign
- ? {
- label: savedData.data?.campaign.name,
- value: savedData.data?.campaign.id.toString(),
- }
- : { label: "", value: "" },
- };
-
- useEffect(() => {
- const list: ApiComponents["schemas"]["CustomUserFieldsData"][] = [];
- data?.forEach((d) => {
- d.fields?.forEach((f) => list.push(f));
- });
- setCufList(list);
- }, [data]);
-
- useEffect(() => {
- if (savedData?.data) {
- dispatch(setLoadedForm(savedData.data));
- }
- }, [savedData]);
- return (
-
-
-
- {id ? "Edit Preselection Form" : "New Preselection Form"}
-
-
- {
- const fieldsToSend = values.fields.map((field) => {
- const newField: PreselectionFormQuestion & { id?: number } = {
- ...(field.questionId ? { id: field.questionId } : {}),
- question: field.question,
- short_name: field.shortTitle,
- type: field.type,
- };
- if (field.options) {
- // @ts-ignore
- newField.options = field.options;
- }
- if ("selectedOptions" in field && field.selectedOptions) {
- if (field.selectedOptions[0]?.value === "-1") {
- getAllOptions(field.cufId).then((res) => {
- newField.options = res;
- });
- } else {
- newField.options = field.selectedOptions.map((o) =>
- parseInt(o.value)
- );
- }
- }
- return newField;
- });
- if (id) {
- setSaveEdit(true);
- const args: PutCampaignsFormsByFormIdApiArg = {
- formId: id,
- body: {
- name: values.formTitle,
- // @ts-ignore
- fields: fieldsToSend,
- },
- };
- if (values.campaign?.value)
- args.body.campaign = parseInt(values.campaign?.value);
- const res = await editForm(args);
- if (res && "data" in res) {
- history.push(
- `/backoffice/campaigns/preselection-forms/${res.data.id}`
- );
- add({ type: "success", message: "Form saved" });
- } else {
- const errorCode =
- "error" in res && "data" in res.error
- ? (res.error.data as { code: string }).code
- : false;
- switch (errorCode) {
- case "CAMPAIGN_ID_ALREADY_ASSIGNED":
- add({
- type: "danger",
- message: "This campaign already has a form assigned",
- });
- break;
- case "NO_ACCESS_TO_CAMPAIGN":
- add({
- type: "danger",
- message:
- "You can't assign a form to a campaign you don't own",
- });
- break;
- default:
- add({
- type: "danger",
- message: "There was an error",
- });
- break;
- }
- }
- } else {
- const args: PostCampaignsFormsApiArg = {
- body: {
- name: values.formTitle,
- // @ts-ignore
- fields: fieldsToSend,
- },
- };
- if (values.campaign?.value)
- args.body.campaign = parseInt(values.campaign?.value);
- const res = await createForm(args);
- if (res && "data" in res) {
- history.push(
- `/backoffice/campaigns/preselection-forms/${res.data.id}`
- );
- add({ type: "success", message: "Form saved" });
- } else {
- const errorCode =
- "error" in res && "data" in res.error
- ? (res.error.data as { code: string }).code
- : false;
- switch (errorCode) {
- case "CAMPAIGN_ID_ALREADY_ASSIGNED":
- add({
- type: "danger",
- message: "This campaign already has a form assigned",
- });
- break;
- case "NO_ACCESS_TO_CAMPAIGN":
- add({
- type: "danger",
- message:
- "You can't assign a form to a campaign you don't own",
- });
- break;
- default:
- add({
- type: "danger",
- message: "There was an error",
- });
- break;
- }
- }
- }
- // scroll to form title
- const selector = `[id="formTitle"]`;
- const formTitleElement = document.querySelector(
- selector
- ) as HTMLElement;
- formTitleElement?.scrollIntoView({
- behavior: "smooth",
- block: "center",
- });
- }}
- >
-
-
-
-
- );
-};
-
-export default PreselectionForm;
diff --git a/src/pages/campaigns/selection/editPanel/selectionFilters/index.tsx b/src/pages/campaigns/selection/editPanel/selectionFilters/index.tsx
index e05c648d..cb3b139a 100644
--- a/src/pages/campaigns/selection/editPanel/selectionFilters/index.tsx
+++ b/src/pages/campaigns/selection/editPanel/selectionFilters/index.tsx
@@ -1,5 +1,3 @@
-import { Card } from "@appquality/appquality-design-system";
-import styled from "styled-components";
import { AgeFilters } from "./FilterItems/AgeFilters";
import { BughuntingLevelFilters } from "./FilterItems/BughuntingLevelFilters";
import { DeviceFilters } from "./FilterItems/DeviceFilters";
diff --git a/src/pages/campaigns/preselectionFormList/CopyLinkButton.tsx b/src/pages/preselectionForms/components/CopyLinkButton.tsx
similarity index 100%
rename from src/pages/campaigns/preselectionFormList/CopyLinkButton.tsx
rename to src/pages/preselectionForms/components/CopyLinkButton.tsx
diff --git a/src/pages/preselectionForms/components/FormProvider.tsx b/src/pages/preselectionForms/components/FormProvider.tsx
new file mode 100644
index 00000000..12b391f3
--- /dev/null
+++ b/src/pages/preselectionForms/components/FormProvider.tsx
@@ -0,0 +1,260 @@
+import {
+ GetCampaignsFormsByFormIdApiResponse,
+ PostCampaignsFormsApiArg,
+ PreselectionFormQuestion,
+ PutCampaignsFormsByFormIdApiArg,
+ usePostCampaignsFormsMutation,
+ usePutCampaignsFormsByFormIdMutation,
+} from "src/services/tryberApi";
+import { getCustomQuestionTypeLabel } from "../functions/getCustomQuestionTypeLabel";
+import { getProfileTypeLabel } from "../functions/getProfileTypeLabel";
+import { v4 as uuidv4 } from "uuid";
+import * as Yup from "yup";
+import { ReactNode, useState } from "react";
+import { Form, Formik } from "@appquality/appquality-design-system";
+import useCufData from "../hooks/useCufData";
+import { useHistory } from "react-router-dom";
+import siteWideMessageStore from "src/redux/siteWideMessages";
+import { scrollToFormTitle } from "../functions/scrollToFormTitle";
+
+interface FormProviderInterface {
+ savedData?: GetCampaignsFormsByFormIdApiResponse;
+ isEdit: boolean;
+ cufList: ApiComponents["schemas"]["CustomUserFieldsData"][];
+ children: ReactNode;
+}
+
+const FormProvider = ({
+ savedData,
+ isEdit,
+ cufList,
+ children,
+}: FormProviderInterface) => {
+ const history = useHistory();
+ const { add } = siteWideMessageStore();
+
+ const [createForm] = usePostCampaignsFormsMutation();
+ const [saveEdit, setSaveEdit] = useState(false);
+ const { getAllOptions } = useCufData();
+ const [editForm] = usePutCampaignsFormsByFormIdMutation();
+ const initialFieldValue: (AdditionalField | CustomUserField)[] = [];
+ savedData?.fields.forEach((f) => {
+ switch (f.type) {
+ case "gender":
+ case "phone_number":
+ case "address":
+ case "text":
+ initialFieldValue.push({
+ questionId: f.id,
+ fieldId: f.type,
+ question: f.question,
+ shortTitle: f.short_name,
+ type: f.type,
+ name:
+ f.type === "text"
+ ? `Custom ${getCustomQuestionTypeLabel(f.type)}`
+ : getProfileTypeLabel(f.type),
+ });
+ break;
+ case "radio":
+ case "select":
+ case "multiselect":
+ initialFieldValue.push({
+ questionId: f.id,
+ fieldId: uuidv4(),
+ question: f.question,
+ shortTitle: f.short_name,
+ type: f.type,
+ options: f.options?.map((o) =>
+ typeof o === "string" ? o : o.toString()
+ ),
+ name: `Custom ${getCustomQuestionTypeLabel(f.type)}`,
+ });
+ break;
+ default:
+ if (f.type.startsWith("cuf_")) {
+ const cufId = parseInt(f.type.replace("cuf_", ""));
+ const cufToAdd = cufList.find((cuf) => cuf.id === cufId);
+ const selectedOptions: { label: string; value: string }[] = [];
+ // @ts-ignore
+ if (cufToAdd?.options?.length === f.options?.length) {
+ selectedOptions.push({ label: "All options", value: "-1" });
+ } else {
+ // @ts-ignore
+ f.options?.forEach((selected) => {
+ const opt = cufToAdd?.options?.find((all) => all.id === selected);
+ opt &&
+ selectedOptions.push({
+ label: opt.name,
+ value: opt.id.toString(),
+ });
+ });
+ }
+ initialFieldValue.push({
+ questionId: f.id,
+ cufId,
+ cufType: cufToAdd?.type,
+ fieldId: f.type,
+ question: f.question,
+ shortTitle: f.short_name,
+ type: f.type,
+ name: `${cufToAdd?.name.it} - ${f.type}`,
+ availableOptions: cufToAdd?.options,
+ selectedOptions,
+ });
+ }
+ }
+ });
+
+ const validationSchema = Yup.object({
+ formTitle: Yup.string().required(),
+ fields: Yup.array().of(
+ Yup.object().shape({
+ question: Yup.string().required("This is a required field"),
+ type: Yup.string().required(),
+ options: Yup.array().when("type", {
+ is: (type: string) =>
+ type === "radio" || type === "select" || type === "multiselect",
+ then: Yup.array()
+ .of(Yup.string().required("This is a required field"))
+ .min(2, "This field must have at least 2 items"),
+ }),
+ })
+ ),
+ });
+ const initialValues: PreselectionFormValues = {
+ formTitle: savedData?.name || "",
+ fields: initialFieldValue,
+ campaign: savedData?.campaign
+ ? {
+ label: savedData?.campaign.name,
+ value: savedData?.campaign.id.toString(),
+ }
+ : { label: "", value: "" },
+ };
+ return (
+ {
+ //refactor
+ const fieldsToSend = values.fields.map((field) => {
+ const newField: PreselectionFormQuestion & { id?: number } = {
+ ...(field.questionId ? { id: field.questionId } : {}),
+ question: field.question,
+ short_name: field.shortTitle,
+ type: field.type,
+ };
+ if (field.options) {
+ // @ts-ignore
+ newField.options = field.options;
+ }
+ if ("selectedOptions" in field && field.selectedOptions) {
+ if (field.selectedOptions[0]?.value === "-1") {
+ getAllOptions(field.cufId).then((res) => {
+ newField.options = res;
+ });
+ } else {
+ newField.options = field.selectedOptions.map((o) =>
+ parseInt(o.value)
+ );
+ }
+ }
+ return newField;
+ });
+ if (isEdit) {
+ setSaveEdit(true);
+ const args: PutCampaignsFormsByFormIdApiArg = {
+ formId: savedData ? savedData?.id.toString() : "",
+ body: {
+ name: values.formTitle,
+ // @ts-ignore
+ fields: fieldsToSend,
+ },
+ };
+ if (values.campaign?.value)
+ args.body.campaign = parseInt(values.campaign?.value);
+ const res = await editForm(args);
+ if (res && "data" in res) {
+ history.push(`/backoffice/preselection-forms/${res.data.id}`);
+ add({ type: "success", message: "Form saved" });
+ } else {
+ const errorCode =
+ "error" in res && "data" in res.error
+ ? (res.error.data as { code: string }).code
+ : false;
+ switch (errorCode) {
+ case "CAMPAIGN_ID_ALREADY_ASSIGNED":
+ add({
+ type: "danger",
+ message: "This campaign already has a form assigned",
+ });
+ break;
+ case "NO_ACCESS_TO_CAMPAIGN":
+ add({
+ type: "danger",
+ message:
+ "You can't assign a form to a campaign you don't own",
+ });
+ break;
+ default:
+ add({
+ type: "danger",
+ message: "There was an error",
+ });
+ break;
+ }
+ }
+ } else {
+ const args: PostCampaignsFormsApiArg = {
+ body: {
+ name: values.formTitle,
+ // @ts-ignore
+ fields: fieldsToSend,
+ },
+ };
+ if (values.campaign?.value)
+ args.body.campaign = parseInt(values.campaign?.value);
+ const res = await createForm(args);
+ if (res && "data" in res) {
+ history.push(`/backoffice/preselection-forms/${res.data.id}`);
+ add({ type: "success", message: "Form saved" });
+ } else {
+ const errorCode =
+ "error" in res && "data" in res.error
+ ? (res.error.data as { code: string }).code
+ : false;
+ switch (errorCode) {
+ case "CAMPAIGN_ID_ALREADY_ASSIGNED":
+ add({
+ type: "danger",
+ message: "This campaign already has a form assigned",
+ });
+ break;
+ case "NO_ACCESS_TO_CAMPAIGN":
+ add({
+ type: "danger",
+ message:
+ "You can't assign a form to a campaign you don't own",
+ });
+ break;
+ default:
+ add({
+ type: "danger",
+ message: "There was an error",
+ });
+ break;
+ }
+ }
+ }
+
+ scrollToFormTitle();
+ }}
+ >
+
+
+ );
+};
+
+export default FormProvider;
diff --git a/src/pages/campaigns/preselectionForm/fieldsSelectors/CufSelectorCard.tsx b/src/pages/preselectionForms/components/fieldsSelectors/CufSelectorCard.tsx
similarity index 100%
rename from src/pages/campaigns/preselectionForm/fieldsSelectors/CufSelectorCard.tsx
rename to src/pages/preselectionForms/components/fieldsSelectors/CufSelectorCard.tsx
diff --git a/src/pages/campaigns/preselectionForm/fieldsSelectors/CustomQuestionCard.tsx b/src/pages/preselectionForms/components/fieldsSelectors/CustomQuestionCard.tsx
similarity index 92%
rename from src/pages/campaigns/preselectionForm/fieldsSelectors/CustomQuestionCard.tsx
rename to src/pages/preselectionForms/components/fieldsSelectors/CustomQuestionCard.tsx
index 6c0b1ab9..c2e55291 100644
--- a/src/pages/campaigns/preselectionForm/fieldsSelectors/CustomQuestionCard.tsx
+++ b/src/pages/preselectionForms/components/fieldsSelectors/CustomQuestionCard.tsx
@@ -1,7 +1,7 @@
import React, { useState } from "react";
import { Button, Card, Radio } from "@appquality/appquality-design-system";
import { v4 as uuidv4 } from "uuid";
-import { getCustomQuestionTypeLabel } from "../getCustomQuestionTypeLabel";
+import { getCustomQuestionTypeLabel } from "src/pages/preselectionForms/functions/getCustomQuestionTypeLabel";
export const CustomQuestionCard: React.FC<{
add: (field: AdditionalField) => void;
diff --git a/src/pages/campaigns/preselectionForm/fieldsSelectors/ProfileFieldsSelectorCard.tsx b/src/pages/preselectionForms/components/fieldsSelectors/ProfileFieldsSelectorCard.tsx
similarity index 100%
rename from src/pages/campaigns/preselectionForm/fieldsSelectors/ProfileFieldsSelectorCard.tsx
rename to src/pages/preselectionForms/components/fieldsSelectors/ProfileFieldsSelectorCard.tsx
diff --git a/src/pages/campaigns/preselectionForm/fieldsSelectors/index.tsx b/src/pages/preselectionForms/components/fieldsSelectors/index.tsx
similarity index 59%
rename from src/pages/campaigns/preselectionForm/fieldsSelectors/index.tsx
rename to src/pages/preselectionForms/components/fieldsSelectors/index.tsx
index 449b0663..511a1bc6 100644
--- a/src/pages/campaigns/preselectionForm/fieldsSelectors/index.tsx
+++ b/src/pages/preselectionForms/components/fieldsSelectors/index.tsx
@@ -1,6 +1,6 @@
-import { ProfileFieldsSelectorCard } from "src/pages/campaigns/preselectionForm/fieldsSelectors/ProfileFieldsSelectorCard";
-import { CufSelectorCard } from "src/pages/campaigns/preselectionForm/fieldsSelectors/CufSelectorCard";
-import { CustomQuestionCard } from "src/pages/campaigns/preselectionForm/fieldsSelectors/CustomQuestionCard";
+import { ProfileFieldsSelectorCard } from "src/pages/preselectionForms/components/fieldsSelectors/ProfileFieldsSelectorCard";
+import { CufSelectorCard } from "src/pages/preselectionForms/components/fieldsSelectors/CufSelectorCard";
+import { CustomQuestionCard } from "src/pages/preselectionForms/components/fieldsSelectors/CustomQuestionCard";
import { FieldArray } from "formik";
export const FieldsSelectors = () => {
diff --git a/src/pages/campaigns/preselectionForm/formConfigurator/CampaignSelect.tsx b/src/pages/preselectionForms/components/formConfigurator/CampaignSelect.tsx
similarity index 100%
rename from src/pages/campaigns/preselectionForm/formConfigurator/CampaignSelect.tsx
rename to src/pages/preselectionForms/components/formConfigurator/CampaignSelect.tsx
diff --git a/src/pages/Jotform/CufConfigurator/CufMultiselect.tsx b/src/pages/preselectionForms/components/formConfigurator/CufMultiselect.tsx
similarity index 100%
rename from src/pages/Jotform/CufConfigurator/CufMultiselect.tsx
rename to src/pages/preselectionForms/components/formConfigurator/CufMultiselect.tsx
diff --git a/src/pages/campaigns/preselectionForm/formConfigurator/DropZone.tsx b/src/pages/preselectionForms/components/formConfigurator/DropZone.tsx
similarity index 100%
rename from src/pages/campaigns/preselectionForm/formConfigurator/DropZone.tsx
rename to src/pages/preselectionForms/components/formConfigurator/DropZone.tsx
diff --git a/src/pages/campaigns/preselectionForm/formConfigurator/OptionsField.tsx b/src/pages/preselectionForms/components/formConfigurator/OptionsField.tsx
similarity index 100%
rename from src/pages/campaigns/preselectionForm/formConfigurator/OptionsField.tsx
rename to src/pages/preselectionForms/components/formConfigurator/OptionsField.tsx
diff --git a/src/pages/campaigns/preselectionForm/formConfigurator/QuestionField.tsx b/src/pages/preselectionForms/components/formConfigurator/QuestionField.tsx
similarity index 100%
rename from src/pages/campaigns/preselectionForm/formConfigurator/QuestionField.tsx
rename to src/pages/preselectionForms/components/formConfigurator/QuestionField.tsx
diff --git a/src/pages/campaigns/preselectionForm/formConfigurator/ShortTitleField.tsx b/src/pages/preselectionForms/components/formConfigurator/ShortTitleField.tsx
similarity index 100%
rename from src/pages/campaigns/preselectionForm/formConfigurator/ShortTitleField.tsx
rename to src/pages/preselectionForms/components/formConfigurator/ShortTitleField.tsx
diff --git a/src/pages/campaigns/preselectionForm/formConfigurator/ValuesFieldsCard.tsx b/src/pages/preselectionForms/components/formConfigurator/ValuesFieldsCard.tsx
similarity index 93%
rename from src/pages/campaigns/preselectionForm/formConfigurator/ValuesFieldsCard.tsx
rename to src/pages/preselectionForms/components/formConfigurator/ValuesFieldsCard.tsx
index 174259d2..ab191c71 100644
--- a/src/pages/campaigns/preselectionForm/formConfigurator/ValuesFieldsCard.tsx
+++ b/src/pages/preselectionForms/components/formConfigurator/ValuesFieldsCard.tsx
@@ -1,6 +1,5 @@
import { FC, useEffect } from "react";
-import { OptionsField } from "src/pages/campaigns/preselectionForm/formConfigurator/OptionsField";
-import { CufMultiselect } from "src/pages/Jotform/CufConfigurator/CufMultiselect";
+import { OptionsField } from "src/pages/preselectionForms/components/formConfigurator/OptionsField";
import {
aqBootstrapTheme,
Card,
@@ -8,10 +7,11 @@ import {
TextareaField,
} from "@appquality/appquality-design-system";
import { useDrag } from "react-dnd";
-import { DropZone } from "src/pages/campaigns/preselectionForm/formConfigurator/DropZone";
+import { DropZone } from "src/pages/preselectionForms/components/formConfigurator/DropZone";
import { XLg, GripVertical } from "react-bootstrap-icons";
import { ShortTitleField } from "./ShortTitleField";
import styled from "styled-components";
+import { CufMultiselect } from "./CufMultiselect";
const StyledInlineField = styled.div`
display: flex;
diff --git a/src/pages/campaigns/preselectionForm/formConfigurator/index.tsx b/src/pages/preselectionForms/components/formConfigurator/index.tsx
similarity index 94%
rename from src/pages/campaigns/preselectionForm/formConfigurator/index.tsx
rename to src/pages/preselectionForms/components/formConfigurator/index.tsx
index 423a9e5b..34d794ce 100644
--- a/src/pages/campaigns/preselectionForm/formConfigurator/index.tsx
+++ b/src/pages/preselectionForms/components/formConfigurator/index.tsx
@@ -2,7 +2,7 @@ import { Field, Button } from "@appquality/appquality-design-system";
import { FieldArray, useFormikContext } from "formik";
import { DndProvider, useDragLayer } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
-import { ValuesFieldsCard } from "src/pages/campaigns/preselectionForm/formConfigurator/ValuesFieldsCard";
+import { ValuesFieldsCard } from "src/pages/preselectionForms/components/formConfigurator/ValuesFieldsCard";
import { CampaignSelect } from "./CampaignSelect";
export const FormConfigurator = () => {
diff --git a/src/pages/campaigns/preselectionFormList/formTableCard/columns.ts b/src/pages/preselectionForms/components/formTableCard/columns.ts
similarity index 100%
rename from src/pages/campaigns/preselectionFormList/formTableCard/columns.ts
rename to src/pages/preselectionForms/components/formTableCard/columns.ts
diff --git a/src/pages/campaigns/preselectionFormList/formTableCard/formSearchCard.tsx b/src/pages/preselectionForms/components/formTableCard/formSearchCard.tsx
similarity index 91%
rename from src/pages/campaigns/preselectionFormList/formTableCard/formSearchCard.tsx
rename to src/pages/preselectionForms/components/formTableCard/formSearchCard.tsx
index 4912241d..4939710a 100644
--- a/src/pages/campaigns/preselectionFormList/formTableCard/formSearchCard.tsx
+++ b/src/pages/preselectionForms/components/formTableCard/formSearchCard.tsx
@@ -2,7 +2,7 @@ import { Input } from "@appquality/appquality-design-system";
import { useEffect, useState } from "react";
import useDebounce from "src/hooks/useDebounce";
import { useAppDispatch } from "src/store";
-import { setSearch } from "../preselectionListSlice";
+import { setSearch } from "src/pages/preselectionForms/listSlice";
export const FormSearchCard = () => {
const dispatch = useAppDispatch();
diff --git a/src/pages/campaigns/preselectionFormList/formTableCard/index.tsx b/src/pages/preselectionForms/components/formTableCard/index.tsx
similarity index 90%
rename from src/pages/campaigns/preselectionFormList/formTableCard/index.tsx
rename to src/pages/preselectionForms/components/formTableCard/index.tsx
index 095212ee..a8dab918 100644
--- a/src/pages/campaigns/preselectionFormList/formTableCard/index.tsx
+++ b/src/pages/preselectionForms/components/formTableCard/index.tsx
@@ -9,7 +9,7 @@ import { PencilSquare } from "react-bootstrap-icons";
import { useHistory } from "react-router-dom";
import { useGetCampaignsFormsQuery } from "src/services/tryberApi";
import { useAppDispatch, useAppSelector } from "src/store";
-import { resetList } from "../preselectionListSlice";
+import { resetList } from "src/pages/preselectionForms/listSlice";
import Columns from "./columns";
import { FormSearchCard } from "./formSearchCard";
import { addMessage } from "src/redux/siteWideMessages/actionCreators";
@@ -50,13 +50,10 @@ export const FormTableCard = () => {
onClick={(e) => {
if (e.ctrlKey)
window.open(
- `/backoffice/campaigns/preselection-forms/${res.id}`,
+ `/backoffice/preselection-forms/${res.id}`,
"_blank"
);
- else
- history.push(
- `/backoffice/campaigns/preselection-forms/${res.id}`
- );
+ else history.push(`/backoffice/preselection-forms/${res.id}`);
}}
style={{ cursor: "pointer" }}
/>
diff --git a/src/pages/preselectionForms/edit/index.tsx b/src/pages/preselectionForms/edit/index.tsx
new file mode 100644
index 00000000..a6c442ad
--- /dev/null
+++ b/src/pages/preselectionForms/edit/index.tsx
@@ -0,0 +1,85 @@
+import {
+ BSCol,
+ BSGrid,
+ Card,
+ PageTitle,
+} from "@appquality/appquality-design-system";
+import { useParams } from "react-router-dom";
+import { useEffect, useState } from "react";
+import { OpsUserContainer } from "src/features/AuthorizedOnlyContainer";
+import { FieldsSelectors } from "src/pages/preselectionForms/components/fieldsSelectors";
+import { FormConfigurator } from "src/pages/preselectionForms/components/formConfigurator";
+
+import {
+ useGetCampaignsFormsByFormIdQuery,
+ useGetCustomUserFieldsQuery,
+} from "src/services/tryberApi";
+import { useAppDispatch } from "src/store";
+
+import { setLoadedForm } from "src/pages/preselectionForms/singleSlice";
+import { CopyLinkButton } from "src/pages/preselectionForms/components/CopyLinkButton";
+import { PageTemplate } from "src/features/PageTemplate";
+import FormProvider from "src/pages/preselectionForms/components/FormProvider";
+
+const PreselectionForm = () => {
+ const dispatch = useAppDispatch();
+ const [cufList, setCufList] = useState<
+ ApiComponents["schemas"]["CustomUserFieldsData"][]
+ >([]);
+ const { data: cufData } = useGetCustomUserFieldsQuery();
+ const { id } = useParams<{ id: string }>();
+ const {
+ data: formData,
+ isLoading,
+ isError,
+ isFetching,
+ } = useGetCampaignsFormsByFormIdQuery({ formId: id }, { skip: !id });
+
+ useEffect(() => {
+ const list: ApiComponents["schemas"]["CustomUserFieldsData"][] = [];
+ cufData?.forEach((d) => {
+ d.fields?.forEach((f) => list.push(f));
+ });
+ setCufList(list);
+ }, [cufData]);
+
+ useEffect(() => {
+ if (formData) {
+ dispatch(setLoadedForm(formData));
+ }
+ }, [dispatch, formData]);
+ return (
+
+
+
+ {id ? "Edit Preselection Form" : "New Preselection Form"}
+
+
+ {isLoading || isFetching || typeof formData === "undefined" ? (
+ ...loading
+ ) : isError ? (
+ ...error retrieving form
+ ) : (
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+ );
+};
+
+export default PreselectionForm;
diff --git a/src/pages/campaigns/preselectionForm/getCustomQuestionTypeLabel.ts b/src/pages/preselectionForms/functions/getCustomQuestionTypeLabel.ts
similarity index 100%
rename from src/pages/campaigns/preselectionForm/getCustomQuestionTypeLabel.ts
rename to src/pages/preselectionForms/functions/getCustomQuestionTypeLabel.ts
diff --git a/src/pages/campaigns/preselectionForm/getProfileTypeLabel.ts b/src/pages/preselectionForms/functions/getProfileTypeLabel.ts
similarity index 100%
rename from src/pages/campaigns/preselectionForm/getProfileTypeLabel.ts
rename to src/pages/preselectionForms/functions/getProfileTypeLabel.ts
diff --git a/src/pages/preselectionForms/functions/scrollToFormTitle.tsx b/src/pages/preselectionForms/functions/scrollToFormTitle.tsx
new file mode 100644
index 00000000..c730e29e
--- /dev/null
+++ b/src/pages/preselectionForms/functions/scrollToFormTitle.tsx
@@ -0,0 +1,8 @@
+export function scrollToFormTitle() {
+ const selector = `[id="formTitle"]`;
+ const formTitleElement = document.querySelector(selector) as HTMLElement;
+ formTitleElement?.scrollIntoView({
+ behavior: "smooth",
+ block: "center",
+ });
+}
diff --git a/src/pages/campaigns/preselectionForm/useCufData.ts b/src/pages/preselectionForms/hooks/useCufData.ts
similarity index 100%
rename from src/pages/campaigns/preselectionForm/useCufData.ts
rename to src/pages/preselectionForms/hooks/useCufData.ts
diff --git a/src/pages/campaigns/preselectionFormList/index.tsx b/src/pages/preselectionForms/index.tsx
similarity index 86%
rename from src/pages/campaigns/preselectionFormList/index.tsx
rename to src/pages/preselectionForms/index.tsx
index 0e95de9d..3c92d00f 100644
--- a/src/pages/campaigns/preselectionFormList/index.tsx
+++ b/src/pages/preselectionForms/index.tsx
@@ -1,6 +1,6 @@
import { BSCol, BSGrid, Button } from "@appquality/appquality-design-system";
-import { OpsUserContainer } from "../../../features/AuthorizedOnlyContainer";
-import { FormTableCard } from "./formTableCard";
+import { OpsUserContainer } from "../../features/AuthorizedOnlyContainer";
+import { FormTableCard } from "./components/formTableCard";
import { PageTitle } from "@appquality/appquality-design-system";
import { PageTemplate } from "src/features/PageTemplate";
diff --git a/src/pages/campaigns/preselectionFormList/preselectionListSlice.ts b/src/pages/preselectionForms/listSlice.ts
similarity index 100%
rename from src/pages/campaigns/preselectionFormList/preselectionListSlice.ts
rename to src/pages/preselectionForms/listSlice.ts
diff --git a/src/pages/preselectionForms/new/index.tsx b/src/pages/preselectionForms/new/index.tsx
new file mode 100644
index 00000000..4d9068ce
--- /dev/null
+++ b/src/pages/preselectionForms/new/index.tsx
@@ -0,0 +1,56 @@
+import { BSCol, BSGrid, PageTitle } from "@appquality/appquality-design-system";
+import { useParams } from "react-router-dom";
+import { useEffect, useState } from "react";
+import { OpsUserContainer } from "src/features/AuthorizedOnlyContainer";
+import { FieldsSelectors } from "src/pages/preselectionForms/components/fieldsSelectors";
+import { FormConfigurator } from "src/pages/preselectionForms/components/formConfigurator";
+import { useGetCustomUserFieldsQuery } from "src/services/tryberApi";
+
+import { CopyLinkButton } from "src/pages/preselectionForms/components/CopyLinkButton";
+import { PageTemplate } from "src/features/PageTemplate";
+import FormProvider from "src/pages/preselectionForms/components/FormProvider";
+
+const PreselectionForm = () => {
+ const { id } = useParams<{ id: string }>();
+ const { data } = useGetCustomUserFieldsQuery();
+ const [cufList, setCufList] = useState<
+ ApiComponents["schemas"]["CustomUserFieldsData"][]
+ >([]);
+
+ useEffect(() => {
+ const list: ApiComponents["schemas"]["CustomUserFieldsData"][] = [];
+ data?.forEach((d) => {
+ d.fields?.forEach((f) => list.push(f));
+ });
+ setCufList(list);
+ }, [data]);
+
+ return (
+
+
+
+ {id ? "Edit Preselection Form" : "New Preselection Form"}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default PreselectionForm;
diff --git a/src/pages/campaigns/preselectionForm/preselectionSlice.ts b/src/pages/preselectionForms/singleSlice.ts
similarity index 94%
rename from src/pages/campaigns/preselectionForm/preselectionSlice.ts
rename to src/pages/preselectionForms/singleSlice.ts
index d036eff3..4225597c 100644
--- a/src/pages/campaigns/preselectionForm/preselectionSlice.ts
+++ b/src/pages/preselectionForms/singleSlice.ts
@@ -1,7 +1,11 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { v4 as uuidv4 } from "uuid";
-import { GetCampaignsFormsByFormIdApiResponse } from "../../../services/tryberApi";
+import { GetCampaignsFormsByFormIdApiResponse } from "../../services/tryberApi";
+interface CufField {
+ fieldData: ApiComponents["schemas"]["CustomUserFieldsData"];
+ checked: boolean;
+}
interface PreselectionFormState {
profileFieldsList: ProfileField[];
cufList: CufField[];
diff --git a/src/pages/campaigns/preselectionForm/types.d.ts b/src/pages/preselectionForms/types.d.ts
similarity index 100%
rename from src/pages/campaigns/preselectionForm/types.d.ts
rename to src/pages/preselectionForms/types.d.ts
diff --git a/src/services/tryberApi/index.ts b/src/services/tryberApi/index.ts
index 5b5ac423..6fbd75e7 100644
--- a/src/services/tryberApi/index.ts
+++ b/src/services/tryberApi/index.ts
@@ -2666,6 +2666,7 @@ export type GetDossiersByCampaignApiResponse = /** status 200 OK */ {
target?: {
notes?: string;
size?: number;
+ cap?: number;
};
countries?: CountryCode[];
languages?: {
@@ -2830,8 +2831,12 @@ export type CampaignOptional = {
ux_effort?: number;
preview_link?: TranslatablePage;
manual_link?: TranslatablePage;
- bugform_link?: {} | TranslatablePage;
+ bugform_link?: boolean | TranslatablePage;
applied?: boolean;
+ visibility?: {
+ freeSpots?: number;
+ totalSpots?: number;
+ };
};
export type CampaignType = {} | {};
export type CampaignRequired = {
@@ -3033,6 +3038,7 @@ export type DossierCreationData = {
target?: {
notes?: string;
size?: number;
+ cap?: number;
};
countries?: CountryCode[];
languages?: number[];
diff --git a/src/store.ts b/src/store.ts
index fd406bdd..10501e39 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -2,9 +2,8 @@ import { configureStore, PreloadedState } from "@reduxjs/toolkit";
import { tryberApiSlice } from "src/services/tryberApi/apiTags";
import oldReducers from "src/redux/reducer";
import { combineReducers } from "redux";
-import jotformReducer from "src/pages/Jotform/jotformSlice";
-import campaignPreselectionReducer from "src/pages/campaigns/preselectionForm/preselectionSlice";
-import campaignPreselectionListReducer from "src/pages/campaigns/preselectionFormList/preselectionListSlice";
+import campaignPreselectionReducer from "src/pages/preselectionForms/singleSlice";
+import campaignPreselectionListReducer from "src/pages/preselectionForms/listSlice";
import selectionReducer from "src/pages/campaigns/selection/selectionSlice";
import uxDashboardReducer from "src/pages/UxDashboard/uxDashboardSlice";
import { useDispatch, useSelector } from "react-redux";
@@ -12,7 +11,6 @@ import type { TypedUseSelectorHook } from "react-redux";
const rootReducer = combineReducers({
...oldReducers,
- jotform: jotformReducer,
campaignPreselection: campaignPreselectionReducer,
campaignPreselectionList: campaignPreselectionListReducer,
selection: selectionReducer,
diff --git a/src/utils/schema.ts b/src/utils/schema.ts
index f0354815..43e01cc1 100644
--- a/src/utils/schema.ts
+++ b/src/utils/schema.ts
@@ -702,6 +702,10 @@ export interface components {
bugform_link?: boolean | components["schemas"]["TranslatablePage"];
/** @description True if you applied on this Campaign */
applied?: boolean;
+ visibility?: {
+ freeSpots?: number;
+ totalSpots?: number;
+ };
};
CampaignRequired: {
name: string;
@@ -931,6 +935,7 @@ export interface components {
target?: {
notes?: string;
size?: number;
+ cap?: number;
};
countries?: components["schemas"]["CountryCode"][];
languages?: number[];
@@ -2222,6 +2227,10 @@ export interface operations {
"application/json": {
id: number;
name: string;
+ customRoles: {
+ roleId: number;
+ userIds: number[];
+ }[];
}[];
};
};
@@ -4203,6 +4212,7 @@ export interface operations {
target?: {
notes?: string;
size?: number;
+ cap?: number;
};
countries?: components["schemas"]["CountryCode"][];
languages?: {