diff --git a/frontend/src/features/AddProject/index.tsx b/frontend/src/features/AddProject/index.tsx index 24e8589..2a7a0bc 100644 --- a/frontend/src/features/AddProject/index.tsx +++ b/frontend/src/features/AddProject/index.tsx @@ -147,7 +147,7 @@ const AddProject = () => { autoComplete='off' noValidate > -
Name
+
Name*
{ required /> {formErrors.name &&

{formErrors.name}

} -
Project link
+
Project link*
{ const navigate = useNavigate(); const token = localStorage.getItem('token'); const userContext = useContext(UserContext); - - const [selectedFile, setSelectedFile] = useState(null); - const [name, SetName] = useState(null); - const [description, setDiscription] = useState(null); - const [validDescription, setValidDescription] = useState(true); - const [validName, setValidName] = useState(false); - const [uniqueName, setUniqueName] = useState(false); - const [members, setMembers] = useState([]); - const [memberName, setMemberName] = useState(null); + const [form, setForm] = useState<_WORKSPACE_FORM>({ + workspace: '', + description: '', + members: [], + image: undefined, + member: '', + }); + const [formErrors, setFormErrors] = useState<_WORKSPACE_FORM_ERROR>( + {} as _WORKSPACE_FORM_ERROR + ); const [users, setUsers] = useState([]); const [orgs, setOrgs] = useState([]); - const dataFetch = async () => { - try { - if (token) { - const users_aray: string[] = []; - const org_aray: string[] = []; - const allUser = await getAllUser(token); - const allOrgs = await getAllOrgs(token); - allUser.data.users.forEach((user) => { - users_aray.push(user.username); - }); - - allOrgs.data.organizations.forEach((org) => { - org_aray.push(org.name); - }); - - setUsers(users_aray); - setOrgs(org_aray); - } - } catch (e) {} - }; - - useEffect(() => { - dataFetch(); - }, []); - - const allowedFieTypes = ['image/jpeg', 'image/jpg', 'image/png']; - - const handleFileChange = (event: ChangeEvent) => { - const file = event.target.files?.[0]; - - if (file) { - if (allowedFieTypes.includes(file.type)) { - setSelectedFile(file); - } else { - setSelectedFile(null); - toast.error('Invalid file type'); - } - } - }; - - function valid_name(str: string): boolean { + function isValidName(str: string): boolean { // Define a regular expression for special characters (excluding letters, digits, and spaces) const specialCharacters = /^[a-zA-Z0-9_-]+$/; @@ -75,76 +43,123 @@ const AddWorkspace = () => { return specialCharacters.test(str) && !str.endsWith('-userspace'); } - function isUniqueName(str: string): boolean { + function isUnique(str: string): boolean { return !orgs.includes(str); } - const handleNameChange = (event: ChangeEvent) => { - SetName(event.target.value); - setUniqueName(() => isUniqueName(event.target.value)); - setValidName(() => valid_name(event.target.value)); - }; - - const handleDesriptionChange = (event: ChangeEvent) => { - setDiscription(event.target.value); - if (description?.length) { - setValidDescription(description.length < 200); - } - }; - const addMembers = () => { - if (memberName) { + if (form.member) { if ( - users.includes(memberName) && - memberName != userContext?.username && - !members.includes(memberName) + users.includes(form.member) && + form.member != userContext?.username && + !form.members.includes(form.member) ) { - setMembers([...members, memberName]); - setMemberName(null); + setForm({ ...form, members: [...form.members, form.member] }); + setForm({ ...form, member: '' }); + console.log(form); } } }; const removeMembers = (member: string) => { - const indexToRemove = members.indexOf(member); + const indexToRemove = form.members.indexOf(member); if (indexToRemove !== -1) { const updatedMembers = [ - ...members.slice(0, indexToRemove), - ...members.slice(indexToRemove + 1), + ...form.members.slice(0, indexToRemove), + ...form.members.slice(indexToRemove + 1), ]; - setMembers(updatedMembers); + setForm({ ...form, members: updatedMembers }); } else { console.warn(`Member "${member}" not found in the members array.`); } }; + + const validate: _VALIDATE_PROPS = (name, value,files) => { + switch (name) { + case 'workspace': + if (!value) { + return 'Workspace Name is required'; + } else if (!isValidName(value)) { + return 'Workspace Name can only contain alphanumeric characters, hyphens, and underscores'; + } else if (!isUnique(value)) { + return 'Workspace name already exist'; + } + return ''; + case 'image': + if (!FileList) { + return "File is required" + } + return '' + case 'description': + if (value.length>200) { + return "Description should be less then 200 characters" + } + return '' + default: + return ''; + } + }; + + const handleChange: _WORKSPACE_FORM_CHANGE = (event) => { + const { name, value } = event.target; + switch (name) { + case 'image': + const file = event.target.files?.[0]; + setForm({ ...form, image: file }); + break; + case 'workspace': + setForm({ ...form, workspace: value }); + break; + case 'description': + setForm({ ...form, description: value }); + break; + case 'member': + setForm({ ...form, member: value }); + break; + } + }; + const handleBlur = (e: React.FocusEvent) => { + const { name, value,files } = e.target; + const error = validate(name, value,files); + setFormErrors({ + ...formErrors, + [name]: error, + }); + }; + + const handleSubmit = () => {}; + const SubmitHandler = async (): Promise => { if ( - description && + form.description && token && - name && - validName && - uniqueName && - validDescription + form.workspace + // && + // validName && + // uniqueName && + // validDescription ) { const func = async (): Promise => { const dataRes = await addOrg(token, { - name: name, - description: description, + name: form.workspace, + description: form.description, }); + if (form.image) { + try { + const fileRes = await uploadIcon(token, form.workspace, form.image); + } catch (e) {} + } - if (selectedFile != null) { - try{ - const fileRes = await uploadIcon(token, name, selectedFile); - }catch (e){ - } - } - - if (members.length > 0) { + if (form.members.length > 0) { try { - const addMmebersRes = await addOrgMembers(token, name, members); + const addMmebersRes = await addOrgMembers( + token, + form.workspace, + form.members + ); } catch (e) {} } navigate('/'); @@ -159,12 +174,40 @@ const AddWorkspace = () => { toast.error('Invalid inputs'); } }; + const dataFetch = async () => { + try { + if (token) { + const users_arr: string[] = []; + const org_arr: string[] = []; + const allUser = await getAllUser(token); + const allOrgs = await getAllOrgs(token); + allUser.data.users.forEach((user) => { + users_arr.push(user.username); + }); + + allOrgs.data.organizations.forEach((org) => { + org_arr.push(org.name); + }); + setUsers(users_arr); + setOrgs(org_arr); + } + } catch (e) {} + }; + useEffect(() => { + dataFetch(); + }, []); return (
-
+
- +

Add Icon*

+ {formErrors.image &&

{formErrors.image}

}
- {!name ?

Name field should not be empty

: <>} - {!validName && name ?

Not a valid name

: <>} - {!uniqueName && name ? ( -

Name already taken. Try another name

- ) : ( - <> - )} + {formErrors.workspace &&

{formErrors.workspace}

}
+
- {members.map((member, index) => { - return ( -
- {member}

{' '} - -
- ); - })} + {form.members.map((member, index) => ( +
+ {member}

+ +
+ ))}
- - -
+ +
); }; diff --git a/frontend/src/features/AddWorkspace/types.ts b/frontend/src/features/AddWorkspace/types.ts new file mode 100644 index 0000000..01bd5d5 --- /dev/null +++ b/frontend/src/features/AddWorkspace/types.ts @@ -0,0 +1,23 @@ +import { ChangeEvent, FormEvent } from 'react'; + +export type _WORKSPACE_FORM_ERROR = { + workspace: string | null; + description: string | null; + image: string | null; + member: string | null; +}; +export type _WORKSPACE_FORM = { + workspace: string; + description: string; + image: File | undefined; + members: string[]; + member:string; + }; +export type _WORKSPACE_FORM_CHANGE = ( + event: ChangeEvent, + index?: number +) => void; + +export type _FORM_SUBMIT = (event: FormEvent) => void; + +export type _VALIDATE_PROPS = (name: string, value: string, files:FileList|null) => string;