Skip to content

Commit 6e0c306

Browse files
author
Alexandra Zwinger
committed
Add Module Creation
1 parent 21a0e7b commit 6e0c306

File tree

9 files changed

+156
-42
lines changed

9 files changed

+156
-42
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@
2121
npm-debug.log*
2222
yarn-debug.log*
2323
yarn-error.log*
24+
25+
package-lock.json

src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function App() {
4646
export enum Resources {
4747
MEETING = "meeting",
4848
USER = "user",
49-
MODULES = "modules",
49+
MODULES = "module",
5050
USERGROUP = "studygroup"
5151
}
5252

src/api/ModuleApi.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import {AxiosInstance} from "axios";
22
import {Resources} from "../App";
33
import {handleErrorResponse, handleSuccessResponse} from "./ErrorHandling";
4+
import {ModuleDto} from "../dtos/ModuleDto";
45

5-
export function getModules(axios: AxiosInstance): Promise<string[]> {
6+
export function getModules(axios: AxiosInstance): Promise<ModuleDto[]> {
67
const url = `/${Resources.MODULES}`;
78
return axios.get(url)
89
.then(handleSuccessResponse, handleErrorResponse);
10+
}
11+
12+
export function createModule(axios: AxiosInstance, moduleName: string) {
13+
const url = `/${Resources.MODULES}`;
14+
axios.post(url, {name: moduleName})
15+
.then(handleSuccessResponse, handleErrorResponse);
916
}

src/api/UserApi.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {AxiosInstance} from "axios";
22
import {Resources} from "../App";
33
import {handleErrorResponse, handleSuccessResponse} from "./ErrorHandling";
44
import {UserDto} from "../dtos/UserDto";
5+
import {ModuleDto} from "../dtos/ModuleDto";
56

67
export function getUser(axios: AxiosInstance): Promise<UserDto> {
78
return axios.get(Resources.USER)
@@ -11,4 +12,9 @@ export function getUser(axios: AxiosInstance): Promise<UserDto> {
1112
export function updateUsername(axios: AxiosInstance, name: string) {
1213
return axios.post(Resources.USER, {username: name})
1314
.then(handleSuccessResponse, handleErrorResponse);
14-
}
15+
}
16+
17+
export function updateUserModules(axios: AxiosInstance, modules: ModuleDto[]) {
18+
return axios.put(Resources.USER, modules)
19+
.then(handleSuccessResponse, handleErrorResponse);
20+
}

src/api/UserGroupApi.tsx

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,21 @@ import {AxiosInstance} from "axios";
22
import {Resources} from "../App";
33
import {handleErrorResponse, handleSuccessResponse} from "./ErrorHandling";
44

5-
65
export function joinStudyGroup(axios: AxiosInstance, meetingId: string): Promise<void> {
7-
return axios.post(`/${Resources.USERGROUP}`, { meetingId })
6+
return axios.post(`/${Resources.USERGROUP}`, {meetingId})
87
.then(handleSuccessResponse, handleErrorResponse);
98
}
109

11-
1210
export async function getUserIdsForMeeting(axios: AxiosInstance, uuid: string): Promise<string[]> {
13-
14-
const res = await axios.get(`/studygroup?uuid=${uuid}`);
15-
const data = res.data;
16-
const userIds = data.map((entry: { userId: string }) => entry.userId);
17-
return userIds;
11+
const res = await axios.get(`/studygroup?uuid=${uuid}`);
12+
const data = res.data;
13+
const userIds = data.map((entry: { userId: string }) => entry.userId);
14+
return userIds;
1815
}
1916

20-
21-
22-
export function leaveStudyGroup(axios: AxiosInstance, targetUUID: string): Promise<void> {
23-
return axios.delete(`/${Resources.USERGROUP}`, {
24-
params: { targetUUID } })
17+
export function leaveStudyGroup(axios: AxiosInstance, targetUUID: string): Promise<void> {
18+
return axios.delete(`/${Resources.USERGROUP}`, {
19+
params: {targetUUID}
20+
})
2521
.then(handleSuccessResponse, handleErrorResponse);
26-
}
22+
}

src/dtos/ModuleDto.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type ModuleDto = {
2+
name: string;
3+
}

src/form/CreateOrUpdateMeetingForm.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {CreateMeetingDto, MeetingDto} from "../dtos/MeetingDto";
1515
import axiosInstance from "../AxiosConfig";
1616
import {getModules} from "../api/ModuleApi";
1717
import {ChangeType} from "../enum/ChangeType";
18+
import {ModuleDto} from "../dtos/ModuleDto";
1819

1920
interface MeetingFormProps {
2021
open: boolean;
@@ -37,7 +38,7 @@ export function CreateOrUpdateMeetingForm({open, onClose, meeting, onlyThisMeeti
3738
const [time1, setTime1] = useState<Dayjs>(meeting ? dateFrom : dayjs().hour(12).minute(0).second(0));
3839
const [date2, setDate2] = useState<Dayjs>(meeting ? dateUntil : dayjs());
3940
const [time2, setTime2] = useState<Dayjs>(meeting ? dateUntil : dayjs().hour(13).minute(0).second(0));
40-
const [moduleNames, setModuleNames] = useState<string[]>([]);
41+
const [moduleNames, setModuleNames] = useState<ModuleDto[]>([]);
4142

4243
useEffect(() => {
4344
fetchModuleNames();
@@ -48,7 +49,7 @@ export function CreateOrUpdateMeetingForm({open, onClose, meeting, onlyThisMeeti
4849
const response = await getModules(axiosInstance);
4950
setModuleNames(response);
5051
} catch (error) {
51-
//alert("Error fetching user modules:" + error);
52+
alert("Error fetching user modules:" + error);
5253
}
5354
}
5455

@@ -163,21 +164,20 @@ export function CreateOrUpdateMeetingForm({open, onClose, meeting, onlyThisMeeti
163164
}}>
164165
<label htmlFor="meeting-title" className="font-semibold block text-lg text-white">Modulname</label>
165166
<div>
166-
<input
167+
<select
167168
id="meeting-title"
168-
list="modules"
169-
required={true}
170-
type="text"
171-
placeholder="Exakten Modulnamen eingeben oder auswählen"
172-
className="mx-5 mt-1 text-gray-300 block bg-[#333C4F] w-11/12 px-10 py-1 mb-4 border rounded-full shadow-sm border-[#333C4F] placeholder-gray-400 placeholder:text-xs"
169+
required
170+
className="mx-5 mt-1 text-gray-300 block bg-[#333C4F] w-11/12 px-10 py-1 mb-4 border rounded-full shadow-sm border-[#333C4F]"
173171
value={meetingTitle}
174172
onChange={(e) => setMeetingTitle(e.target.value)}
175-
/>
176-
<datalist id="modules">
177-
{moduleNames.map((option) => (
178-
<option key={option} className={"w-full"} value={option}/>
173+
>
174+
<option value="" disabled>Modul auswählen</option>
175+
{moduleNames.map((module, index) => (
176+
<option key={index} value={module.name}>
177+
{module.name}
178+
</option>
179179
))}
180-
</datalist>
180+
</select>
181181
</div>
182182

183183

src/form/SearchMeetingForm.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ import axiosInstance from "../AxiosConfig";
1515
import {getMeetingsForModule} from "../api/MeetingApi";
1616
import {MeetingDto} from "../dtos/MeetingDto";
1717
import MeetingSearchResult from "../components/meeting/MeetingSearchResult";
18+
import {ModuleDto} from "../dtos/ModuleDto";
1819

1920
interface MeetingFormProps {
2021
open: boolean;
2122
onClose: () => void;
2223
}
2324

2425
export function SearchMeetingForm({open, onClose}: MeetingFormProps) {
25-
const [modulNames, setModuleNames] = useState<string[]>([]);
26+
const [modulNames, setModuleNames] = useState<ModuleDto[]>([]);
2627
const [meetings, setMeetings] = useState<MeetingDto[]>([]);
2728
const [module, setModule] = useState<string | undefined>();
2829

2930
const fetchModuleNames = async () => {
3031
try {
31-
setModuleNames(["GDI", "AlgoDat"]);
3232
const response = await getModules(axiosInstance);
3333
setModuleNames(response);
3434
} catch (error) {
@@ -105,9 +105,9 @@ export function SearchMeetingForm({open, onClose}: MeetingFormProps) {
105105
{modulNames.map((module, i) => (
106106
<MenuItem
107107
key={i}
108-
value={module}
108+
value={module.name}
109109
>
110-
{module}
110+
{module.name}
111111
</MenuItem>
112112
))}
113113
</Select>

src/pages/YourStudies.tsx

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import ModuleProgressSettings from "../components/ModuleProgressSettings";
55
import {getMeetingsOfWeek} from "../api/MeetingApi";
66
import axiosInstance from "../AxiosConfig";
77
import {MeetingDto} from "../dtos/MeetingDto";
8-
import {getUser, updateUsername} from "../api/UserApi";
8+
import {getUser, updateUserModules, updateUsername} from "../api/UserApi";
99
import {UserDto} from "../dtos/UserDto";
10+
import {ModuleDto} from "../dtos/ModuleDto";
11+
import {createModule, getModules} from "../api/ModuleApi";
1012

1113
const subjects = [
1214
{name: "Algorithmen und Datenstrukturen", date: "17.02.2025", time: "10:30", room: "HQ.120", progress: 70},
@@ -20,7 +22,11 @@ export default function YourStudies() {
2022
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
2123
const [user, setUser] = useState<UserDto | undefined>();
2224
const [editProfile, setEditProfile] = useState(false);
25+
const [editModule, setEditModule] = useState(false);
2326
const [profileName, setProfileName] = useState(user?.username);
27+
const [ownModules, setownModules] = useState<ModuleDto[]>([]);
28+
const [allModules, setAllModules] = useState<ModuleDto[]>([]);
29+
const [module, setModule] = useState<string>("");
2430

2531
const filterMeetingsForCurrentWeek = (meetings: MeetingDto[]) => {
2632
const currentDate = new Date();
@@ -33,6 +39,15 @@ export default function YourStudies() {
3339
});
3440
};
3541

42+
const fetchAllModules = async () => {
43+
try {
44+
const response = await getModules(axiosInstance);
45+
setAllModules(response);
46+
} catch (error) {
47+
alert("Error fetching user modules:" + error);
48+
}
49+
}
50+
3651
const fetchMeetings = async () => {
3752
try {
3853
const response = await getMeetingsOfWeek(axiosInstance);
@@ -53,6 +68,7 @@ export default function YourStudies() {
5368

5469
useEffect(() => {
5570
fetchMeetings();
71+
fetchAllModules();
5672
fetchUserInfo();
5773
}, []);
5874

@@ -67,12 +83,46 @@ export default function YourStudies() {
6783
}
6884
updateUsername(axiosInstance, profileName);
6985
editProfileMode(false);
86+
fetchUserInfo();
87+
}
88+
89+
const saveNewModule = async () => {
90+
try {
91+
await createModule(axiosInstance, module);
92+
fetchAllModules();
93+
} catch (error) {
94+
alert("Error fetching user modules:" + error);
95+
}
96+
}
97+
98+
const saveModules = async () => {
99+
try {
100+
await updateUserModules(axiosInstance, ownModules);
101+
fetchAllModules();
102+
} catch (error) {
103+
alert("Error fetching user modules:" + error);
104+
}
105+
}
106+
107+
const addModule = () => {
108+
setownModules([...ownModules, {name: module}]);
109+
setModule("");
110+
if (!allModules.some(m => m.name === module.toUpperCase()))
111+
saveNewModule();
112+
}
113+
114+
const deleteModule = (moduleName: string) => {
115+
setownModules(ownModules.filter(m => m.name !== moduleName));
70116
}
71117

72118
const openModal = () => {
73119
setIsModalOpen(true);
74120
};
75121

122+
const editModulesMode = (mode: boolean) => {
123+
setEditModule(mode);
124+
}
125+
76126
const closeModal = () => {
77127
setIsModalOpen(false);
78128
};
@@ -119,17 +169,67 @@ export default function YourStudies() {
119169
<div className="p-4 lg:mr-20 mr-8 mt-2">
120170
<table className="w-full border-collapse">
121171
<tbody>
122-
{subjects.map((subject, index) => (
123-
<tr key={index}>
124-
<td className="py-2 border-b border-[#4B708C] text-gray-300">{subject.name}</td>
125-
</tr>
126-
))}
172+
{editModule ? (
173+
<div className={"flex flex-col gap-4"}>
174+
{ownModules.map((subject) => (
175+
<div
176+
className={"flex flex-row justify-between pr-4 py-1 border-b border-[#4B708C] text-gray-300"}>
177+
<p>{subject.name}</p>
178+
<button
179+
onClick={() => deleteModule(subject.name)}
180+
>
181+
x
182+
</button>
183+
</div>
184+
))}
185+
<input
186+
id="module"
187+
type="text"
188+
placeholder={"Modul"}
189+
className="text-gray-300 block bg-[#333C4F] w-full px-10 py-2 border rounded-full shadow-sm border-[#333C4F] placeholder-gray-550 placeholder:text-xs"
190+
value={module}
191+
onChange={(e) => setModule(e.target.value)}
192+
/>
193+
194+
<datalist id="modules">
195+
{allModules.map((module, index) => (
196+
<option key={index} className={"w-full"} value={module.name}/>
197+
))}
198+
</datalist>
199+
<div className="flex flex-col w-full my-4">
200+
<button
201+
className="bg-[#2EF6D9] text-white cursor-pointer p-[10px] border-none w-[30px] h-[30px] rounded font-semibold text-[16px] inline-flex items-center"
202+
onClick={() => addModule()}>
203+
+
204+
</button>
205+
</div>
206+
207+
</div>
208+
) : (
209+
ownModules.map((subject, index) => (
210+
<tr key={index}>
211+
<td className="py-2 border-b border-[#4B708C] text-gray-300">{subject.name}</td>
212+
</tr>
213+
))
214+
215+
)}
127216
</tbody>
128217
</table>
129218
</div>
130219
<div className="mt-3">
131-
<CuteButton bgColor="#598BB1" classname="lg:text-lg text-base" textColor="#e6ebfc"
132-
text="Module verwalten"/>
220+
{editModule ? (
221+
<div className={"flex items-center w-full gap-2 lg:pr-20 pr-8"}>
222+
<CuteButton classname="lg:text-base text-sm ml-auto" bgColor={"#598BB1"}
223+
textColor={"#e6ebfc"} onClick={() => editModulesMode(false)}
224+
text="Abbrechen"/>
225+
<CuteButton classname="lg:text-lg text-base" bgColor={"#56A095"} textColor={"#e8fcf6"}
226+
onClick={saveModules}
227+
text="Speichern"/>
228+
</div>
229+
) : (
230+
<CuteButton bgColor="#598BB1" classname="lg:text-lg text-base" textColor="#e6ebfc"
231+
text="Module verwalten" onClick={() => editModulesMode(true)}/>
232+
)}
133233
</div>
134234
</div>
135235
</div>

0 commit comments

Comments
 (0)