diff --git a/userman_all/client/index.html b/userman_all/client/index.html index 59c14495bae1c9a4bf2576be9a073ec17431ddbd..e6ae1977265194e9c29b6f7dd32eccb88446f9c7 100644 --- a/userman_all/client/index.html +++ b/userman_all/client/index.html @@ -74,7 +74,7 @@ <div class="hero-text"> <p>your journey begins</p> <h1>Entdecken, Erleben, Unterstützen</h1> - <button id="hero-button" onclick="showPage('reisen')">Reise mit uns!</button> + <button id="hero-button" onclick="showPage('reisen')">Reise mit uns! </button> </div> </div> <!-- Titeltext--> @@ -837,14 +837,6 @@ <option value="kenia">Kenia</option> </select> - <div class="rating" id="ratingReisebericht"> - <span id="stern1">★</span> - <span id="stern2">★</span> - <span id="stern3">★</span> - <span id="stern4">★</span> - <span id="stern5">★</span> - </div> - <label for="titleReisebericht">Titel</label> <input type="text" id="titleReisebericht" name="title" placeholder="titel"> @@ -883,15 +875,54 @@ <section id="sectionNewReisebericht"> <h2>Meine Reiseberichte</h2> <div class="reisebericht-card" id="reisebericht-card"> - <h3 id="titelReise">Meine Reise in Indien</h3> - <h5 id="reiseland"> ...</h5> - <p id="reisebeschreibung">Das Projekt setzt sich dafür ein, Frauen in benachteiligten Regionen Indiens - Zugang zu Bildung und beruflichen Chancen zu ermöglichen. Schon bei meiner Ankunft wurde deutlich, - wie wichtig diese Arbeit ist: Die strahlenden Augen der Teilnehmerinnen und ihre Geschichten - zeigten, dass Bildung für sie ein Tor zu einem besseren Leben bedeutet.</p> - <button class="details-button">Reisebericht löschen</button> - <button class="report-button" onclick="showPage('reiseberichtSchreiben')">Reisebericht bearbeiten - </button> + <h3 id="titelReise">Meine Reise in Indien</h3> + <h5 id="reiseland"> ...</h5> + <p id="reisebeschreibung">Das Projekt setzt sich dafür ein, Frauen in benachteiligten Regionen Indiens Zugang zu Bildung und beruflichen Chancen zu ermöglichen. Schon bei meiner Ankunft wurde deutlich, wie wichtig diese Arbeit ist: Die strahlenden Augen der Teilnehmerinnen und ihre Geschichten zeigten, dass Bildung für sie ein Tor zu einem besseren Leben bedeutet.</p> + + + <!-- Delete-Popup-Modal --> + <div class="modal fade" id="deleteReiseberichtModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h1 class="modal-title fs-5" id="deleteReiseberichtModalLabel">Profil löschen</h1> + <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> + </div> + <div class="modal-body"> + Bist du dir sicher, dass du dein Reisebericht löschen möchtest? Dein Feedback ist uns wichtig! Diese Aktion kann nicht rückgängig gemacht werden. + </div> + <div class="modal-footer"> + <button type="submit" id="saveButtonDeleteReisebericht" class="btn btn-danger">Löschen</button> + </div> + </div> + </div> + </div> + + + + <!-- Modal --> + <div class="modal fade" id="updateModalReisebericht"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h1 class="modal-title fs-5" id="exampleModalLabelReisebericht">Meinung geändert? Halte uns auf dem neusten Stand!</h1> + <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> + </div> + <div class="modal-body"> + <input type="hidden" id="edit-reisebericht-id"> + Titel + <label for="modal-title" class="d-none">Titel</label> + <input type="text" class="form-control-registrieren-modal" id="modal-title"> + Feedback + <label for="modal-description" class="d-none">Feedback</label> + <input type="text" class="form-control-registrieren-modal" id="modal-description"> + </div> + <div class="modal-footer"> + <button type="submit" id="saveButtonEditReisebericht" class="btn btn-primary">Sichern</button> + </div> + </div> + </div> + </div> </div> </section> </main> diff --git a/userman_all/client/src/client.ts b/userman_all/client/src/client.ts index 46b510dbe4bc3d81b1f242288811626fbba7b280..5f56d9b90b2f40f50e4c6072e68fdea0db2afdc6 100644 --- a/userman_all/client/src/client.ts +++ b/userman_all/client/src/client.ts @@ -40,7 +40,6 @@ interface Review { reviews_id: number; title: string; description: string; - rating: number; country: string; user_id: number; } @@ -50,6 +49,7 @@ let modalEl: bootstrap.Modal let modalTest: bootstrap.Modal let modalAdmin: bootstrap.Modal let modalAdminDelete: bootstrap.Modal +let modalReview: bootstrap.Modal document.addEventListener("DOMContentLoaded", (): void => { @@ -58,6 +58,7 @@ document.addEventListener("DOMContentLoaded", (): void => { modalTest = new bootstrap.Modal("#deleteModal"); modalAdmin = new bootstrap.Modal("#updateAdminModal"); modalAdminDelete = new bootstrap.Modal("#deleteModalAdmin"); + modalReview = new bootstrap.Modal("#updateModalReisebericht"); //--- check, if user is already logged in (e.g. after refresh) ------------------------------------------------------- @@ -293,13 +294,11 @@ document.addEventListener("DOMContentLoaded", (): void => { const countryEl: HTMLInputElement = document.getElementById("country") as HTMLInputElement; const titleEl: HTMLInputElement = document.getElementById("titleReisebericht") as HTMLInputElement; const descriptionEl: HTMLInputElement = document.getElementById("feedback") as HTMLInputElement; - const ratingEl: HTMLInputElement = document.getElementById("ratingReisebericht") as HTMLInputElement; //Die Werte der Eingabefelder werden in Variablen gespeichert const country: string = countryEl.value; const title: string = titleEl.value; const description: string = descriptionEl.value; - const rating: string = ratingEl.value; // Validieren der Eingaben if (!country|| !title || !description) { @@ -315,7 +314,7 @@ document.addEventListener("DOMContentLoaded", (): void => { headers: { "Content-type": "application/json", }, - body: JSON.stringify({country, title, description, rating: Number(rating) }), + body: JSON.stringify({country, title, description }), }); //Antwort vom Server verarbeiten @@ -336,7 +335,6 @@ document.addEventListener("DOMContentLoaded", (): void => { countryEl.value = ""; titleEl.value = ""; descriptionEl.value = ""; - ratingEl.value = ""; }); ///Read Reisebericht @@ -346,7 +344,34 @@ document.addEventListener("DOMContentLoaded", (): void => { }) +//update Reisebericht + document.getElementById("updateModalReisebericht")!.addEventListener("submit", async (event: SubmitEvent): Promise<void> => { + event.preventDefault(); + let reviews_idEl: HTMLInputElement = document.getElementById("edit-reisebericht-id") as HTMLInputElement; + let titleEl: HTMLInputElement = document.getElementById("modal-title") as HTMLInputElement; + let descriptionEl: HTMLInputElement = document.getElementById("modal-description") as HTMLInputElement; + + // Read the user's id from the hidden field. + let reviews_id: number = parseInt(reviews_idEl.value); + let title: string = titleEl.value; + let description: string = descriptionEl.value; + const res: Response = await fetch('/reviews/' + reviews_id, { + method: 'PUT', + headers: { + "Content-type": "application/json" + }, + body: JSON.stringify({title, description}), + }); + const data: any = await res.json(); + addMessage(data.message); + + // Hide the modal window + modalReview.hide(); + + // Update the html + readReviews(); + }); }); @@ -396,12 +421,11 @@ function reviewDataInProfile (reviews: Review): void { const countryEl: HTMLInputElement = document.getElementById("reiseland") as HTMLInputElement; const titleEl: HTMLInputElement = document.getElementById('titelReise') as HTMLInputElement; const descriptionEl: HTMLInputElement = document.getElementById('reisebeschreibung') as HTMLInputElement; - //const ratingEl: HTMLInputElement = document.getElementById('edit-user-email') as HTMLInputElement; countryEl.value = reviews.country; titleEl.value = reviews.title; descriptionEl.value = reviews.description; - //ratingEl.value = reviews.rating; + } /** * Displays the logged in username @@ -434,7 +458,7 @@ async function deleteUser(): Promise<void> { //Daten an den Server senden - delete anfrage, um daten zu aktualisieren const res: Response = await fetch(`/user`, { - method: 'delete', + method: 'DELETE', headers: { "Content-type": "application/json" }, @@ -500,7 +524,29 @@ function renderReviews(reviewsList: Review[]): void { let p: HTMLElement = document.createElement("p"); p.textContent = reviews.description.toString(); - container.append(h3, h5, p); + + // Delete button + let deleteReviewButton: HTMLButtonElement = document.createElement("button"); + deleteReviewButton.className = "small-button-delete"; + deleteReviewButton.textContent = "Reisebericht löschen"; + deleteReviewButton.addEventListener("click", async () => { + const res: Response = await fetch('/reviews' + reviews.reviews_id, { + method: 'DELETE' + }); + const data: any = await res.json(); + addMessage(data.message); + readReviews(); + }); + + // Edit button + let editReviewButton: HTMLButtonElement = document.createElement("button"); + editReviewButton.className = "small-button-edit"; + editReviewButton.textContent = "Reisebericht bearbeiten"; + editReviewButton.addEventListener("click", () => { + showEditModalReisebericht(reviews); + }); + + container.append(h3, h5, p, deleteReviewButton, editReviewButton ); reviewsListEl.appendChild(container); @@ -610,6 +656,22 @@ function showEditModal(user: User): void { modalAdmin.show(); } +function showEditModalReisebericht(reviews: Review): void { + let reviews_idEl: HTMLInputElement = document.getElementById("edit-reisebericht-id") as HTMLInputElement; + let titleEl: HTMLInputElement = document.getElementById("modal-title") as HTMLInputElement; + let descriptionEl: HTMLInputElement = document.getElementById("modal-description") as HTMLInputElement; + + // Write the user's id into the hidden field. + reviews_idEl.value = reviews.reviews_id.toString(); + + // Write the user's data into the text fields. + titleEl.value = reviews.title; + descriptionEl.value = reviews.description; + + // Show the modal window. + modalReview.show(); +} + /** * Creates a new alert message. diff --git a/userman_all/server/src/server.ts b/userman_all/server/src/server.ts index df05f0bc2b02e7c9c714d58a93333cdc479cdffb..6c26f648e156b2fb24d4f1cefaa9f52077426371 100644 --- a/userman_all/server/src/server.ts +++ b/userman_all/server/src/server.ts @@ -84,7 +84,6 @@ export interface Review { reviews_id: number; title: string; description: string; - rating: number; country: string; user_id: number; } @@ -872,7 +871,6 @@ app.post('/reviews', isLoggedIn, async (req: Request, res: Response): Promise<vo const country: string = req.body.country; const title: string = req.body.title; const description: string = req.body.description; - const rating: number = req.body.rating; const user_id: number = Number(req.session.user?.user_id); //user_id wird zu Number gemacht weil könnte "theoretisch" undefined sein,. aber eig wegen isloggedin nicht // Check, if any given value is empty @@ -883,16 +881,15 @@ app.post('/reviews', isLoggedIn, async (req: Request, res: Response): Promise<vo return; } -//aufrufen titel, beschreibung, land, rating, userid - const data: [string, string, string, number, number] = [ +//aufrufen titel, beschreibung, land, userid + const data: [string, string, string, number] = [ title, description, country, - Number(rating), user_id, ]; //soll in review tabelle gespeichert werden - const query: string = 'INSERT INTO reviews (title, description, country, rating, user_id) VALUES (?, ?, ?, ?, ?);'; + const query: string = 'INSERT INTO reviews (title, description, country, user_id) VALUES (?, ?, ?, ?, ?);'; try { const [rows] = await database.query<RowDataPacket[]>(query, data); @@ -930,7 +927,6 @@ app.get('/reviews', isLoggedIn, async (req: Request, res: Response): Promise<voi country: row.country, title: row.title, description: row.description, - rating: row.rating, }; reviewsList.push(reviews); } @@ -948,7 +944,72 @@ app.get('/reviews', isLoggedIn, async (req: Request, res: Response): Promise<voi } }); +/// Update Review +app.put('/reviews/:reviews_id', isLoggedIn, async (req: Request, res: Response): Promise<void> => { + // Read data from request + const reviews_id: number = parseInt(req.params.reviews_id); + const title: string = req.body.title; + const description: string = req.body.description; + // Check that all arguments are given + if (title && description) { + // Create database query and data + const data: [string, string, number] = [ + title, + description, + reviews_id + ]; + const query: string = 'UPDATE reviews SET title = ?, description = ? WHERE reviews_id = ?;'; + + // Execute database query + try { + const [result] = await database.query<ResultSetHeader>(query, data); + + if (result.affectedRows != 1) { + res.status(404).send({ + message: 'The review to update could not be found', + }); + } else { + res.status(200).send({ + message: `Successfully updated review`, + }); + } + } catch (error) { + res.status(500).send({ + message: 'Database request failed: ' + error + }); + } + } else { + res.status(400).send({ + message: 'füll alle Felder aus', + }); + } +}); + +//Delete Review +app.delete('/reviews/:reviews_id', isLoggedIn, async (req: Request, res: Response): Promise<void> => { + // Read data from request + const reviews_id: number = parseInt(req.params.reviews_id); + // Delete user + const query: string = 'DELETE FROM reviews WHERE reviews_id = ?;'; + try { + const [result] = await database.query<ResultSetHeader>(query, reviews_id); + if (result.affectedRows === 1) { + res.status(200).send({ + message: `Löschen des Erfahrungsberichts war erfolgreich!`, + }); + } else { + res.status(404).send({ + message: 'Der Beitrag, der gelöscht werden soll, konnte nicht gefunden werden.', + }); + } + } catch (error) { + // Database operation has failed + res.status(500).send({ + message: 'Database request failed: ' + error + }); + } +}); /***************************************************************************** * STATIC ROUTES * *****************************************************************************/