diff --git a/src/backend/app/config.py b/src/backend/app/config.py index 844bb2d2b9..af84897407 100644 --- a/src/backend/app/config.py +++ b/src/backend/app/config.py @@ -27,7 +27,10 @@ from pydantic_settings import BaseSettings, SettingsConfigDict HttpUrlStr = Annotated[ - str, BeforeValidator(lambda value: str(TypeAdapter(HttpUrl).validate_python(value))) + str, + BeforeValidator( + lambda value: str(TypeAdapter(HttpUrl).validate_python(value) if value else "") + ), ] diff --git a/src/frontend/src/components/createnewproject/ProjectDetailsForm.tsx b/src/frontend/src/components/createnewproject/ProjectDetailsForm.tsx index 8c55c1241f..8234ae1bed 100644 --- a/src/frontend/src/components/createnewproject/ProjectDetailsForm.tsx +++ b/src/frontend/src/components/createnewproject/ProjectDetailsForm.tsx @@ -1,5 +1,6 @@ import TextArea from '@/components/common/TextArea'; import InputTextField from '@/components/common/InputTextField'; +import RadioButton from '@/components/common/RadioButton'; import React, { useEffect } from 'react'; import { CreateProjectActions } from '@/store/slices/CreateProjectSlice'; import { useDispatch } from 'react-redux'; @@ -35,6 +36,11 @@ const ProjectDetailsForm = ({ flag }) => { CreateProjectValidation, ); + const orgDefaultOdkCreds = useAppSelector((state) => state.createproject.orgDefaultOdkCreds); + const handleCheckboxChange = () => { + dispatch(CreateProjectActions.ToggleOrgDefaultOdkCreds(!orgDefaultOdkCreds)); // Dispatch the action to toggle the orgDefaultOdkCreds state + }; + const onFocus = () => { dispatch(OrganisationService(`${import.meta.env.VITE_API_URL}/organisation/`)); }; @@ -112,52 +118,55 @@ const ProjectDetailsForm = ({ flag }) => { required errorMsg={errors.short_description} /> - - - + + {orgDefaultOdkCreds && ( + <> + + + + + )}
{ handleHashtagOnChange(e); }} fieldType="text" - required errorMsg={errors.hashtag} />

- *Default comments added to uploaded changeset comment field. Users should also be encouraged to add text - describing what they mapped. Hashtags are sometimes used for analysis later, but should be human - informative and not overused, #group #event + *Hashtags related to what is being mapped. By default #FMTM is included. Hashtags are sometimes used for + analysis later, but should be human informative and not overused, #group #event

diff --git a/src/frontend/src/components/createnewproject/validation/CreateProjectValidation.tsx b/src/frontend/src/components/createnewproject/validation/CreateProjectValidation.tsx index f1f8e3ebad..69298522f9 100755 --- a/src/frontend/src/components/createnewproject/validation/CreateProjectValidation.tsx +++ b/src/frontend/src/components/createnewproject/validation/CreateProjectValidation.tsx @@ -25,20 +25,23 @@ interface ValidationErrors { const regexForSymbol = /_/g; +function isValidUrl(url: string) { + try { + new URL(url); + return true; + } catch (error) { + return false; + } +} + function CreateProjectValidation(values: ProjectValues) { const errors: ValidationErrors = {}; if (!values?.organisation_id) { errors.organisation_id = 'Organization is Required.'; } - if (!values?.odk_central_url) { - errors.odk_central_url = 'ODK Central Url is Required.'; - } - if (!values?.odk_central_user) { - errors.odk_central_user = 'ODK Central User is Required.'; - } - if (!values?.odk_central_password) { - errors.odk_central_password = 'ODK Central Password is Required.'; + if (values?.odk_central_url && !isValidUrl(values.odk_central_url)) { + errors.odk_central_url = 'Invalid URL.'; } if (!values?.name) { errors.name = 'Project Name is Required.'; @@ -49,9 +52,6 @@ function CreateProjectValidation(values: ProjectValues) { if (!values?.short_description) { errors.short_description = 'Short Description is Required.'; } - if (!values?.hashtags) { - errors.hashtags = 'Tags is Required.'; - } if (!values?.description) { errors.description = 'Description is Required.'; } diff --git a/src/frontend/src/components/editproject/validation/EditProjectDetailsValidation.ts b/src/frontend/src/components/editproject/validation/EditProjectDetailsValidation.ts index b2f553953c..b54e3fdc5c 100644 --- a/src/frontend/src/components/editproject/validation/EditProjectDetailsValidation.ts +++ b/src/frontend/src/components/editproject/validation/EditProjectDetailsValidation.ts @@ -28,15 +28,6 @@ function EditProjectValidation(values: ProjectValues) { // if (!values?.organisation) { // errors.organisation = 'Organization is Required.'; // } - // if (!values?.odk_central_url) { - // errors.odk_central_url = 'ODK Central Url is Required.'; - // } - // if (!values?.odk_central_user) { - // errors.odk_central_user = 'ODK Central User is Required.'; - // } - // if (!values?.odk_central_password) { - // errors.odk_central_password = 'ODK Central Password is Required.'; - // } if (!values?.name) { errors.name = 'Project Name is Required.'; } diff --git a/src/frontend/src/store/slices/CreateProjectSlice.ts b/src/frontend/src/store/slices/CreateProjectSlice.ts index 7bff71cc65..854dabcbed 100755 --- a/src/frontend/src/store/slices/CreateProjectSlice.ts +++ b/src/frontend/src/store/slices/CreateProjectSlice.ts @@ -50,6 +50,7 @@ export const initialState: CreateProjectStateTypes = { isTasksGenerated: { divide_on_square: false, task_splitting_algorithm: false }, isFgbFetching: false, toggleSplittedGeojsonEdit: false, + orgDefaultOdkCreds: false, }; const CreateProject = createSlice({ @@ -91,6 +92,7 @@ const CreateProject = createSlice({ state.uploadAreaSelection = null; state.dividedTaskGeojson = null; state.dividedTaskLoading = false; + state.orgDefaultOdkCreds = false; }, UploadAreaLoading(state, action) { state.projectAreaLoading = action.payload; @@ -229,6 +231,9 @@ const CreateProject = createSlice({ SetToggleSplittedGeojsonEdit(state, action) { state.toggleSplittedGeojsonEdit = action.payload; }, + ToggleOrgDefaultOdkCreds(state, action) { + state.orgDefaultOdkCreds = action.payload; + }, }, }); diff --git a/src/frontend/src/store/types/ICreateProject.ts b/src/frontend/src/store/types/ICreateProject.ts index ce1200a5d8..3d33382c72 100644 --- a/src/frontend/src/store/types/ICreateProject.ts +++ b/src/frontend/src/store/types/ICreateProject.ts @@ -36,6 +36,7 @@ export type CreateProjectStateTypes = { isTasksGenerated: {}; isFgbFetching: boolean; toggleSplittedGeojsonEdit: boolean; + orgDefaultOdkCreds: boolean; }; export type ValidateCustomFormResponse = { detail: { message: string; possible_reason: string }; diff --git a/src/frontend/src/views/CreateOrganisation.tsx b/src/frontend/src/views/CreateOrganisation.tsx index 4ed89c1714..81578c3f58 100644 --- a/src/frontend/src/views/CreateOrganisation.tsx +++ b/src/frontend/src/views/CreateOrganisation.tsx @@ -2,6 +2,8 @@ import React, { useEffect } from 'react'; import CoreModules from '@/shared/CoreModules'; import environment from '@/environment'; import useForm from '@/hooks/useForm'; +import InputTextField from '@/components/common/InputTextField'; +import TextArea from '@/components/common/TextArea'; import OrganisationAddValidation from '@/components/organisation/Validation/OrganisationAddValidation'; import { PostOrganisationDataService } from '@/api/OrganisationService'; import { useNavigate, useSearchParams } from 'react-router-dom'; @@ -63,136 +65,90 @@ const CreateOrganisationForm = () => { borderRadius: 2, }} > -
- + + - - Organization Name - - * - - - - { handleCustomChange('name', e.target.value); }} - helperText={errors.name} - FormHelperTextProps={inputFormStyles()} + fieldType="text" + required + errorMsg={errors.name} /> - - - Website URL - - - * - - - { handleCustomChange('url', e.target.value); }} - fullWidth - helperText={errors.url} - FormHelperTextProps={inputFormStyles()} + fieldType="text" + required + errorMsg={errors.url} /> - - - Description - - - * - - - { handleCustomChange('description', e.target.value); }} - fullWidth - multiline - rows={4} - helperText={errors.description} - FormHelperTextProps={inputFormStyles()} + required + errorMsg={errors.description} /> - - - ODK Central URL (Optional) - - - { handleCustomChange('odk_central_url', e.target.value); }} - fullWidth - multiline - rows={1} - helperText={errors.odk_central_url} - FormHelperTextProps={inputFormStyles()} + fieldType="text" + errorMsg={errors.odk_central_url} /> - - - ODK Central User (Optional) - - - { handleCustomChange('odk_central_user', e.target.value); }} - fullWidth - multiline - rows={1} - helperText={errors.odk_central_user} - FormHelperTextProps={inputFormStyles()} + fieldType="text" + errorMsg={errors.odk_central_user} /> - - - ODK Central Password (Optional) - - - { handleCustomChange('odk_central_password', e.target.value); }} - fullWidth - multiline - rows={1} - helperText={errors.odk_central_password} - FormHelperTextProps={inputFormStyles()} + fieldType="password" + errorMsg={errors.odk_central_password} /> @@ -209,6 +165,7 @@ const CreateOrganisationForm = () => { '&.Mui-focused': { color: 'black', }, + fontWeight: 'bold', }} > Upload Logo