From 59a01ed218091559c05611be5d1146751879d1e3 Mon Sep 17 00:00:00 2001 From: Karthik Ayangar Date: Fri, 29 Dec 2023 23:34:02 +0530 Subject: [PATCH 1/2] feat: add workspace page Signed-off-by: Karthik Ayangar --- src/features/AddWorkspace/index.scss | 162 +++++++++++++++++++ src/features/AddWorkspace/index.tsx | 230 +++++++++++++++++++-------- 2 files changed, 322 insertions(+), 70 deletions(-) create mode 100644 src/features/AddWorkspace/index.scss diff --git a/src/features/AddWorkspace/index.scss b/src/features/AddWorkspace/index.scss new file mode 100644 index 0000000..f6f5ed5 --- /dev/null +++ b/src/features/AddWorkspace/index.scss @@ -0,0 +1,162 @@ +$breakpoint-tablet: 768px; +.main_aworkspace_container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: max-content; + padding: 2rem; + .addworkspace-form-container { + background: linear-gradient(110.51deg, #141432 0.9%, #2a2a4b 101.51%); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + padding: 2rem 1rem; + border-radius: 1.25rem; + gap: 2rem; + .submit { + display: flex; + padding: 1rem 2rem; + align-self: flex-end; + font-size: 1.5rem; + border-radius: 0.875rem; + background: #402aa4; + color: white; + outline: none; + border: none; + } + } + + .single-form-element-container { + display: flex; + flex-direction: column; + gap: 1rem; + width: 100%; + .label { + color: #8181ff; + font-size: 1.5rem; + font-weight: 900; + } + } +} + +.custom-input { + box-sizing: border-box; + border: 0.8px solid #402aa4; + border-radius: 14px; + background-color: transparent; + align-items: flex-start; + color: rgba(173, 173, 255, 0.75); + padding: 1.5rem 1rem; + font-size: 1.25rem; + font-family: 'Poppins'; + outline: none; +} + +.custom-input::placeholder { + color: rgba(173, 173, 255, 0.75); + font-family: Poppins; + font-size: 1.25rem; + font-weight: 100; + line-height: normal; +} + +.file-input-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + max-width: 30rem; + padding: 2rem; + border-radius: 1.25rem; + background: linear-gradient( + 138deg, + rgba(20, 20, 50, 0.7) 5.19%, + rgba(20, 20, 50, 0.7) 97.11% + ); + backdrop-filter: blur(25px); + + .custom-file-input { + visibility: hidden; + } + .file-label { + width: fit-content; + padding: 0.4375rem 0.5625rem; + border-radius: 1.75rem; + background: #402aa4; + color: white; + } +} + +.add-member-container { + position: relative; + box-sizing: border-box; + border: 0.8px solid #402aa4; + border-radius: 14px; + display: flex; + flex-direction: row; + outline: #141432; + .custom-input { + display: flex; + width: 100%; + border: none; + outline: none; + } + button { + border: none; + display: flex; + justify-content: center; + align-items: center; + font-size: 1.25rem; + margin: 0.75rem 1rem; + color: white; + width: 7rem; + font-weight: 100 !important; + border-radius: 2.3125rem; + background: #402aa4; + } +} + +.added-members { + display: flex; + flex-direction: row; + gap: 2rem; + flex-wrap: wrap; + width: 100%; + .member-card { + display: inline-flex; + padding: 0.4375rem 0.875rem 0.625rem 0.875rem; + justify-content: center; + align-items: center; + gap: 0.5625rem; + color: #8989ce; + border-radius: 0.75rem; + background: #26264e; + .member-avatar { + width: 40px; + height: 40px; + } + .btn-cross { + appearance: none; + border: none; + display: flex; + justify-content: center; + align-items: center; + background-color: transparent; + } + } +} + +@media (min-width: $breakpoint-tablet) { + .main_aworkspace_container { + padding: 2rem 5rem; + .addworkspace-form-container { + padding: 2rem 5rem; + } + } +} diff --git a/src/features/AddWorkspace/index.tsx b/src/features/AddWorkspace/index.tsx index 6d93760..99c9c39 100644 --- a/src/features/AddWorkspace/index.tsx +++ b/src/features/AddWorkspace/index.tsx @@ -6,6 +6,8 @@ import toast from 'react-hot-toast'; import { addOrg, getAllOrgs } from 'app/api/organization'; import { uploadIcon } from 'app/api/file'; +import './index.scss'; + const AddWorkspace = () => { const navigate = useNavigate(); const token = localStorage.getItem('token'); @@ -16,7 +18,7 @@ const AddWorkspace = () => { const [validName, setValidName] = useState(false); const [members, setMembers] = useState([]); - const [memberName, setMemberName]=useState(null); + const [memberName, setMemberName] = useState(null); const [users, setUsers] = useState([]); const [orgs, setOrgs] = useState([]); @@ -45,20 +47,20 @@ const AddWorkspace = () => { const checklogin = async () => { if (token != null) { const userData = await getUser(token); - return userData.data + return userData.data; } else { - toast.error("Session expired") + toast.error('Session expired'); navigate('/login'); } }; - const { data,isError } = useQuery({ + const { data, isError } = useQuery({ queryFn: () => checklogin(), queryKey: 'checkLogin', }); if (isError) { - toast.error("Session expired") + toast.error('Session expired'); navigate('/login'); } @@ -104,83 +106,171 @@ const AddWorkspace = () => { setDiscription(event.target.value); }; - const addMembers= ()=>{ - if(memberName){ - if(users.includes(memberName)&& memberName!=data?.message){ - setMembers([...members,memberName]) - setMemberName(null) + const addMembers = () => { + if (memberName) { + if (users.includes(memberName) && memberName != data?.message) { + setMembers([...members, memberName]); + setMemberName(null); } } - } + }; + const removeMembers = (member: string) => { + const indexToRemove = members.indexOf(member); - const SubmitHandler=async():Promise=>{ + if (indexToRemove !== -1) { + const updatedMembers = [ + ...members.slice(0, indexToRemove), + ...members.slice(indexToRemove + 1), + ]; + setMembers(updatedMembers); + } else { + console.warn(`Member "${member}" not found in the members array.`); + } + }; - if(validName&&description&&token&&name){ - try{ - const dataRes= await addOrg(token,{ - name:name, - description:description - }) - - }catch(e){ - toast.error('Try again!') - return - } - try{ - if(selectedFile!=null){ - const fileRes= uploadIcon(token, name, selectedFile) + const SubmitHandler = async (): Promise => { + if (validName && description && token && name) { + try { + const dataRes = await addOrg(token, { + name: name, + description: description, + }); + } catch (e) { + toast.error('Try again!'); + return; + } + try { + if (selectedFile != null) { + const fileRes = uploadIcon(token, name, selectedFile); } - navigate("/workspace-view") - - }catch(e){ - navigate("/workspace-view") + navigate('/workspace-view'); + } catch (e) { + navigate('/workspace-view'); } - }else{ - toast.error('Invalid inputs') + } else { + toast.error('Invalid inputs'); } + }; - - } - - toast.promise( - SubmitHandler(), - { - loading: 'Saving Workspace', - success: Workspace saved, - error: Could not save, - } - ); - + toast.promise(SubmitHandler(), { + loading: 'Saving Workspace', + success: Workspace saved, + error: Could not save, + }); return ( -
- - -

Selected File: {selectedFile?.name}

- - - - )=>{setMemberName(e.target.value)}} - placeholder='Enter membername' - /> - -

{members}

- +
+
+
+ +
+ + +

Supported formats: JPEG, JPG, PNG

+

Selected File: {selectedFile?.name}

+
+
+
+ + +
+
+ + +
+ +
+ +
+ ) => { + setMemberName(e.target.value); + }} + placeholder='Github ID of user' + /> + +
+
+
+ {members.map((member, index) => { + return ( +
+ {' '} +

{member}

{' '} + +
+ ); + })} +
+ + +
); }; From 6b85e27abf2f9b62a3d299b7b095e1a259a9efbb Mon Sep 17 00:00:00 2001 From: Karthik Ayangar Date: Fri, 29 Dec 2023 23:36:31 +0530 Subject: [PATCH 2/2] chore: ran prettier Signed-off-by: Karthik Ayangar --- docker-compose.yaml | 16 ++-- src/app/api/file.ts | 16 ++-- src/app/api/login.ts | 15 ++-- src/app/api/organization.ts | 15 ++-- src/app/api/user.ts | 44 ++++++----- src/app/index.tsx | 2 +- src/app/state/action-creators/usersActions.ts | 1 - src/features/login/index.tsx | 75 ++++++++----------- src/index.tsx | 14 ++-- 9 files changed, 90 insertions(+), 108 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 6df6d6e..9265be0 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,11 +1,11 @@ version: '3.3' services: api: - build: - context: ./ - dockerfile: local.Dockerfile - volumes: - - ./:/app - - ./.m2:/root/.m2 - working_dir: /app - command: sh run.sh \ No newline at end of file + build: + context: ./ + dockerfile: local.Dockerfile + volumes: + - ./:/app + - ./.m2:/root/.m2 + working_dir: /app + command: sh run.sh diff --git a/src/app/api/file.ts b/src/app/api/file.ts index b187ec4..821e22b 100644 --- a/src/app/api/file.ts +++ b/src/app/api/file.ts @@ -1,23 +1,17 @@ import axios, { AxiosResponse } from 'axios'; import { BACKEND_URL } from 'envConstants'; - -export interface FileUpload{ - - message: string, - isSuccessful: boolean, - statusCode: number, - +export interface FileUpload { + message: string; + isSuccessful: boolean; + statusCode: number; } - - - export const uploadIcon = async ( authorizationToken: string, orgName: string, file: File -):Promise> => { +): Promise> => { const url = BACKEND_URL + '/api/protected/file/upload/' + orgName; const formData = new FormData(); formData.append('file', file); diff --git a/src/app/api/login.ts b/src/app/api/login.ts index 6f1f1c9..2fdfa66 100644 --- a/src/app/api/login.ts +++ b/src/app/api/login.ts @@ -2,15 +2,16 @@ import axios from 'axios'; import { BACKEND_URL } from 'envConstants'; import { AxiosResponse } from 'axios'; - -export interface LoginData{ - token: string, - username: string, - type: string, - id: number +export interface LoginData { + token: string; + username: string; + type: string; + id: number; } -export const login = async (code: string):Promise> => { +export const login = async ( + code: string +): Promise> => { const url = BACKEND_URL + '/api/auth/login'; const respnse = await axios.post( url, diff --git a/src/app/api/organization.ts b/src/app/api/organization.ts index e182af3..2cba422 100644 --- a/src/app/api/organization.ts +++ b/src/app/api/organization.ts @@ -6,13 +6,12 @@ export interface organizationBody { description: string; } - -export interface AllOrgs{ +export interface AllOrgs { organizations: { - id: number, - name: string, - description: string|null - }[] + id: number; + name: string; + description: string | null; + }[]; } export const deleteOrg = async ( @@ -204,7 +203,9 @@ export const getOrg = async (authorizationToken: string, orgName: string) => { return respnse; }; -export const getAllOrgs = async (authorizationToken: string): Promise> => { +export const getAllOrgs = async ( + authorizationToken: string +): Promise> => { const url = BACKEND_URL + '/api/protected/org/getAllOrg'; const respnse = await axios.get(url, { headers: { diff --git a/src/app/api/user.ts b/src/app/api/user.ts index 5b6fbfd..ad71ade 100644 --- a/src/app/api/user.ts +++ b/src/app/api/user.ts @@ -1,38 +1,36 @@ -import axios,{AxiosResponse} from 'axios'; +import axios, { AxiosResponse } from 'axios'; import { BACKEND_URL } from 'envConstants'; - - - -export interface UserData{ - message: string +export interface UserData { + message: string; } - - -export interface AllUserData{ +export interface AllUserData { users: { - id: number, - username: string - }[] + id: number; + username: string; + }[]; } -export const getUser= async (authorizationToken: string):Promise> => { +export const getUser = async ( + authorizationToken: string +): Promise> => { const url = BACKEND_URL + '/api/protected/user/getUser'; - const respnse = await axios.get(url, { - headers: { - Accept: 'application/json', - - Authorization: `Bearer ${authorizationToken}`, - }, - }); - - return respnse; + const respnse = await axios.get(url, { + headers: { + Accept: 'application/json', + + Authorization: `Bearer ${authorizationToken}`, + }, + }); + return respnse; }; -export const getAllUser = async (authorizationToken: string):Promise> => { +export const getAllUser = async ( + authorizationToken: string +): Promise> => { const url = BACKEND_URL + '/api/protected/user/all'; const respnse = await axios.get(url, { headers: { diff --git a/src/app/index.tsx b/src/app/index.tsx index c71f936..062bd6b 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -8,7 +8,7 @@ function App() { <> - + ); } diff --git a/src/app/state/action-creators/usersActions.ts b/src/app/state/action-creators/usersActions.ts index 3911e53..e7078bc 100644 --- a/src/app/state/action-creators/usersActions.ts +++ b/src/app/state/action-creators/usersActions.ts @@ -17,4 +17,3 @@ export const setAllUsernames = (usernames: string[]) => { }); }; }; - diff --git a/src/features/login/index.tsx b/src/features/login/index.tsx index 33dff2d..2e44165 100644 --- a/src/features/login/index.tsx +++ b/src/features/login/index.tsx @@ -1,60 +1,51 @@ - - import { useEffect } from 'react'; import { CLIENT_ID } from '../../envConstants'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { login } from 'app/api/login'; import { useQuery } from 'react-query'; -import {getUser } from 'app/api/user'; +import { getUser } from 'app/api/user'; import toast from 'react-hot-toast'; - const Login = () => { - const [searchParam, ] = useSearchParams(); + const [searchParam] = useSearchParams(); const navigate = useNavigate(); - const token=localStorage.getItem('token') - const checklogin=async()=>{ - if(token!=null){ - try{ - const userData= await getUser(token); - navigate('/') - - }catch(e){ - navigate('/login') - } - + const token = localStorage.getItem('token'); + const checklogin = async () => { + if (token != null) { + try { + const userData = await getUser(token); + navigate('/'); + } catch (e) { + navigate('/login'); + } } - } + }; - useEffect(()=>{ - checklogin() - },[]) - - + useEffect(() => { + checklogin(); + }, []); - const loginFunc= async()=>{ - - if(searchParam.get('code')!==null){ - console.log("hello") - const code:string= searchParam.get('code')!; - const loginData= await login(code); - const token= loginData.data.token - localStorage.setItem('token',token) - toast.success('Login successfull') - navigate("/") - } - - } + const loginFunc = async () => { + if (searchParam.get('code') !== null) { + console.log('hello'); + const code: string = searchParam.get('code')!; + const loginData = await login(code); + const token = loginData.data.token; + localStorage.setItem('token', token); + toast.success('Login successfull'); + navigate('/'); + } + }; - const {isError}=useQuery({ - queryFn: ()=>loginFunc(), - queryKey:"loginData" - }) + const { isError } = useQuery({ + queryFn: () => loginFunc(), + queryKey: 'loginData', + }); - if(isError){ - toast.error('Some error occured') - navigate("/login") + if (isError) { + toast.error('Some error occured'); + navigate('/login'); } function loginWithGithub() { diff --git a/src/index.tsx b/src/index.tsx index 062718b..8289a63 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,22 +7,20 @@ import { store } from 'app/state/store'; import { Provider } from 'react-redux'; import { QueryClient, QueryClientProvider } from 'react-query'; - -const queryClient= new QueryClient() +const queryClient = new QueryClient(); const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); - root.render( - - - - - + + + + + );