Skip to content

Commit 03e0ac1

Browse files
committed
feat: add workspace added
1 parent 46cdf0e commit 03e0ac1

File tree

10 files changed

+259
-11
lines changed

10 files changed

+259
-11
lines changed

package-lock.json

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"eslint-config-prettier": "^9.0.0",
1313
"react": "^18.2.0",
1414
"react-dom": "^18.2.0",
15+
"react-hot-toast": "^2.4.1",
1516
"react-query": "^3.39.3",
1617
"react-redux": "^8.1.3",
1718
"react-router-dom": "^6.16.0",

src/app/api/file.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
1-
import axios from 'axios';
1+
import axios, { AxiosResponse } from 'axios';
22
import { BACKEND_URL } from 'envConstants';
33

4+
5+
export interface FileUpload{
6+
7+
message: string,
8+
isSuccessful: boolean,
9+
statusCode: number,
10+
11+
}
12+
13+
14+
15+
416
export const uploadIcon = async (
517
authorizationToken: string,
618
orgName: string,
719
file: File
8-
) => {
20+
):Promise<AxiosResponse<FileUpload>> => {
921
const url = BACKEND_URL + '/api/protected/file/upload/' + orgName;
1022
const formData = new FormData();
1123
formData.append('file', file);
12-
const respnse = await axios.post(url, formData, {
24+
const respnse = await axios.post<FileUpload>(url, formData, {
1325
headers: {
1426
Accept: 'application/json',
1527
Authorization: `Bearer ${authorizationToken}`,

src/app/api/organization.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
import axios from 'axios';
1+
import axios, { AxiosResponse } from 'axios';
22
import { BACKEND_URL } from 'envConstants';
33

44
export interface organizationBody {
55
name: string;
66
description: string;
77
}
88

9+
10+
export interface AllOrgs{
11+
organizations: {
12+
id: number,
13+
name: string,
14+
description: string|null
15+
}[]
16+
}
17+
918
export const deleteOrg = async (
1019
authorizationToken: string,
1120
orgName: string
@@ -195,9 +204,9 @@ export const getOrg = async (authorizationToken: string, orgName: string) => {
195204
return respnse;
196205
};
197206

198-
export const getAllOrgs = async (authorizationToken: string) => {
207+
export const getAllOrgs = async (authorizationToken: string): Promise<AxiosResponse<AllOrgs>> => {
199208
const url = BACKEND_URL + '/api/protected/org/getAllOrg';
200-
const respnse = await axios.get(url, {
209+
const respnse = await axios.get<AllOrgs>(url, {
201210
headers: {
202211
Accept: 'application/json',
203212
Authorization: `Bearer ${authorizationToken}`,

src/app/api/user.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ export interface UserData{
99
}
1010

1111

12+
13+
export interface AllUserData{
14+
users: {
15+
id: number,
16+
username: string
17+
}[]
18+
}
19+
1220
export const getUser= async (authorizationToken: string):Promise<AxiosResponse<UserData>> => {
1321
const url = BACKEND_URL + '/api/protected/user/getUser';
1422

@@ -24,9 +32,9 @@ export const getUser= async (authorizationToken: string):Promise<AxiosResponse<U
2432

2533
};
2634

27-
export const getAllUser = async (authorizationToken: string) => {
35+
export const getAllUser = async (authorizationToken: string):Promise<AxiosResponse<AllUserData>> => {
2836
const url = BACKEND_URL + '/api/protected/user/all';
29-
const respnse = await axios.get(url, {
37+
const respnse = await axios.get<AllUserData>(url, {
3038
headers: {
3139
Accept: 'application/json',
3240
Authorization: `Bearer ${authorizationToken}`,

src/app/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import React from 'react';
22
import Navbar from 'app/components/navbar';
33
import BasicRoutes from 'app/routes/BasicRoutes';
44
import './index.scss';
5-
5+
import { Toaster } from 'react-hot-toast';
66
function App() {
77
return (
88
<>
99
<Navbar />
1010
<BasicRoutes />
11+
<Toaster/>
1112
</>
1213
);
1314
}

src/app/routes/BasicRoutes.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import AddProject from 'features/AddProject';
66
import Error from 'features/Error';
77
import WorkspaceView from 'features/workspace-view';
88
import Login from 'features/login';
9+
import AddWorkspace from 'features/AddWorkspace';
910
const BasicRoutes = () => {
1011
return (
1112
<Routes>
@@ -14,6 +15,7 @@ const BasicRoutes = () => {
1415
<Route path={'/addproject'} element={<AddProject />} />
1516
<Route path={'/workspace-view'} element={<WorkspaceView />} />
1617
<Route path={'/login'} element={<Login />} />
18+
<Route path={'/addWorkspace'} element={<AddWorkspace />} />
1719
<Route path={'/*'} element={<Error />} />
1820
</Routes>
1921
);

src/app/state/action-creators/usersActions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ export const setAllUsernames = (usernames: string[]) => {
1717
});
1818
};
1919
};
20+
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import { getAllUser, getUser } from 'app/api/user';
2+
import React, { ChangeEvent, useState } from 'react';
3+
import { useNavigate } from 'react-router-dom';
4+
import { useQuery } from 'react-query';
5+
import toast from 'react-hot-toast';
6+
import { addOrg, getAllOrgs } from 'app/api/organization';
7+
import { uploadIcon } from 'app/api/file';
8+
9+
const AddWorkspace = () => {
10+
const navigate = useNavigate();
11+
const token = localStorage.getItem('token');
12+
13+
const [selectedFile, setSelectedFile] = useState<File | null>(null);
14+
const [name, SetName] = useState<string | null>(null);
15+
const [description, setDiscription] = useState<string | null>(null);
16+
const [validName, setValidName] = useState<boolean>(false);
17+
18+
const [members, setMembers] = useState<string[]>([]);
19+
const [memberName, setMemberName]=useState<string| null>(null);
20+
21+
const [users, setUsers] = useState<string[]>([]);
22+
const [orgs, setOrgs] = useState<string[]>([]);
23+
24+
const dataFetch = async () => {
25+
try {
26+
if (token) {
27+
const users_aray: string[] = [];
28+
const org_aray: string[] = [];
29+
const allUser = await getAllUser(token);
30+
const allOrgs = await getAllOrgs(token);
31+
allUser.data.users.forEach((user) => {
32+
users_aray.push(user.username);
33+
});
34+
35+
allOrgs.data.organizations.forEach((org) => {
36+
org_aray.push(org.name);
37+
});
38+
39+
setUsers(users_aray);
40+
setOrgs(org_aray);
41+
}
42+
} catch (e) {}
43+
};
44+
45+
const checklogin = async () => {
46+
if (token != null) {
47+
const userData = await getUser(token);
48+
return userData.data
49+
} else {
50+
toast.error("Session expired")
51+
navigate('/login');
52+
}
53+
};
54+
55+
const { data,isError } = useQuery({
56+
queryFn: () => checklogin(),
57+
queryKey: 'checkLogin',
58+
});
59+
60+
if (isError) {
61+
toast.error("Session expired")
62+
navigate('/login');
63+
}
64+
65+
const {} = useQuery({
66+
queryFn: () => dataFetch(),
67+
queryKey: 'allUsersAndAllOrgs',
68+
});
69+
70+
const allowedFieTypes = ['image/jpeg', 'image/jpg', 'image/png'];
71+
72+
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
73+
const file = event.target.files?.[0];
74+
75+
if (file) {
76+
if (allowedFieTypes.includes(file.type)) {
77+
setSelectedFile(file);
78+
} else {
79+
setSelectedFile(null);
80+
toast.error('Invalid file type');
81+
}
82+
}
83+
};
84+
85+
function valid_name(str: string): boolean {
86+
// Define a regular expression for special characters (excluding letters, digits, and spaces)
87+
const specialCharacters = /[^a-zA-Z0-9\s]/;
88+
89+
// Check if the string contains any special characters
90+
return (
91+
specialCharacters.test(str) &&
92+
!str.endsWith('/userspace') &&
93+
!orgs.includes(str)
94+
);
95+
}
96+
97+
const handleNameChange = (event: ChangeEvent<HTMLInputElement>) => {
98+
SetName(event.target.value);
99+
100+
setValidName(() => valid_name(event.target.value));
101+
};
102+
103+
const handleDesriptionChange = (event: ChangeEvent<HTMLInputElement>) => {
104+
setDiscription(event.target.value);
105+
};
106+
107+
const addMembers= ()=>{
108+
if(memberName){
109+
if(users.includes(memberName)&& memberName!=data?.message){
110+
setMembers([...members,memberName])
111+
setMemberName(null)
112+
}
113+
}
114+
}
115+
116+
117+
const SubmitHandler=async():Promise<void>=>{
118+
119+
120+
if(validName&&description&&token&&name){
121+
try{
122+
const dataRes= await addOrg(token,{
123+
name:name,
124+
description:description
125+
})
126+
127+
}catch(e){
128+
toast.error('Try again!')
129+
return
130+
}
131+
try{
132+
if(selectedFile!=null){
133+
const fileRes= uploadIcon(token, name, selectedFile)
134+
}
135+
navigate("/workspace-view")
136+
137+
}catch(e){
138+
navigate("/workspace-view")
139+
}
140+
}else{
141+
toast.error('Invalid inputs')
142+
}
143+
144+
145+
}
146+
147+
toast.promise(
148+
SubmitHandler(),
149+
{
150+
loading: 'Saving Workspace',
151+
success: <b>Workspace saved</b>,
152+
error: <b>Could not save</b>,
153+
}
154+
);
155+
156+
157+
return (
158+
<div>
159+
<input type='file' onChange={handleFileChange} />
160+
161+
<p>Selected File: {selectedFile?.name}</p>
162+
<input
163+
type='text'
164+
value={name ? name : ''}
165+
onChange={handleNameChange}
166+
placeholder='Enter name'
167+
/>
168+
<input
169+
type='text'
170+
value={description ? description : ''}
171+
onChange={handleDesriptionChange}
172+
placeholder='Enter Description'
173+
/>
174+
175+
<input
176+
type='text'
177+
value={memberName ? memberName : ''}
178+
onChange={(e:ChangeEvent<HTMLInputElement>)=>{setMemberName(e.target.value)}}
179+
placeholder='Enter membername'
180+
/>
181+
<button onClick={addMembers} disabled={memberName?!users.includes(memberName)&& memberName==data?.message:true}>Add Memeber</button>
182+
<p>{members}</p>
183+
<button onClick={SubmitHandler}>Submit</button>
184+
</div>
185+
);
186+
};
187+
188+
export default AddWorkspace;

0 commit comments

Comments
 (0)