diff --git a/backend/graphql/index.ts b/backend/graphql/index.ts index e6998015..90024be2 100644 --- a/backend/graphql/index.ts +++ b/backend/graphql/index.ts @@ -196,7 +196,7 @@ const graphQLMiddlewares = { createBranch: authorizedByAdmin(), updateBranch: authorizedByAdmin(), deleteBranch: authorizedByAdmin(), - createLanguage: authorizedByAdmin(), + createLanguage: authorizedByAllRoles(), updateLanguage: authorizedByAdmin(), deleteLanguage: authorizedByAdmin(), upsertDeleteShiftSignups: authorizedByAdminAndVolunteer(), diff --git a/frontend/src/components/user/AccountForm.tsx b/frontend/src/components/user/AccountForm.tsx index 8f6aaed0..fa394c01 100644 --- a/frontend/src/components/user/AccountForm.tsx +++ b/frontend/src/components/user/AccountForm.tsx @@ -31,7 +31,6 @@ import { LanguageQueryResponse, } from "../../types/api/LanguageTypes"; import TextField from "./fields/TextField"; -import SelectorField from "./fields/SelectorField"; import SearchSelectorField from "./fields/SearchSelectorField"; export enum AccountFormMode { @@ -65,6 +64,14 @@ const LANGUAGES = gql` } `; +const CREATE_LANGUAGE = gql` + mutation AccountForm_CreateLanguage($language: LanguageRequestDTO!) { + createLanguage(language: $language) { + id + } + } +`; + type AccountFormProps = { mode: AccountFormMode; isAdmin: boolean; // False if user is a volunteer @@ -326,6 +333,23 @@ const AccountForm = ({ return createdSkill; }; + const [createLanguage] = useMutation(CREATE_LANGUAGE, { + refetchQueries: ["AccountForm_Languages"], + }); + + // A set to store languages (strings) added by the user + const [addedLanguages, setAddedLanguages] = useState>( + new Set(), + ); + const addNewLanguage = (newLanguage: string) => { + setAddedLanguages(new Set(addedLanguages.add(newLanguage))); + }; + const deleteNewLanguage = (newLanguage: string) => { + setAddedLanguages( + new Set(Array.from(addedLanguages).filter((l) => l !== newLanguage)), + ); + }; + const selectLanguage = ( language: string, currentLanguages: LanguageResponseDTO[], @@ -356,12 +380,36 @@ const AccountForm = ({ ); }; + const handleAddLanguageToDB = async (name: string) => { + let createdLanguage; + try { + createdLanguage = await createLanguage({ + variables: { + language: { name }, + }, + }); + } catch (error: unknown) { + toast({ + title: `Cannot create language`, + description: `${error}`, + status: "error", + duration: 9000, + isClosable: true, + }); + } + return createdLanguage; + }; + const handleSubmit = async ( values: CreateAccountFormValues | EditAccountFormValues, ) => { const newSkillsArr: string[] = Array.from(addedSkills); + const newLanguagesArr: string[] = Array.from(addedLanguages); + const newSkillsInDB: SkillResponseDTO[] = []; + const newLanguagesInDB: LanguageResponseDTO[] = []; + // Add all skills to DB for (let i = 0; i < newSkillsArr.length; i += 1) { /* eslint-disable-next-line no-await-in-loop */ const newSkill = await handleAddSkillToDB(newSkillsArr[i]); @@ -371,9 +419,20 @@ const AccountForm = ({ }); } + // Add all languages to DB + for (let i = 0; i < newLanguagesArr.length; i += 1) { + /* eslint-disable-next-line no-await-in-loop */ + const newLanguage = await handleAddLanguageToDB(newLanguagesArr[i]); + newLanguagesInDB.push({ + id: newLanguage?.data.createLanguage.id.toString(), + name: newLanguagesArr[i], + }); + } + const valuesToBeSubmitted = { ...values, skills: [...values.skills, ...newSkillsInDB], + languages: [...values.languages, ...newLanguagesInDB], }; if (mode === AccountFormMode.CREATE) { @@ -474,12 +533,13 @@ const AccountForm = ({ onDeleteNewOption={(newSkill) => deleteNewSkill(newSkill)} /> )} - Search and select languages you understand. } @@ -489,6 +549,10 @@ const AccountForm = ({ onDeselect={(language) => deselectLanguage(language, values.languages, setFieldValue) } + onCreateNewOption={(newLanguage) => addNewLanguage(newLanguage)} + onDeleteNewOption={(newLanguage) => + deleteNewLanguage(newLanguage) + } /> { setDropdownClicked(true); - if (option.id !== "-1") { // User-added values have an id of "-1" before submitting + if (option.id !== "-1") { + // User-added values have an id of "-1" before submitting onSelect(option.id); } + setTextboxInput(""); }} > {option.name}