Skip to content

Commit 07b0d18

Browse files
author
Alexandra Zwinger
committed
Clean code and adjust it to backend api
1 parent 6e0c306 commit 07b0d18

File tree

4 files changed

+350
-323
lines changed

4 files changed

+350
-323
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import React, {useEffect, useState} from "react";
2+
import ProgressBar from "../../components/Progressbar";
3+
import {getMeetingsOfWeek} from "../../api/MeetingApi";
4+
import axiosInstance from "../../AxiosConfig";
5+
import {MeetingDto} from "../../dtos/MeetingDto";
6+
import ModuleProgressSettings from "../ModuleProgressSettings";
7+
8+
const subjects = [
9+
{name: "Algorithmen und Datenstrukturen", date: "17.02.2025", time: "10:30", room: "HQ.120", progress: 70},
10+
{name: "Mathematik III", date: "29.01.2025", time: "08:30", room: "KA.046", progress: 50},
11+
{name: "Mensch-Computer-Interaktion", date: "15.02.2025", time: "08:30", room: "HQ.120", progress: 40},
12+
{name: "Software Engineering", date: "27.01.2025", time: "14:00", room: "KA.046", progress: 80},
13+
];
14+
15+
export default function UserInfo() {
16+
const [weeklyMeetings, setWeeklyMeetings] = useState<MeetingDto[]>([]);
17+
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
18+
19+
const filterMeetingsForCurrentWeek = (meetings: MeetingDto[]) => {
20+
const currentDate = new Date();
21+
const startOfWeek = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay() + 1));
22+
const endOfWeek = new Date(currentDate.setDate(startOfWeek.getDate() + 6));
23+
24+
return meetings.filter((meeting) => {
25+
const meetingDate = new Date(meeting.dateFrom);
26+
return meetingDate >= startOfWeek && meetingDate <= endOfWeek;
27+
});
28+
};
29+
30+
const fetchMeetings = async () => {
31+
try {
32+
const response = await getMeetingsOfWeek(axiosInstance);
33+
setWeeklyMeetings(filterMeetingsForCurrentWeek(response));
34+
} catch (error) {
35+
alert("Fehler beim Abrufen der Meetings: " + error);
36+
}
37+
};
38+
39+
useEffect(() => {
40+
fetchMeetings();
41+
}, []);
42+
43+
const openModal = () => {
44+
setIsModalOpen(true);
45+
};
46+
47+
const closeModal = () => {
48+
setIsModalOpen(false);
49+
};
50+
51+
return (
52+
<div className="lg:w-[60%] w-[80%] sm:px-8 mb-16 justify-center mt-8">
53+
<div className="w-full md:px-16">
54+
<p className="text-2xl font-bold text-white text-left lg:mt-4 mt-16 mb-7">Prüfungstermine</p>
55+
56+
<table className="w-full border-collapse hidden md:table">
57+
<tbody>
58+
{subjects.map((subject, index) => (
59+
<tr key={index}>
60+
<td className="px-1 py-1 text-[#9B9B9B]">{subject.name}</td>
61+
<td className="px-1 py-1 text-[#2AB19D]">{subject.date}</td>
62+
<td className="px-1 py-1 text-[#9B9B9B]">{subject.time}</td>
63+
<td className="px-1 py-1 text-[#9B9B9B]">{subject.room}</td>
64+
</tr>
65+
))}
66+
</tbody>
67+
</table>
68+
69+
<div className="md:hidden space-y-4">
70+
{subjects.map((subject, index) => (
71+
<div key={index} className="p-3 shadow-sm">
72+
<p className="text-[#9B9B9B]">
73+
{subject.name}
74+
</p>
75+
<p className="text-[#2AB19D] inline">
76+
{subject.date}
77+
</p>
78+
<p className="text-[#9B9B9B] inline ml-2">
79+
{subject.time} {subject.room}
80+
</p>
81+
</div>
82+
))}
83+
</div>
84+
85+
<p className="text-2xl font-bold text-white text-left mt-9">Lerngruppen in dieser Woche</p>
86+
87+
<table className="w-full border-collapse hidden md:table">
88+
<tbody>
89+
{weeklyMeetings.map((meeting, index) => (
90+
<tr key={index}>
91+
<td className="px-1 py-1 text-[#9B9B9B]">{meeting.title}</td>
92+
<td className="px-1 py-1 text-[#2AB19D]">
93+
{new Date(meeting.dateFrom).toLocaleDateString()}
94+
</td>
95+
<td className="px-1 py-1 text-[#9B9B9B]">
96+
{new Date(meeting.dateFrom).toLocaleTimeString([], {
97+
hour: '2-digit',
98+
minute: '2-digit'
99+
})}
100+
</td>
101+
<td className="px-1 py-1 text-[#9B9B9B]">{meeting.place}</td>
102+
</tr>
103+
))}
104+
</tbody>
105+
</table>
106+
107+
<div className="md:hidden space-y-4">
108+
{weeklyMeetings.map((meeting, index) => (
109+
<div key={index} className="p-3 shadow-sm">
110+
<p className="text-[#9B9B9B]">
111+
{meeting.title}
112+
</p>
113+
<p className="text-[#2AB19D] inline">
114+
{new Date(meeting.dateFrom).toLocaleDateString()}
115+
</p>
116+
<p className="text-[#9B9B9B] inline ml-2">
117+
{new Date(meeting.dateFrom).toLocaleTimeString([], {
118+
hour: '2-digit',
119+
minute: '2-digit'
120+
})} {meeting.place}
121+
</p>
122+
</div>
123+
))}
124+
</div>
125+
126+
<p className="text-2xl font-bold text-white text-left mt-9 mb-6">Lernfortschritt</p>
127+
{subjects.map((subject, index) => (
128+
<div key={index} className="mb-6">
129+
<p className="text-m text-[#9B9B9B]">{subject.name}</p>
130+
<div onClick={openModal}>
131+
<ProgressBar progress={subject.progress}/>
132+
</div>
133+
</div>
134+
))}
135+
</div>
136+
{
137+
isModalOpen && <ModuleProgressSettings isOpen={isModalOpen} onClose={closeModal}/>
138+
}
139+
</div>
140+
);
141+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import React, {useEffect, useState} from "react";
2+
import {CuteButton} from "../CuteButton";
3+
import axiosInstance from "../../AxiosConfig";
4+
import {getUser, updateUserModules, updateUsername} from "../../api/UserApi";
5+
import {UserDto} from "../../dtos/UserDto";
6+
import {ModuleDto} from "../../dtos/ModuleDto";
7+
import {createModule, getModules} from "../../api/ModuleApi";
8+
9+
10+
export default function UserSettings() {
11+
const [user, setUser] = useState<UserDto | undefined>();
12+
const [editProfile, setEditProfile] = useState(false);
13+
const [editModule, setEditModule] = useState(false);
14+
const [profileName, setProfileName] = useState(user?.username);
15+
const [ownModules, setOwnModules] = useState<ModuleDto[]>([]);
16+
const [allModules, setAllModules] = useState<ModuleDto[]>([]);
17+
const [module, setModule] = useState<string>("");
18+
19+
const fetchAllModules = async () => {
20+
try {
21+
const response = await getModules(axiosInstance);
22+
setAllModules(response);
23+
console.log(response);
24+
} catch (error) {
25+
alert("Error fetching user modules:" + error);
26+
}
27+
}
28+
29+
const fetchUserInfo = async () => {
30+
try {
31+
const response = await getUser(axiosInstance);
32+
setUser(response);
33+
setOwnModules(response.modules);
34+
} catch (error) {
35+
alert("Fehler beim Abrufen der UserDaten: " + error);
36+
}
37+
}
38+
39+
useEffect(() => {
40+
fetchAllModules();
41+
fetchUserInfo();
42+
}, []);
43+
44+
const editProfileMode = (mode: boolean) => {
45+
setProfileName(user?.username);
46+
setEditProfile(mode);
47+
}
48+
49+
const saveProfileModifications = () => {
50+
if (!profileName) {
51+
return;
52+
}
53+
updateUsername(axiosInstance, profileName);
54+
editProfileMode(false);
55+
fetchUserInfo();
56+
}
57+
58+
const saveNewModule = async () => {
59+
try {
60+
await createModule(axiosInstance, module);
61+
fetchAllModules();
62+
} catch (error) {
63+
alert("Error fetching user modules:" + error);
64+
}
65+
}
66+
67+
const saveModules = async () => {
68+
try {
69+
await updateUserModules(axiosInstance, ownModules);
70+
fetchUserInfo();
71+
setEditModule(false);
72+
} catch (error) {
73+
alert("Error fetching user modules:" + error);
74+
}
75+
}
76+
77+
const addModule = () => {
78+
if (!ownModules.some(m => m.name.toUpperCase() === module.toUpperCase()))
79+
setOwnModules([...ownModules, {name: module}]);
80+
setModule("");
81+
if (!allModules.some(m => m.name.toUpperCase() === module.toUpperCase())) {
82+
saveNewModule();
83+
}
84+
}
85+
86+
const deleteModule = (moduleName: string) => {
87+
setOwnModules(ownModules.filter(m => m.name !== moduleName));
88+
}
89+
90+
const editModulesMode = (mode: boolean) => {
91+
setOwnModules(user ? user.modules : []);
92+
setEditModule(mode);
93+
}
94+
95+
return (
96+
<div className="lg:w-[40%] w-[80%] bg-[#1C212C] text-white sm:p-4 mb-12 lg:ml-16 ml-4 ">
97+
<div className="w-full">
98+
<h1 className="md:text-5xl text-4xl font-bold text-gray-300 text-left mt-16">Mein
99+
Studium</h1>
100+
<p className="text-xl font-medium text-white text-left mt-3">Mein Profil</p>
101+
<div className="p-4 lg:mr-20 mr-8 mt-2">
102+
{editProfile ? (
103+
<input
104+
id="profileName"
105+
type="text"
106+
placeholder={"Name"}
107+
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"
108+
value={profileName}
109+
onChange={(e) => setProfileName(e.target.value)}
110+
/>
111+
) : (
112+
<p className="py-2 border-b border-[#4B708C] text-gray-300">Name: {user?.username}</p>
113+
)}
114+
</div>
115+
<div className="mt-3 mb-8">
116+
{editProfile ? (
117+
<div className={"flex items-center w-full gap-2 lg:pr-20 pr-8"}>
118+
<CuteButton classname="lg:text-base text-sm ml-auto" bgColor={"#598BB1"}
119+
textColor={"#e6ebfc"} onClick={() => editProfileMode(false)}
120+
text="Abbrechen"/>
121+
<CuteButton classname="lg:text-lg text-base" bgColor={"#56A095"} textColor={"#e8fcf6"}
122+
onClick={saveProfileModifications}
123+
text="Speichern"/>
124+
</div>
125+
) : (
126+
<CuteButton bgColor="#598BB1" classname="lg:text-lg text-base" textColor="#e6ebfc"
127+
text="Profil verwalten" onClick={() => editProfileMode(true)}/>
128+
)}
129+
130+
</div>
131+
<p className="text-xl font-medium text-white text-left mt-3">Aktuelle Module</p>
132+
<div className="p-4 lg:mr-20 mr-8 mt-2">
133+
<table className="w-full border-collapse">
134+
<tbody>
135+
{editModule ? (
136+
<div className={"flex flex-col gap-4"}>
137+
{ownModules.map((subject) => (
138+
<div
139+
className={"flex flex-row justify-between pr-4 py-1 border-b border-[#4B708C] text-gray-300"}>
140+
<p>{subject.name}</p>
141+
<button
142+
onClick={() => deleteModule(subject.name)}
143+
>
144+
x
145+
</button>
146+
</div>
147+
))}
148+
<input
149+
id="module"
150+
type="text"
151+
placeholder={"Modul"}
152+
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"
153+
value={module}
154+
onChange={(e) => setModule(e.target.value)}
155+
/>
156+
157+
<datalist id="modules">
158+
{allModules.map((module, index) => (
159+
<option key={index} className={"w-full"} value={module.name}/>
160+
))}
161+
</datalist>
162+
<div className="flex flex-col w-full my-4">
163+
<button
164+
className="bg-[#2EF6D9] text-white cursor-pointer p-[10px] border-none w-[30px] h-[30px] rounded font-semibold text-[16px] inline-flex items-center"
165+
onClick={() => addModule()}>
166+
+
167+
</button>
168+
</div>
169+
170+
</div>
171+
) : (
172+
ownModules.map((subject, index) => (
173+
<tr key={index}>
174+
<td className="py-2 border-b border-[#4B708C] text-gray-300">{subject.name}</td>
175+
</tr>
176+
))
177+
178+
)}
179+
</tbody>
180+
</table>
181+
</div>
182+
<div className="mt-3">
183+
{editModule ? (
184+
<div className={"flex items-center w-full gap-2 lg:pr-20 pr-8"}>
185+
<CuteButton classname="lg:text-base text-sm ml-auto" bgColor={"#598BB1"}
186+
textColor={"#e6ebfc"} onClick={() => editModulesMode(false)}
187+
text="Abbrechen"/>
188+
<CuteButton classname="lg:text-lg text-base" bgColor={"#56A095"} textColor={"#e8fcf6"}
189+
onClick={saveModules}
190+
text="Speichern"/>
191+
</div>
192+
) : (
193+
<CuteButton bgColor="#598BB1" classname="lg:text-lg text-base" textColor="#e6ebfc"
194+
text="Module verwalten" onClick={() => editModulesMode(true)}/>
195+
)}
196+
</div>
197+
</div>
198+
</div>
199+
);
200+
}

src/dtos/UserDto.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import {ModuleDto} from "./ModuleDto";
2+
13
export type UserDto = {
24
username: string;
35
uuid: string;
6+
modules: ModuleDto[];
47
}

0 commit comments

Comments
 (0)