mirror of
https://github.com/GCMatters/hermes.git
synced 2026-02-04 05:30:13 +01:00
Wersja probna
powinno cos dzialac
This commit is contained in:
89
WebApp/Controllers/EventApiController.cs
Normal file
89
WebApp/Controllers/EventApiController.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using WebApp.Data;
|
||||||
|
using WebApp.Entities;
|
||||||
|
|
||||||
|
namespace WebApp.Controllers.Api
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/events")]
|
||||||
|
public class EventsApiController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ApplicationDbContext _context;
|
||||||
|
|
||||||
|
public EventsApiController(ApplicationDbContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: /api/events
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetAll()
|
||||||
|
{
|
||||||
|
var events = _context.Events.ToList();
|
||||||
|
return Ok(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: /api/events/5
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public IActionResult GetById(int id)
|
||||||
|
{
|
||||||
|
var ev = _context.Events.Find(id);
|
||||||
|
if (ev == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return Ok(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST: /api/events
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult Create([FromBody] Event ev)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
|
||||||
|
ev.EventDate = DateTime.SpecifyKind(ev.EventDate, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
_context.Events.Add(ev);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetById), new { id = ev.EventId }, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT: /api/events/5
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public IActionResult Update(int id, [FromBody] Event updated)
|
||||||
|
{
|
||||||
|
if (id != updated.EventId)
|
||||||
|
return BadRequest("ID w URL nie zgadza się z obiektem.");
|
||||||
|
|
||||||
|
var ev = _context.Events.Find(id);
|
||||||
|
if (ev == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
ev.Title = updated.Title;
|
||||||
|
ev.Description = updated.Description;
|
||||||
|
ev.Location = updated.Location;
|
||||||
|
ev.EventDate = updated.EventDate;
|
||||||
|
ev.OrganisationId = updated.OrganisationId;
|
||||||
|
|
||||||
|
_context.SaveChanges();
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE: /api/events/5
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public IActionResult Delete(int id)
|
||||||
|
{
|
||||||
|
var ev = _context.Events.Find(id);
|
||||||
|
if (ev == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
_context.Events.Remove(ev);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using WebApp.Data;
|
|
||||||
using WebApp.Entities;
|
|
||||||
|
|
||||||
namespace WebApp.Controllers
|
|
||||||
{
|
|
||||||
public class EventsController : Controller
|
|
||||||
{
|
|
||||||
private readonly ApplicationDbContext _context;
|
|
||||||
|
|
||||||
public EventsController(ApplicationDbContext context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IActionResult Create()
|
|
||||||
{
|
|
||||||
return View();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
[ValidateAntiForgeryToken]
|
|
||||||
public async Task<IActionResult> Create(Event ev)
|
|
||||||
{
|
|
||||||
if (ModelState.IsValid)
|
|
||||||
{
|
|
||||||
ev.EventDate = DateTime.SpecifyKind(ev.EventDate, DateTimeKind.Utc);
|
|
||||||
_context.Events.Add(ev);
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
return RedirectToAction("Index", "Home");
|
|
||||||
}
|
|
||||||
return View(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
[ValidateAntiForgeryToken]
|
|
||||||
public async Task<IActionResult> Delete(int id)
|
|
||||||
{
|
|
||||||
var ev = await _context.Events.FindAsync(id);
|
|
||||||
if (ev != null)
|
|
||||||
{
|
|
||||||
_context.Events.Remove(ev);
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
return RedirectToAction("Index", "Home");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,6 +30,7 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
app.UseDefaultFiles();
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
@model WebApp.Entities.Event
|
|
||||||
|
|
||||||
@{
|
|
||||||
ViewData["Title"] = "Create Event";
|
|
||||||
}
|
|
||||||
|
|
||||||
<h2>Create Event</h2>
|
|
||||||
|
|
||||||
<form asp-action="Create" method="post">
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Title"></label>
|
|
||||||
<input asp-for="Title" class="form-control" />
|
|
||||||
<span asp-validation-for="Title" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Location"></label>
|
|
||||||
<input asp-for="Location" class="form-control" />
|
|
||||||
<span asp-validation-for="Location" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Description"></label>
|
|
||||||
<textarea asp-for="Description" class="form-control"></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="EventDate"></label>
|
|
||||||
<input asp-for="EventDate" type="datetime-local" class="form-control" />
|
|
||||||
<span asp-validation-for="EventDate" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="OrganisationId">OrganisationId (for debugging purposes)</label>
|
|
||||||
<input asp-for="OrganisationId" class="form-control" />
|
|
||||||
<span asp-validation-for="OrganisationId" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">Save</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
@section Scripts {
|
|
||||||
@{
|
|
||||||
await Html.RenderPartialAsync("_ValidationScriptsPartial");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
||||||
|
|
||||||
namespace WebApp.Views.Events
|
|
||||||
{
|
|
||||||
public class CreateModel : PageModel
|
|
||||||
{
|
|
||||||
public void OnGet()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
const deleteButtons = document.querySelectorAll(".delete-btn");
|
document.body.addEventListener("click", async (e) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
|
||||||
deleteButtons.forEach(button => {
|
if (!target.matches(".delete-btn")) return;
|
||||||
button.addEventListener("click", async () => {
|
|
||||||
const id = (button as HTMLButtonElement).dataset.id;
|
const id = target.getAttribute("data-id");
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
const confirmed = confirm("Na pewno chcesz usunąć to wydarzenie?");
|
const confirmed = confirm("Na pewno chcesz usunąć to wydarzenie?");
|
||||||
if (!confirmed) return;
|
if (!confirmed) return;
|
||||||
|
|
||||||
const response = await fetch(`/api/events/${id}`, {
|
const response = await fetch(`/api/events/${id}`, {
|
||||||
|
|
||||||
method: "DELETE"
|
method: "DELETE"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const row = button.closest("tr");
|
const card = target.closest(".col");
|
||||||
if (row) row.remove();
|
if (card) card.remove();
|
||||||
} else {
|
} else {
|
||||||
alert("Nie udało się usunąć wydarzenia.");
|
alert("Nie udało się usunąć wydarzenia.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
41
WebApp/ts/eventList.ts
Normal file
41
WebApp/ts/eventList.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", async () => {
|
||||||
|
const container = document.getElementById("eventList");
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/events");
|
||||||
|
if (!res.ok) throw new Error("Błąd pobierania wydarzeń");
|
||||||
|
|
||||||
|
const events = await res.json();
|
||||||
|
|
||||||
|
if (events.length === 0) {
|
||||||
|
container.innerHTML = "<p class='text-muted'>Brak wydarzeń do wyświetlenia.</p>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ev of events) {
|
||||||
|
const card = document.createElement("div");
|
||||||
|
card.className = "col";
|
||||||
|
card.innerHTML = `
|
||||||
|
<div class="card shadow-sm h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">${ev.title}</h5>
|
||||||
|
<p class="card-text">
|
||||||
|
<strong>Miejsce:</strong> ${ev.location}<br/>
|
||||||
|
<strong>Data:</strong> ${new Date(ev.eventDate).toLocaleString()}<br/>
|
||||||
|
<strong>Organizacja ID:</strong> ${ev.organisationId}
|
||||||
|
</p>
|
||||||
|
<button class="btn btn-outline-danger delete-btn" data-id="${ev.eventId}">
|
||||||
|
🗑️ Usuń
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
container.appendChild(card);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
container.innerHTML = `<p class="text-danger">Błąd ładowania danych.</p>`;
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
51
WebApp/wwwroot/create.html
Normal file
51
WebApp/wwwroot/create.html
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pl">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Nowe wydarzenie</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="/css/style.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<body class="bg-light">
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h1 class="mb-4">Utwórz wydarzenie</h1>
|
||||||
|
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<label for="title">Tytuł</label>
|
||||||
|
<input id="title" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<label for="location">Lokalizacja</label>
|
||||||
|
<input id="location" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<label for="description">Opis</label>
|
||||||
|
<textarea id="description" class="form-control"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<label for="eventDate">Data</label>
|
||||||
|
<input id="eventDate" type="datetime-local" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-4">
|
||||||
|
<label for="organisationId">ID Organizacji</label>
|
||||||
|
<input id="organisationId" type="number" class="form-control" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<button class="button"><span>Zapisz</span><span>⮞</span></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="module" src="/js/eventCreate.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</html>
|
||||||
37
WebApp/wwwroot/css/style.css
Normal file
37
WebApp/wwwroot/css/style.css
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
.button {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f4511e;
|
||||||
|
color: #FFFFFF;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28px;
|
||||||
|
padding: 20px 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.5s;
|
||||||
|
text-transform: uppercase;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background-color: rgb(189, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button span:first-child {
|
||||||
|
padding-left: 10px;
|
||||||
|
transition: all 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover span:first-child {
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button span:last-child {
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.5s;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover span:last-child {
|
||||||
|
opacity: 1;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
25
WebApp/wwwroot/index.html
Normal file
25
WebApp/wwwroot/index.html
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pl">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Lista wydarzeń</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="/css/style.css" />
|
||||||
|
</head>
|
||||||
|
<body class="bg-light">
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h1 class="text-primary">📅 Wydarzenia</h1>
|
||||||
|
<a href="/create.html" class="btn btn-success">+ Dodaj nowe</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="eventList" class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="module" src="/js/eventList.js"></script>
|
||||||
|
<script type="module" src="/js/eventDelete.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -9,10 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
const deleteButtons = document.querySelectorAll(".delete-btn");
|
document.body.addEventListener("click", (e) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
deleteButtons.forEach(button => {
|
const target = e.target;
|
||||||
button.addEventListener("click", () => __awaiter(void 0, void 0, void 0, function* () {
|
if (!target.matches(".delete-btn"))
|
||||||
const id = button.dataset.id;
|
return;
|
||||||
|
const id = target.getAttribute("data-id");
|
||||||
if (!id)
|
if (!id)
|
||||||
return;
|
return;
|
||||||
const confirmed = confirm("Na pewno chcesz usunąć to wydarzenie?");
|
const confirmed = confirm("Na pewno chcesz usunąć to wydarzenie?");
|
||||||
@@ -22,13 +23,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
method: "DELETE"
|
method: "DELETE"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const row = button.closest("tr");
|
const card = target.closest(".col");
|
||||||
if (row)
|
if (card)
|
||||||
row.remove();
|
card.remove();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alert("Nie udało się usunąć wydarzenia.");
|
alert("Nie udało się usunąć wydarzenia.");
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
49
WebApp/wwwroot/js/eventList.js
Normal file
49
WebApp/wwwroot/js/eventList.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
document.addEventListener("DOMContentLoaded", () => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const container = document.getElementById("eventList");
|
||||||
|
if (!container)
|
||||||
|
return;
|
||||||
|
try {
|
||||||
|
const res = yield fetch("/api/events");
|
||||||
|
if (!res.ok)
|
||||||
|
throw new Error("Błąd pobierania wydarzeń");
|
||||||
|
const events = yield res.json();
|
||||||
|
if (events.length === 0) {
|
||||||
|
container.innerHTML = "<p class='text-muted'>Brak wydarzeń do wyświetlenia.</p>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const ev of events) {
|
||||||
|
const card = document.createElement("div");
|
||||||
|
card.className = "col";
|
||||||
|
card.innerHTML = `
|
||||||
|
<div class="card shadow-sm h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">${ev.title}</h5>
|
||||||
|
<p class="card-text">
|
||||||
|
<strong>Miejsce:</strong> ${ev.location}<br/>
|
||||||
|
<strong>Data:</strong> ${new Date(ev.eventDate).toLocaleString()}<br/>
|
||||||
|
<strong>Organizacja ID:</strong> ${ev.organisationId}
|
||||||
|
</p>
|
||||||
|
<button class="btn btn-outline-danger delete-btn" data-id="${ev.eventId}">
|
||||||
|
🗑️ Usuń
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
container.appendChild(card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
container.innerHTML = `<p class="text-danger">Błąd ładowania danych.</p>`;
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}));
|
||||||
Reference in New Issue
Block a user