diff --git a/frontend/public/index.html b/frontend/public/index.html index a9db1db..de43004 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -29,7 +29,6 @@ href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet" /> - Tracer diff --git a/frontend/public/site.webmanifest b/frontend/public/site.webmanifest index 45dc8a2..fa99de7 100644 --- a/frontend/public/site.webmanifest +++ b/frontend/public/site.webmanifest @@ -1 +1,19 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/frontend/src/app/api/file.ts b/frontend/src/app/api/file.ts index 607ec01..d9e81ea 100644 --- a/frontend/src/app/api/file.ts +++ b/frontend/src/app/api/file.ts @@ -11,13 +11,6 @@ export interface IconNameRes { message: string; } - - - - - - - export const uploadIcon = async ( authorizationToken: string, orgName: string, @@ -35,10 +28,6 @@ export const uploadIcon = async ( return respnse; }; - - - - export const getIcon = async (authorizationToken: string, orgName: string) => { const url = BACKEND_URL + '/api/protected/file/getIcon/' + orgName; const response = await axios.get( @@ -55,8 +44,6 @@ export const getIcon = async (authorizationToken: string, orgName: string) => { return response; }; - - export const deleteFile = async ( authorizationToken: string, fileName: string @@ -71,9 +58,6 @@ export const deleteFile = async ( return respnse; }; - - - export const getIconName = async ( authorizationToken: string, orgName: string diff --git a/frontend/src/app/api/githubData.ts b/frontend/src/app/api/githubData.ts index 665dfae..8111994 100644 --- a/frontend/src/app/api/githubData.ts +++ b/frontend/src/app/api/githubData.ts @@ -25,7 +25,6 @@ export interface ProjectStats { contributors: Contributors; } - export interface OrgProjectGithubData { projects: ProjectsGithubData; } diff --git a/frontend/src/app/assets/icons/cross.svg b/frontend/src/app/assets/icons/cross.svg new file mode 100644 index 0000000..351d333 --- /dev/null +++ b/frontend/src/app/assets/icons/cross.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/app/components/search/index.tsx b/frontend/src/app/components/search/index.tsx index 99ac0fb..b78e628 100644 --- a/frontend/src/app/components/search/index.tsx +++ b/frontend/src/app/components/search/index.tsx @@ -6,7 +6,7 @@ import './index.scss'; const SearchBar = () => { const dispatch = useDispatch(); - const [search,setSearch] = useState('') + const [search, setSearch] = useState(''); const handleInputChange = (e: React.ChangeEvent) => { setSearch(e.target.value); }; diff --git a/frontend/src/app/components/timeRangeSwitch/index.tsx b/frontend/src/app/components/timeRangeSwitch/index.tsx index 6e62dec..7d8a15a 100644 --- a/frontend/src/app/components/timeRangeSwitch/index.tsx +++ b/frontend/src/app/components/timeRangeSwitch/index.tsx @@ -13,9 +13,7 @@ interface Props { const TimeRangeSwitch: React.FC = ({ weekly, setWeekly }) => { // const dispatch = useDispatch(); // const isWeekly = useSelector((state: timeRangeModel) => state.isWeekly.value); - useEffect(()=>{ - - },[weekly, setWeekly]) + useEffect(() => {}, [weekly, setWeekly]); return (
-
+ ); }; diff --git a/frontend/src/features/AddProject/types.ts b/frontend/src/features/AddProject/types.ts new file mode 100644 index 0000000..5a3fc2f --- /dev/null +++ b/frontend/src/features/AddProject/types.ts @@ -0,0 +1,20 @@ +import { ChangeEvent, FormEvent } from 'react'; + +export type _ADD_PROJECT_FORM_ERROR = { + name: string | null; + description: string | null; + link: string | null; +}; +export type _ADD_PROJECT_FORM = { + name: string; + description: string; + link: string; +}; +export type _ADD_PROJECT_FORM_CHANGE = ( + event: ChangeEvent, + index?: number +) => void; + +export type _FORM_SUBMIT = (event: FormEvent) => void; + +export type _VALIDATE_PROPS = (name: string, value: string) => string; diff --git a/frontend/src/features/AddProject/utils.ts b/frontend/src/features/AddProject/utils.ts new file mode 100644 index 0000000..4d61b7c --- /dev/null +++ b/frontend/src/features/AddProject/utils.ts @@ -0,0 +1,14 @@ +export function isGitHubRepositoryLink(link: string): boolean { + const githubRepoPattern = + /^https:\/\/github\.com\/[a-zA-Z0-9-]+\/[a-zA-Z0-9-]+$/; + const githubRepoPattern2 = + /^https:\/\/github\.com\/[a-zA-Z0-9-]+\/[a-zA-Z0-9-]+(\.git)?$/; + return githubRepoPattern.test(link) || githubRepoPattern2.test(link); +} + +export function isValidName(input: string): boolean { + // Regular expression to match only alphanumeric characters, hyphens, and underscores + const regex = /^[a-zA-Z0-9-_]+$/; + // Test if the input string matches the regular expression + return regex.test(input); +} diff --git a/frontend/src/features/AddWorkspace/index.scss b/frontend/src/features/AddWorkspace/index.scss index f6f5ed5..008ef66 100644 --- a/frontend/src/features/AddWorkspace/index.scss +++ b/frontend/src/features/AddWorkspace/index.scss @@ -20,6 +20,10 @@ $breakpoint-tablet: 768px; gap: 2rem; .submit { display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + gap: 10px; padding: 1rem 2rem; align-self: flex-end; font-size: 1.5rem; @@ -120,6 +124,9 @@ $breakpoint-tablet: 768px; border-radius: 2.3125rem; background: #402aa4; } + .add-member-button:disabled { + background-color: grey; + } } .added-members { diff --git a/frontend/src/features/AddWorkspace/index.tsx b/frontend/src/features/AddWorkspace/index.tsx index 3372f93..9f2423d 100644 --- a/frontend/src/features/AddWorkspace/index.tsx +++ b/frontend/src/features/AddWorkspace/index.tsx @@ -1,5 +1,5 @@ import { getAllUser } from 'app/api/user'; -import { ChangeEvent, useContext, useEffect, useState } from 'react'; +import { ChangeEvent, useContext, useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import toast from 'react-hot-toast'; import { addOrg, addOrgMembers, getAllOrgs } from 'app/api/organization'; @@ -9,65 +9,34 @@ import './index.scss'; import UserContext from 'app/context/user/userContext'; import { AVATAR_URL } from 'app/constants/api'; import { AVATAR_API } from 'envConstants'; +import Cross from '../../app/assets/icons/cross.svg'; +import { + _FORM_SUBMIT, + _VALIDATE_PROPS, + _WORKSPACE_FORM, + _WORKSPACE_FORM_CHANGE, + _WORKSPACE_FORM_ERROR, +} from './types'; const AddWorkspace = () => { 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,96 +44,178 @@ 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 SubmitHandler = async (): Promise => { - if ( - description && - token && - name && - validName && - uniqueName && - validDescription - ) { - const func = async (): Promise => { - const dataRes = await addOrg(token, { - name: name, - description: description, - }); + const validate: _VALIDATE_PROPS = (name, value) => { + 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 'description': + if (value.length > 200) { + return 'Description should be less then 200 characters'; + } + return ''; + default: + return ''; + } + }; - if (selectedFile != null) { - try{ - const fileRes = await uploadIcon(token, name, selectedFile); - }catch (e){ - } - } + 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 } = e.target; + const error = validate(name, value); + setFormErrors({ + ...formErrors, + [name]: error, + }); + }; - if (members.length > 0) { - try { - const addMmebersRes = await addOrgMembers(token, name, members); - } catch (e) {} + const handleSubmit: _FORM_SUBMIT = (event) => { + event.preventDefault(); + const workspace_error = validate('workspace', form.workspace); + const desc_error = validate('description', form.description); + setFormErrors({ + ...formErrors, + workspace: workspace_error, + description: desc_error, + }); + if (workspace_error || desc_error) { + if (workspace_error) toast.error('Check workspace field'); + if (desc_error) toast.error('Check description field'); + } else { + if (token) { + const newForm = form; + if (!form.description) { + newForm.description = ' '; } - navigate('/'); - }; + const func = async (): Promise => { + const dataRes = await addOrg(token, { + name: newForm.workspace, + description: newForm.description, + }); - toast.promise(func(), { - loading: 'Saving Workspace', - success: Workspace saved, - error: Could not save, - }); - } else { - toast.error('Invalid inputs'); + if (form.image) { + try { + const fileRes = await uploadIcon( + token, + form.workspace, + form.image + ); + } catch (e) {} + } + + if (form.members.length > 0) { + try { + const addMmebersRes = await addOrgMembers( + token, + form.workspace, + form.members + ); + } catch (e) {} + } + navigate('/'); + }; + + toast.promise(func(), { + loading: 'Saving Workspace', + success: Workspace saved, + error: Something's wrong with your inputs, + }); + } else { + toast.error(`Something's wrong with your 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

- {!name ?

Name feild should not be empty

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

Not a valid name

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

Name already taken. Try another name

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

{formErrors.workspace}

)}
@@ -207,34 +262,39 @@ const AddWorkspace = () => { id='workspace-description' type='text' className='custom-input' - value={description ? description : ''} - onChange={handleDesriptionChange} + name='description' + value={form.description} + onChange={handleChange} + onBlur={handleBlur} placeholder='workspace description' + maxLength={201} /> - {!description ?

Description feild should not be empty

: <>} - {!validDescription ? ( -

Characters length should be less than 200

- ) : ( - <> + {formErrors.description && ( +

{formErrors.description}

)} +
+
+
) => { - setMemberName(e.target.value); - }} + value={form.member} + name='member' + onChange={handleChange} placeholder='Github ID of user' />
- {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..c927168 --- /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) => string; diff --git a/frontend/src/features/EditProject/index.tsx b/frontend/src/features/EditProject/index.tsx index b7dd1e8..5ea2c97 100644 --- a/frontend/src/features/EditProject/index.tsx +++ b/frontend/src/features/EditProject/index.tsx @@ -1,15 +1,10 @@ -import { ChangeEvent, useEffect, useState } from 'react'; +import { ChangeEvent, useEffect, useState } from 'react'; import './index.scss'; // import tick from '../../app/assets/images/tick.png'; import { useNavigate, useParams } from 'react-router-dom'; import toast from 'react-hot-toast'; -import { - getProject, - updateProject, -} from 'app/api/project'; -import { Projects, getOrgProjects } from 'app/api/organization'; - - +import { getProject, updateProject } from 'app/api/project'; +import { Projects, getOrgProjects } from 'app/api/organization'; const EditProject = () => { const navigate = useNavigate(); @@ -111,7 +106,7 @@ const EditProject = () => { onChange={nameChange} value={name ? name : ''} /> - {!name ? 'Name feild should not be empty' : <>} + {!name ? 'Name field should not be empty' : <>} {name && !isValidName(name) && 'Not a valid name'} {name && name != projectName && @@ -124,7 +119,7 @@ const EditProject = () => { onChange={linkChange} placeholder='Github link of project' /> - {!link ? 'Link feild should not be empty' : <>} + {!link ? 'Link field should not be empty' : <>} {link && !isGitHubRepositoryLink(link) && 'Not a valid github repository link'} @@ -137,14 +132,14 @@ const EditProject = () => { } placeholder='Details about project' /> - {!description ? 'Description feild should not be empty' : <>} + {!description ? 'Description field should not be empty' : <>} {description && description.length >= 200 && 'Description length should not be greater than 200'} diff --git a/frontend/src/features/EditWorkspace/index.tsx b/frontend/src/features/EditWorkspace/index.tsx index 4bc35a9..391fc7b 100644 --- a/frontend/src/features/EditWorkspace/index.tsx +++ b/frontend/src/features/EditWorkspace/index.tsx @@ -1,13 +1,8 @@ import { getAllUser, getUser } from 'app/api/user'; -import { ChangeEvent, useContext, useEffect, useState } from 'react'; +import { ChangeEvent, useContext, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import toast from 'react-hot-toast'; -import { - - getAllOrgs, - getOrg, - updateOrg, -} from 'app/api/organization'; +import { getAllOrgs, getOrg, updateOrg } from 'app/api/organization'; import { uploadIcon } from 'app/api/file'; import './index.scss'; @@ -25,7 +20,6 @@ const EditWorkspace = () => { const [validName, setValidName] = useState(false); const [uniqueName, setUniqueName] = useState(false); - const [users, setUsers] = useState([]); const [orgs, setOrgs] = useState([]); @@ -119,15 +113,11 @@ const EditWorkspace = () => { description: description, }); - - if (selectedFile != null) { - try{ + if (selectedFile != null) { + try { const fileRes = await uploadIcon(token, name, selectedFile); - }catch(e){ - - } - } - + } catch (e) {} + } navigate('/'); }; @@ -173,7 +163,7 @@ const EditWorkspace = () => { onChange={handleNameChange} placeholder='workspace name' /> - {!name ?

Name feild should not be empty

: <>} + {!name ?

Name field should not be empty

: <>} {name != spaceName && !validName && name ? (

Not a valid name

) : ( @@ -197,7 +187,7 @@ const EditWorkspace = () => { onChange={handleDesriptionChange} placeholder='workspace description' /> - {!description ?

Description feild should not be empty

: <>} + {!description ?

Description field should not be empty

: <>} {!validDescription ? (

Characters length should be less than 200

) : ( diff --git a/frontend/src/features/ProjectAddMember /index.tsx b/frontend/src/features/ProjectAddMember /index.tsx index b08ff09..0e10397 100644 --- a/frontend/src/features/ProjectAddMember /index.tsx +++ b/frontend/src/features/ProjectAddMember /index.tsx @@ -1,12 +1,9 @@ - -import { ChangeEvent, useContext, useEffect, useState } from 'react'; +import { ChangeEvent, useContext, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { AVATAR_API } from 'envConstants'; import { AVATAR_URL } from 'app/constants/api'; import toast from 'react-hot-toast'; -import { - getOrgMembers, -} from 'app/api/organization'; +import { getOrgMembers } from 'app/api/organization'; import './index.scss'; import UserContext from 'app/context/user/userContext'; diff --git a/frontend/src/features/WorkspaceAddMember/index.tsx b/frontend/src/features/WorkspaceAddMember/index.tsx index 0126778..61e14d8 100644 --- a/frontend/src/features/WorkspaceAddMember/index.tsx +++ b/frontend/src/features/WorkspaceAddMember/index.tsx @@ -1,12 +1,8 @@ import { getAllUser, getUser } from 'app/api/user'; -import { ChangeEvent, useContext, useEffect, useState } from 'react'; +import { ChangeEvent, useContext, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import toast from 'react-hot-toast'; -import { - addOrgMembers, - getOrgMembers, -} from 'app/api/organization'; - +import { addOrgMembers, getOrgMembers } from 'app/api/organization'; import './index.scss'; import UserContext from 'app/context/user/userContext'; diff --git a/frontend/src/features/login/index.tsx b/frontend/src/features/login/index.tsx index 557ccdf..c367022 100644 --- a/frontend/src/features/login/index.tsx +++ b/frontend/src/features/login/index.tsx @@ -1,4 +1,3 @@ - import { CLIENT_ID } from '../../envConstants'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { login } from 'app/api/login'; diff --git a/frontend/src/features/project-members /components/MemberCard.tsx b/frontend/src/features/project-members /components/MemberCard.tsx index 88c24d7..74d3114 100644 --- a/frontend/src/features/project-members /components/MemberCard.tsx +++ b/frontend/src/features/project-members /components/MemberCard.tsx @@ -1,13 +1,9 @@ - import { changeProjectMembersStatus, removeProjectMembers, } from 'app/api/project'; import UserContext from 'app/context/user/userContext'; -import { - ChangeEvent, - useContext, -} from 'react'; +import { ChangeEvent, useContext } from 'react'; import toast from 'react-hot-toast'; const MemberCard = ({ diff --git a/frontend/src/features/project/components/contributorCard/index.tsx b/frontend/src/features/project/components/contributorCard/index.tsx index 0017431..08a1227 100644 --- a/frontend/src/features/project/components/contributorCard/index.tsx +++ b/frontend/src/features/project/components/contributorCard/index.tsx @@ -1,4 +1,3 @@ - import './index.scss'; import contributorPropTypes from 'app/models/contributorPropTypes'; import { AVATAR_API } from 'envConstants'; diff --git a/frontend/src/features/workspace-members /components/MemberCard.tsx b/frontend/src/features/workspace-members /components/MemberCard.tsx index d8b0ac4..236b691 100644 --- a/frontend/src/features/workspace-members /components/MemberCard.tsx +++ b/frontend/src/features/workspace-members /components/MemberCard.tsx @@ -1,9 +1,6 @@ import { changeOrgMembersStatus, removeOrgMembers } from 'app/api/organization'; import UserContext from 'app/context/user/userContext'; -import { - ChangeEvent, - useContext, -} from 'react'; +import { ChangeEvent, useContext } from 'react'; import toast from 'react-hot-toast'; const MemberCard = ({ diff --git a/frontend/src/features/workspace-view/index.tsx b/frontend/src/features/workspace-view/index.tsx index dab79b9..0a2eff4 100644 --- a/frontend/src/features/workspace-view/index.tsx +++ b/frontend/src/features/workspace-view/index.tsx @@ -1,9 +1,9 @@ import SearchBar from 'app/components/search'; -import { useContext, useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import './index.scss'; import WorkspaceCard from './workspace-card'; import UserContext from 'app/context/user/userContext'; -import { UserOrgs, getUserOrgs } from 'app/api/user'; +import { UserOrgs, getUserOrgs } from 'app/api/user'; import loader from '../../app/assets/gifs/loader.gif'; import { useNavigate } from 'react-router-dom'; import { useSelector } from 'react-redux'; @@ -35,12 +35,7 @@ const WorkspaceView = () => { }; useEffect(() => { fetchData(); - }, [ - userContext?.username, - navigate, - searchValue, - - ]); + }, [userContext?.username, navigate, searchValue]); const LogoutHandler = async () => { try { diff --git a/frontend/src/features/workspace-view/workspace-card/index.tsx b/frontend/src/features/workspace-view/workspace-card/index.tsx index 6df44b4..3d62eb5 100644 --- a/frontend/src/features/workspace-view/workspace-card/index.tsx +++ b/frontend/src/features/workspace-view/workspace-card/index.tsx @@ -5,8 +5,7 @@ import { deleteOrg, getOrg, getOrgMembers } from 'app/api/organization'; import { deleteFile, getIcon, getIconName } from 'app/api/file'; import UserContext from 'app/context/user/userContext'; import toast from 'react-hot-toast'; -import { FaBookmark } from "react-icons/fa"; - +import { FaBookmark } from 'react-icons/fa'; import { UserOrgDetails, @@ -28,10 +27,22 @@ interface members { [username: string]: string; } -const WorkspaceCard = ({ workspaceName, role, archeive, bookmark, archeives }: { workspaceName:string, role:string, archeive:boolean, bookmark:boolean, archeives:boolean }) => { +const WorkspaceCard = ({ + workspaceName, + role, + archeive, + bookmark, + archeives, +}: { + workspaceName: string; + role: string; + archeive: boolean; + bookmark: boolean; + archeives: boolean; +}) => { // const { workspaceName, role, archeive, bookmark, archeives } = props; - const [localArchive,setLocalArchive] = useState(archeive) - const [localBookmark,setLocalBookmark] = useState(bookmark) + const [localArchive, setLocalArchive] = useState(archeive); + const [localBookmark, setLocalBookmark] = useState(bookmark); const [description, setDescription] = useState(null); const [showPopUp, setShowPopUp] = useState(false); const token = localStorage.getItem('token'); @@ -107,7 +118,7 @@ const WorkspaceCard = ({ workspaceName, role, archeive, bookmark, archeives }: { userContext?.setUserOrgs(orgs); } }; - setLocalBookmark(!localBookmark) + setLocalBookmark(!localBookmark); if (initBmk) { toast.promise(func(), { loading: 'Unpinning', @@ -140,7 +151,7 @@ const WorkspaceCard = ({ workspaceName, role, archeive, bookmark, archeives }: { orgs.userOrgs[workspaceName].archeive = (!archeive).toString(); userContext?.setUserOrgs(orgs); } - setLocalArchive(!localArchive) + setLocalArchive(!localArchive); }; if (!initArc) { toast.promise(func(), { @@ -165,9 +176,8 @@ const WorkspaceCard = ({ workspaceName, role, archeive, bookmark, archeives }: { <> {localArchive == archeives && (
-
- {localBookmark&&} + {localBookmark && }
setShowPopUp(showPopUp ? false : true)} @@ -193,7 +203,7 @@ const WorkspaceCard = ({ workspaceName, role, archeive, bookmark, archeives }: { delete
)} - + {members && userContext?.username && members[userContext?.username.toString()] === 'admin' && ( @@ -222,7 +232,10 @@ const WorkspaceCard = ({ workspaceName, role, archeive, bookmark, archeives }: { ? "USER's WORKSPACE" : workspaceName}
-
navigate(`/workspaceMembers/${workspaceName}`)}> +
navigate(`/workspaceMembers/${workspaceName}`)} + >
{membersArray.length > 0 ? ( diff --git a/frontend/src/features/workspace/components/projectCard/index.scss b/frontend/src/features/workspace/components/projectCard/index.scss index eb9be42..a009fc6 100644 --- a/frontend/src/features/workspace/components/projectCard/index.scss +++ b/frontend/src/features/workspace/components/projectCard/index.scss @@ -7,7 +7,6 @@ height: 100%; min-height: 257px; padding: 1em; - } // .projectcard:hover { @@ -162,7 +161,6 @@ font-size: 1rem; } -.pinDiv{ +.pinDiv { height: 12px; - -} \ No newline at end of file +} diff --git a/frontend/src/features/workspace/components/projectCard/index.tsx b/frontend/src/features/workspace/components/projectCard/index.tsx index e1749dc..7b09a0e 100644 --- a/frontend/src/features/workspace/components/projectCard/index.tsx +++ b/frontend/src/features/workspace/components/projectCard/index.tsx @@ -1,7 +1,7 @@ -import { useContext, useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import './index.scss'; import { deleteProject, getMembers, getProject } from 'app/api/project'; -import { FaBookmark } from "react-icons/fa"; +import { FaBookmark } from 'react-icons/fa'; import { GetProject } from 'app/api/project'; import { AVATAR_URL } from 'app/constants/api'; import { AVATAR_API } from 'envConstants'; @@ -72,16 +72,15 @@ const ProjectCard: React.FC = ({ const temp = userOrgs; Object.entries(temp.userOrgs).map(([org]) => { if (org === orgName) { - if (temp.userOrgs[org].bookmark === "true" ) { - temp.userOrgs[org].bookmark = "false"; - } - else { - temp.userOrgs[org].bookmark = "true"; + if (temp.userOrgs[org].bookmark === 'true') { + temp.userOrgs[org].bookmark = 'false'; + } else { + temp.userOrgs[org].bookmark = 'true'; } } }); - setUserOrgs(userOrgs => { - return userOrgs = {...temp} + setUserOrgs((userOrgs) => { + return (userOrgs = { ...temp }); }); userContext?.setUserOrgs(userOrgs); }; @@ -101,7 +100,7 @@ const ProjectCard: React.FC = ({ } } }; - + const ArchiveHandler = async () => { if (token && orgName) { let initial = archive; @@ -109,25 +108,23 @@ const ProjectCard: React.FC = ({ const res = await setArcheiveStatus(token, orgName, { [projectName]: !archive, }); - + setArchive(!archive); status.archeive = !archive; const temp = userOrgs; Object.entries(temp.userOrgs).map(([org]) => { if (org === orgName) { - if (temp.userOrgs[org].archeive === "true" ) { - temp.userOrgs[org].archeive = "false"; - } - else { - temp.userOrgs[org].archeive = "true"; + if (temp.userOrgs[org].archeive === 'true') { + temp.userOrgs[org].archeive = 'false'; + } else { + temp.userOrgs[org].archeive = 'true'; } } }); - setUserOrgs(userOrgs => { - return userOrgs = {...temp} + setUserOrgs((userOrgs) => { + return (userOrgs = { ...temp }); }); userContext?.setUserOrgs(userOrgs); - }; if (initial) { @@ -141,7 +138,6 @@ const ProjectCard: React.FC = ({ loading: 'On progress', success: Project archived, error: Unable to arhive, - }); } } @@ -151,10 +147,10 @@ const ProjectCard: React.FC = ({ const func = async () => { const res = await deleteProject(token, projectName, orgName); // TODO update local state - if (userOrgs) {Object.entries(userOrgs.userOrgs) - .map(([org]) =>{ - }) - };} + if (userOrgs) { + Object.entries(userOrgs.userOrgs).map(([org]) => {}); + } + }; toast.promise(func(), { loading: 'On progress', success: Successfully deleted, @@ -172,7 +168,6 @@ const ProjectCard: React.FC = ({ userContext?.setUserOrgs(userOrgsRes.data); setUserOrgs(userOrgsRes.data); } catch (e) {} - } }; useEffect(() => { @@ -180,44 +175,44 @@ const ProjectCard: React.FC = ({ fetchProjectMembers(); fetchData(); }, []); - return (
- -
- {pin && } -
+
{pin && }

{projectName}

{project ? project.description : <>}

{(userContext?.userOrgs?.userOrgs[orgName].role === 'admin' || userContext?.userOrgs?.userOrgs[orgName].role === 'manager') && ( -
+
setShowPopUp(!showPopUp)} > - +
- {showPopUp &&
-
- {pin ? 'Unpin' : 'Pin'} + {showPopUp && ( +
+
+ {pin ? 'Unpin' : 'Pin'} +
+
+ {archive ? 'Unarchive' : 'Archive'} +
+
+ navigate(`/editProject/${orgName}/${projectName}`) + } + > + Edit +
+
+ Delete +
-
- {archive ? 'Unarchive' : 'Archive'} -
-
navigate(`/editProject/${orgName}/${projectName}`)} - > - Edit -
-
- Delete -
-
} -
+ )} +
)}
diff --git a/frontend/src/features/workspace/components/projectCardContainer/index.tsx b/frontend/src/features/workspace/components/projectCardContainer/index.tsx index 10ec8ea..ca703c3 100644 --- a/frontend/src/features/workspace/components/projectCardContainer/index.tsx +++ b/frontend/src/features/workspace/components/projectCardContainer/index.tsx @@ -26,26 +26,26 @@ const ProjectCardCont: React.FC = ({ }, [weekly]); return ( -
- {orgProjects && - Object.entries(orgProjects).map(([key, value]) => { - return ( - archives === value.archeive && ( - - ) - ); - })} -
+
+ {orgProjects && + Object.entries(orgProjects).map(([key, value]) => { + return ( + archives === value.archeive && ( + + ) + ); + })} +
); }; diff --git a/frontend/src/features/workspace/index.scss b/frontend/src/features/workspace/index.scss index 444d2b0..a515882 100644 --- a/frontend/src/features/workspace/index.scss +++ b/frontend/src/features/workspace/index.scss @@ -45,7 +45,6 @@ color: white; font-size: 0.9rem; background: var(--timerange-switch-btn-bg); - } .loader-container { diff --git a/frontend/src/features/workspace/index.tsx b/frontend/src/features/workspace/index.tsx index 868f90e..0ea79f2 100644 --- a/frontend/src/features/workspace/index.tsx +++ b/frontend/src/features/workspace/index.tsx @@ -1,15 +1,12 @@ -import { useContext, useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import SearchBar from 'app/components/search'; import TimeRangeSwitch from 'app/components/timeRangeSwitch'; import ProjectCardCont from './components/projectCardContainer'; import LeaderBoard from './components/leaderboard'; import './index.scss'; -import { useNavigate, useParams } from 'react-router-dom'; -import { getOrgProjects } from 'app/api/organization'; -import { - getOrgGithubData, - getOrgRank, -} from 'app/api/githubData'; +import { useNavigate, useParams } from 'react-router-dom'; +import { getOrgProjects } from 'app/api/organization'; +import { getOrgGithubData, getOrgRank } from 'app/api/githubData'; import { Projects } from 'app/api/organization'; import { ProjectsGithubData } from 'app/api/githubData'; import { Contributors } from 'app/api/githubData'; @@ -18,7 +15,6 @@ import UserContext from 'app/context/user/userContext'; import { UserOrgs, getUserOrgs } from 'app/api/user'; import { useSelector } from 'react-redux'; - const Workspace = () => { const searchValue = useSelector((state: any) => state.searchKeyword.value); const navigate = useNavigate(); @@ -43,8 +39,10 @@ const Workspace = () => { if (token && spaceName) { try { const orgProjects = await getOrgProjects(token, spaceName); - const temp = Object.entries(orgProjects.data.projects).filter(([key]) => key.toLowerCase().includes(searchValue.toLowerCase())); - setOrgProjects(Object.fromEntries(temp)) + const temp = Object.entries(orgProjects.data.projects).filter(([key]) => + key.toLowerCase().includes(searchValue.toLowerCase()) + ); + setOrgProjects(Object.fromEntries(temp)); } catch (e) { navigate('/'); } @@ -69,7 +67,7 @@ const Workspace = () => { }; const fetchData = async () => { - console.log(userContext?.username) + console.log(userContext?.username); if (token && userContext?.username) { try { const userOrgsRes = await getUserOrgs( @@ -79,7 +77,6 @@ const Workspace = () => { userContext?.setUserOrgs(userOrgsRes.data); setUserOrgs(userOrgsRes.data); } catch (e) {} - } }; @@ -102,18 +99,13 @@ const Workspace = () => { fetchOrgProjects(); fetchWeeklyData(); fetchMonthlyData(); - }, [spaceName,searchValue]); + }, [spaceName, searchValue]); return ( <>
- +