mirror of
https://github.com/LD-Reborn/Berufsschule_HAM.git
synced 2025-12-20 15:01:56 +00:00
382 lines
17 KiB
Plaintext
382 lines
17 KiB
Plaintext
@using Microsoft.AspNetCore.Html
|
|
@using Microsoft.AspNetCore.Mvc.Localization
|
|
@using Berufsschule_HAM.Models
|
|
@model LocationsIndexViewModel
|
|
@inject IViewLocalizer T
|
|
@{
|
|
ViewData["Title"] = T["Locations"];
|
|
}
|
|
|
|
|
|
<div class="container py-4">
|
|
<h2 class="mb-3">@T["Locations"]</h2>
|
|
|
|
|
|
<div class="mb-4 d-flex flex-wrap gap-2">
|
|
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createModal">@T["Create location"]</button>
|
|
</div>
|
|
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-striped align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>@T["Location ID"]</th>
|
|
<th>@T["Location Name"]</th>
|
|
<th>@T["Room Number"]</th>
|
|
<th>@T["Seat"]</th>
|
|
<th>@T["Action"]</th>
|
|
</tr>
|
|
<tr>
|
|
<th><input type="text" class="form-control form-control-sm column-filter" placeholder="@T["Location ID"]" data-column="0" /></th>
|
|
<th><input type="text" class="form-control form-control-sm column-filter" placeholder="@T["Location Name"]" data-column="1" /></th>
|
|
<th><input type="text" class="form-control form-control-sm column-filter" placeholder="@T["Room Number"]" data-column="2" /></th>
|
|
<th><input type="text" class="form-control form-control-sm column-filter" placeholder="@T["Seat"]" data-column="3" /></th>
|
|
<th class="text-center">-</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@{
|
|
foreach (LocationTableViewModel locationTableViewModel in Model.LocationTableViewModels)
|
|
{
|
|
<tr>
|
|
<td>@locationTableViewModel.LocationID</td>
|
|
<td>@locationTableViewModel.LocationName</td>
|
|
<td>@locationTableViewModel.RoomNumber</td>
|
|
<td>@locationTableViewModel.Seat</td>
|
|
<td>
|
|
<div class="d-flex gap-2">
|
|
<button class="btn btn-sm btn-warning btn-edit"
|
|
data-location-id="@locationTableViewModel.LocationID"
|
|
data-location-name="@locationTableViewModel.LocationName"
|
|
data-room-number="@locationTableViewModel.RoomNumber"
|
|
data-seat="@locationTableViewModel.Seat"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#editModal">
|
|
@T["Edit"]
|
|
</button>
|
|
<button class="btn btn-sm btn-danger btn-delete"
|
|
data-location-id="@locationTableViewModel.LocationID"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#deleteModal">
|
|
@T["Delete"]
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
}
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Location Delete Confirmation Modal -->
|
|
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-danger text-white">
|
|
<h5 class="modal-title" id="deleteModalLabel">@T["Confirm Delete"]</h5>
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>
|
|
@T["DeleteLocationConfirmation", new HtmlString("<strong id=\"locationId\"></strong>")]
|
|
</p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">@T["Cancel"]</button>
|
|
<form id="deleteForm" method="post" action="">
|
|
<button type="submit" class="btn btn-danger">@T["Yes, Delete"]</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const deleteModal = document.getElementById('deleteModal');
|
|
let currentButton = null; // The delete button that opened the modal
|
|
|
|
deleteModal.addEventListener('show.bs.modal', event => {
|
|
currentButton = event.relatedTarget; // Button that triggered the modal
|
|
const locationId = currentButton.getAttribute('data-location-id');
|
|
const locationName = currentButton.getAttribute('data-location-name');
|
|
|
|
deleteModal.querySelector('#locationId').textContent = locationId;
|
|
|
|
// Store the delete URL for later use
|
|
deleteModal.querySelector('#deleteForm').dataset.url = `/Locations/Delete?cn=${locationId}`;
|
|
});
|
|
|
|
// Handle submit of deleteForm via fetch()
|
|
const deleteForm = document.getElementById('deleteForm');
|
|
deleteForm.addEventListener('submit', async e => {
|
|
e.preventDefault();
|
|
|
|
const url = deleteForm.dataset.url;
|
|
const locationId = deleteModal.querySelector('#locationId').textContent;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
}//,
|
|
//body: JSON.stringify({ id: locationId }) // Use this for Post requests with [FromBody] parameters like in /Groups/Update
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
// Close the modal
|
|
const modal = bootstrap.Modal.getInstance(deleteModal);
|
|
modal.hide();
|
|
|
|
// Remove the row from the table
|
|
const row = currentButton.closest('tr');
|
|
row.classList.add('table-danger');
|
|
setTimeout(() => row.remove(), 300);
|
|
|
|
showToast('@T["Location deleted successfully"]', 'success');
|
|
} else {
|
|
showToast(`${result.reason}: ${result.exception || '@T["Unknown error"]'}`, 'danger');
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
showToast('@T["Error contacting server"]', 'danger');
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<!-- Location Edit Modal -->
|
|
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-warning text-dark">
|
|
<h5 class="modal-title" id="editModalLabel">@T["Edit Location"]</h5>
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<form id="editForm">
|
|
<div class="modal-body">
|
|
<input type="hidden" id="editLocationId" name="LocationID">
|
|
|
|
<div class="mb-3">
|
|
<label for="editLocationName" class="form-label">@T["Location Name"]</label>
|
|
<input type="text" class="form-control" id="editLocationName" name="LocationName" required>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="editRoomNumber" class="form-label">@T["Room Number"]</label>
|
|
<input type="text" class="form-control" id="editRoomNumber" name="RoomNumber">
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="editSeat" class="form-label">@T["Seat"]</label>
|
|
<input type="text" class="form-control" id="editSeat" name="Seat">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">@T["Cancel"]</button>
|
|
<button type="submit" class="btn btn-warning">@T["Save changes"]</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// --- EDIT MODAL ---
|
|
const editModal = document.getElementById('editModal');
|
|
const editForm = document.getElementById('editForm');
|
|
|
|
editModal.addEventListener('show.bs.modal', event => {
|
|
const button = event.relatedTarget;
|
|
const id = button.getAttribute('data-location-id');
|
|
const name = button.getAttribute('data-location-name');
|
|
const room = button.getAttribute('data-room-number');
|
|
const seat = button.getAttribute('data-seat');
|
|
|
|
// Set values in the modal form
|
|
editForm.querySelector('#editLocationId').value = id;
|
|
editForm.querySelector('#editLocationName').value = name;
|
|
editForm.querySelector('#editRoomNumber').value = room;
|
|
editForm.querySelector('#editSeat').value = seat;
|
|
});
|
|
|
|
editForm.addEventListener('submit', async e => {
|
|
e.preventDefault();
|
|
|
|
const data = {
|
|
Location: editForm.editLocationId.value,
|
|
Description:
|
|
{
|
|
Location: editLocationName.value,
|
|
RoomNumber: editForm.editRoomNumber.value,
|
|
Seat: editForm.editSeat.value
|
|
}
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/Locations/Update', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result) {
|
|
const btn = document.querySelector(`button[data-location-id="${data.Location}"]`);
|
|
const row = btn.closest('tr');
|
|
let slugifiedLocationID = `${data.Description.Location}-${data.Description.RoomNumber}-${data.Description.Seat}`
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9-]/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.replace(/^-|-$/g, '');
|
|
btn.setAttribute("data-location-id", slugifiedLocationID);
|
|
btn.setAttribute("data-location-name", data.Description.Location);
|
|
btn.setAttribute("data-room-number", data.Description.RoomNumber);
|
|
btn.setAttribute("data-seat", data.Description.Seat);
|
|
row.children[0].textContent = slugifiedLocationID;
|
|
row.children[1].textContent = data.Description.Location;
|
|
row.children[2].textContent = data.Description.RoomNumber;
|
|
row.children[3].textContent = data.Description.Seat;
|
|
|
|
// Close modal
|
|
bootstrap.Modal.getInstance(editModal).hide();
|
|
|
|
showToast('@T["Location updated successfully"]', 'success');
|
|
} else {
|
|
showToast(`${result.reason || '@T["Location update failed"]'}`, 'danger');
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
showToast('@T["Error contacting server"]', 'danger');
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<!-- Location Create Modal -->
|
|
<div class="modal fade" id="createModal" tabindex="-1" aria-labelledby="createModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-primary text-white">
|
|
<h5 class="modal-title" id="createModalLabel">@T["Create location"]</h5>
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<form id="createForm">
|
|
<div class="modal-body">
|
|
|
|
<div class="mb-3">
|
|
<label for="createLocationName" class="form-label">@T["Location Name"]</label>
|
|
<input type="text" class="form-control" id="createLocationName" name="LocationName" required>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="createRoomNumber" class="form-label">@T["Room Number"]</label>
|
|
<input type="text" class="form-control" id="createRoomNumber" name="RoomNumber">
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="createSeat" class="form-label">@T["Seat"]</label>
|
|
<input type="text" class="form-control" id="createSeat" name="Seat">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">@T["Cancel"]</button>
|
|
<button type="submit" class="btn btn-primary">@T["Create"]</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// --- CREATE MODAL ---
|
|
const createForm = document.getElementById('createForm');
|
|
|
|
createForm.addEventListener('submit', async e => {
|
|
e.preventDefault();
|
|
|
|
const data = {
|
|
Description: {
|
|
Location: createForm.createLocationName.value,
|
|
RoomNumber: createForm.createRoomNumber.value,
|
|
Seat: createForm.createSeat.value
|
|
}
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/Locations/Create', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result) {
|
|
const newLoc = data.Description;
|
|
const slugifiedLocationID = `${newLoc.Location}-${newLoc.RoomNumber}-${newLoc.Seat}`
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9-]/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.replace(/^-|-$/g, '');
|
|
|
|
// Insert new row into the table dynamically
|
|
const tbody = document.querySelector('table tbody');
|
|
const newRow = document.createElement('tr');
|
|
newRow.innerHTML = `
|
|
<td>${slugifiedLocationID}</td>
|
|
<td>${newLoc.Location}</td>
|
|
<td>${newLoc.RoomNumber}</td>
|
|
<td>${newLoc.Seat}</td>
|
|
<td>
|
|
<div class="d-flex gap-2">
|
|
<button class="btn btn-sm btn-warning btn-edit"
|
|
data-location-id="${slugifiedLocationID}"
|
|
data-location-name="${newLoc.Location}"
|
|
data-room-number="${newLoc.RoomNumber}"
|
|
data-seat="${newLoc.Seat}"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#editModal">
|
|
@T["Edit"]
|
|
</button>
|
|
<button class="btn btn-sm btn-danger btn-delete"
|
|
data-location-id="${slugifiedLocationID}"
|
|
data-location-name="${newLoc.Location}"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#deleteModal">
|
|
@T["Delete"]
|
|
</button>
|
|
</div>
|
|
</td>
|
|
`;
|
|
tbody.appendChild(newRow);
|
|
|
|
// Close modal
|
|
bootstrap.Modal.getInstance(document.getElementById('createModal')).hide();
|
|
createForm.reset();
|
|
showToast('@T["Location created successfully"]', 'success');
|
|
} else {
|
|
showToast(`${result.reason || '@T["Location creation failed"]'}`, 'danger');
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
showToast('@T["Error contacting server"]', 'danger');
|
|
}
|
|
});
|
|
});
|
|
</script> |