Added a few controllers and views

This commit is contained in:
2025-11-29 21:15:56 +01:00
parent f9a41263a5
commit 6819d1e38b
18 changed files with 2073 additions and 6 deletions

View File

@@ -0,0 +1,67 @@
@{
ViewData["Title"] = "Login";
}
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="text-center mb-4">Login</h2>
<form id="loginForm">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Login</button>
</form>
<hr>
<p class="text-center">Don't have an account? <a asp-controller="AuthView" asp-action="Register">Register here</a></p>
<div id="message" class="mt-3"></div>
</div>
</div>
</div>
</div>
</div>
<script>
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
const messageDiv = document.getElementById('message');
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
if (response.ok) {
messageDiv.innerHTML = '<div class="alert alert-success">Login successful! Redirecting...</div>';
setTimeout(() => {
window.location.href = '/';
}, 1500);
} else {
const error = await response.json();
messageDiv.innerHTML = `<div class="alert alert-danger">${error.message}</div>`;
}
} catch (error) {
messageDiv.innerHTML = `<div class="alert alert-danger">An error occurred: ${error.message}</div>`;
}
});
</script>

View File

@@ -0,0 +1,79 @@
@{
ViewData["Title"] = "Register";
}
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="text-center mb-4">Register</h2>
<form id="registerForm">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="mb-3">
<label for="confirmPassword" class="form-label">Confirm Password</label>
<input type="password" class="form-control" id="confirmPassword" name="confirmPassword" required>
</div>
<button type="submit" class="btn btn-primary w-100">Register</button>
</form>
<hr>
<p class="text-center">Already have an account? <a href="/auth/login">Login here</a></p>
<div id="message" class="mt-3"></div>
</div>
</div>
</div>
</div>
</div>
<script>
document.getElementById('registerForm').addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
const confirmPassword = document.getElementById('confirmPassword').value;
const messageDiv = document.getElementById('message');
if (password !== confirmPassword) {
messageDiv.innerHTML = '<div class="alert alert-danger">Passwords do not match!</div>';
return;
}
try {
const response = await fetch('/api/auth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
if (response.ok) {
messageDiv.innerHTML = '<div class="alert alert-success">Registration successful! Redirecting to login...</div>';
setTimeout(() => {
window.location.href = '/AuthView/Login';
}, 1500);
} else {
const error = await response.json();
const errorMessages = error.errors.join('<br>');
messageDiv.innerHTML = `<div class="alert alert-danger">${errorMessages}</div>`;
}
} catch (error) {
messageDiv.innerHTML = `<div class="alert alert-danger">An error occurred: ${error.message}</div>`;
}
});
</script>

130
Views/Home/Dashboard.cshtml Normal file
View File

@@ -0,0 +1,130 @@
@using OneForMe.Controllers
@model DashboardViewModel
@{
ViewData["Title"] = "Dashboard";
}
<div class="container mt-5">
<div class="row mb-4">
<div class="col-md-12">
<h1>Welcome to OneForMe</h1>
<p>Logged in as: <strong>@User.Identity?.Name</strong></p>
<a href="/AuthView/Logout" class="btn btn-danger">Logout</a>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body">
<h5 class="card-title">Create New Order</h5>
<p class="card-text">Start a new group order and invite friends</p>
<a href="/order/create" class="btn btn-primary">Create Order</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card shadow">
<div class="card-body">
<h5 class="card-title">Join Order</h5>
<p class="card-text">Join an existing order using the order code</p>
<form method="get" action="/order/join" class="mb-3">
<div class="input-group">
<input type="text" class="form-control" name="code" placeholder="Enter order code" required>
<button class="btn btn-success" type="submit">Join</button>
</div>
</form>
</div>
</div>
</div>
</div>
<hr>
<!-- Created Orders -->
<div class="row mb-4">
<div class="col-md-12">
<h3>My Created Orders</h3>
@if (Model.CreatedOrders.Any())
{
<div class="row">
@foreach (var order in Model.CreatedOrders)
{
<div class="col-md-6 mb-3">
<div class="card shadow">
<div class="card-body">
<h5 class="card-title">@order.CreatorName</h5>
<p class="card-text">
<small class="text-muted">Code: <strong>@order.OrderCode</strong></small><br>
<small class="text-muted">Created: @order.CreatedAt.ToString("MMM dd, yyyy HH:mm")</small><br>
<small>Items: @order.MenuItems.Count | Orders: @order.OrderItems.Count</small>
</p>
<p class="text-success"><strong>Total: $@order.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p>
<div class="d-flex gap-2">
<a href="/order/details?code=@order.OrderCode" class="btn btn-sm btn-primary">View</a>
@if (!order.IsClosed)
{
<a href="/order/close?code=@order.OrderCode" class="btn btn-sm btn-danger">Close Order</a>
}
else
{
<span class="badge bg-secondary">Closed</span>
}
</div>
</div>
</div>
</div>
}
</div>
}
else
{
<div class="alert alert-info">You haven't created any orders yet.</div>
}
</div>
</div>
<hr>
<!-- Joined Orders -->
<div class="row">
<div class="col-md-12">
<h3>Orders I Joined</h3>
@if (Model.JoinedOrders.Any())
{
<div class="row">
@foreach (var order in Model.JoinedOrders)
{
var myItems = order.OrderItems.Where(oi => oi.ParticipantEmail == User.Identity?.Name || oi.ParticipantName == User.Identity?.Name).ToList();
<div class="col-md-6 mb-3">
<div class="card shadow">
<div class="card-body">
<h5 class="card-title">@order.CreatorName</h5>
<p class="card-text">
<small class="text-muted">Code: <strong>@order.OrderCode</strong></small><br>
<small class="text-muted">Created by: @order.CreatorName</small><br>
<small>My items: @myItems.Count</small>
</p>
<p class="text-warning"><strong>I owe: $@myItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p>
<div class="d-flex gap-2">
<a href="/order/join?code=@order.OrderCode" class="btn btn-sm btn-primary">View</a>
@if (!order.IsClosed)
{
<a href="/order/join?code=@order.OrderCode" class="btn btn-sm btn-success">Add More</a>
}
</div>
</div>
</div>
</div>
}
</div>
}
else
{
<div class="alert alert-info">You haven't joined any orders yet.</div>
}
</div>
</div>
</div>

84
Views/Order/Create.cshtml Normal file
View File

@@ -0,0 +1,84 @@
@{
ViewData["Title"] = "Create Order";
}
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="mb-4">Create New Order</h2>
<form method="post" id="createOrderForm">
<div class="mb-3">
<label for="creatorName" class="form-label">Order Name</label>
<input type="text" class="form-control" id="creatorName" name="creatorName" placeholder="e.g., Pizza Party" required>
<small class="text-muted">Give your order a name</small>
</div>
<hr>
<h5 class="mb-3">Menu Items</h5>
<p class="text-muted">Add items that people can order</p>
<div id="itemsContainer">
<div class="item-row mb-3">
<div class="row">
<div class="col-md-8">
<input type="text" class="form-control" placeholder="Item name (e.g., Margherita Pizza)" name="itemNames[]">
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text">$</span>
<input type="number" class="form-control" placeholder="Price" name="itemPrices[]" step="0.01" min="0">
</div>
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-secondary mb-3" id="addItemBtn">+ Add Another Item</button>
<hr>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Create Order</button>
<a href="/Home/Dashboard" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
document.getElementById('addItemBtn').addEventListener('click', function() {
const container = document.getElementById('itemsContainer');
const newRow = document.createElement('div');
newRow.className = 'item-row mb-3';
newRow.innerHTML = `
<div class="row">
<div class="col-md-8">
<input type="text" class="form-control" placeholder="Item name" name="itemNames[]">
</div>
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text">$</span>
<input type="number" class="form-control" placeholder="Price" name="itemPrices[]" step="0.01" min="0">
<button type="button" class="btn btn-outline-danger" onclick="this.closest('.item-row').remove()">Remove</button>
</div>
</div>
</div>
`;
container.appendChild(newRow);
});
// Add first item row on page load
document.addEventListener('DOMContentLoaded', function() {
const container = document.getElementById('itemsContainer');
if (container.children.length === 0) {
document.getElementById('addItemBtn').click();
}
});
</script>

124
Views/Order/Details.cshtml Normal file
View File

@@ -0,0 +1,124 @@
@model OneForMe.Models.Order
@{
ViewData["Title"] = "Order Details";
}
<div class="container mt-5">
<div class="row">
<div class="col-md-8">
<div class="card shadow mb-4">
<div class="card-body">
<h2>@Model.CreatorName</h2>
<p class="text-muted">Order Code: <strong>@Model.OrderCode</strong></p>
<p>Created by: <strong>@Model.CreatorName</strong></p>
<p>Status: <span class="badge @(Model.IsClosed ? "bg-danger" : "bg-success")">@(Model.IsClosed ? "Closed" : "Open")</span></p>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Menu Items</h5>
</div>
<div class="card-body">
@if (Model.MenuItems.Any())
{
<table class="table table-hover">
<thead>
<tr>
<th>Item</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.MenuItems)
{
<tr>
<td>@item.Name</td>
<td>$@item.Price.ToString("F2")</td>
</tr>
}
</tbody>
</table>
}
else
{
<p class="text-muted">No items added yet</p>
}
</div>
</div>
<div class="card shadow">
<div class="card-header bg-info text-white">
<h5 class="mb-0">Orders (@Model.OrderItems.Count)</h5>
</div>
<div class="card-body">
@if (Model.OrderItems.Any())
{
<table class="table table-hover">
<thead>
<tr>
<th>Participant</th>
<th>Item</th>
<th>Qty</th>
<th>Total</th>
</tr>
</thead>
<tbody>
@foreach (var orderItem in Model.OrderItems)
{
<tr>
<td>@orderItem.ParticipantName</td>
<td>@orderItem.MenuItem?.Name</td>
<td>@orderItem.Quantity</td>
<td>$@(orderItem.MenuItem?.Price * orderItem.Quantity ?? 0).ToString("F2")</td>
</tr>
}
</tbody>
</table>
}
else
{
<p class="text-muted">No orders yet</p>
}
</div>
</div>
</div>
<div class="col-md-4">
<div class="card shadow mb-4 bg-light">
<div class="card-body">
<h5>Share Order</h5>
<p>Send this link to others:</p>
<div class="input-group">
<input type="text" class="form-control" id="shareLink" value="@(Context.Request.Scheme)://@(Context.Request.Host)/order/join?code=@Model.OrderCode" readonly>
<button class="btn btn-outline-primary" onclick="copyToClipboard()">Copy</button>
</div>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-body">
<h5>Quick Stats</h5>
<p>Total Items: <strong>@Model.MenuItems.Count</strong></p>
<p>Total Orders: <strong>@Model.OrderItems.Count</strong></p>
<p>Total Revenue: <strong>$@Model.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p>
</div>
</div>
@if (!Model.IsClosed)
{
<a href="#" class="btn btn-danger w-100">Close Order</a>
}
</div>
</div>
</div>
<script>
function copyToClipboard() {
const link = document.getElementById('shareLink');
link.select();
document.execCommand('copy');
alert('Link copied to clipboard!');
}
</script>

151
Views/Order/Join.cshtml Normal file
View File

@@ -0,0 +1,151 @@
@model OneForMe.Models.Order
@{
ViewData["Title"] = "Join Order";
}
<div class="container mt-5">
<div class="row">
<div class="col-md-8">
<div class="card shadow mb-4">
<div class="card-body">
<h2>@Model.CreatorName</h2>
<p class="text-muted">Order Code: <strong>@Model.OrderCode</strong></p>
<p>Created by: <strong>@Model.CreatorName</strong></p>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Available Items</h5>
</div>
<div class="card-body">
@if (Model.MenuItems.Any())
{
<form method="post" action="/order/additem">
<input type="hidden" name="orderId" value="@Model.Id">
<div class="mb-3">
<label for="participantName" class="form-label">Your Name</label>
<input type="text" class="form-control" id="participantName" name="participantName" placeholder="Enter your name" required>
</div>
<div class="mb-3">
<label for="participantEmail" class="form-label">Your Email (optional)</label>
<input type="email" class="form-control" id="participantEmail" name="participantEmail" placeholder="Enter your email">
</div>
<div class="mb-3">
<label for="menuItemId" class="form-label">Select Item</label>
<select class="form-select" id="menuItemId" name="menuItemId" required onchange="updatePrice()">
<option value="">-- Choose an item --</option>
@foreach (var item in Model.MenuItems)
{
<option value="@item.Id" data-price="@item.Price.ToString("F2")">@item.Name - $@item.Price.ToString("F2")</option>
}
</select>
</div>
<div class="mb-3">
<label for="quantity" class="form-label">Quantity</label>
<input type="number" class="form-control" id="quantity" name="quantity" value="1" min="1" required>
</div>
<div class="alert alert-info">
<strong>Total:</strong> $<span id="totalPrice">0.00</span>
</div>
<button type="submit" class="btn btn-success">Add to Order</button>
<a href="/Home/Dashboard" class="btn btn-secondary">Back to Dashboard</a>
</form>
}
else
{
<p class="text-muted">No items available for this order</p>
}
</div>
</div>
</div>
<div class="col-md-4">
<div class="card shadow mb-4">
<div class="card-header bg-info text-white">
<h5 class="mb-0">Current Orders (@Model.OrderItems.Count)</h5>
</div>
<div class="card-body">
@if (Model.OrderItems.Any())
{
<table class="table table-sm table-hover">
<thead>
<tr>
<th>Name</th>
<th>Item</th>
<th>Qty</th>
<th>Total</th>
</tr>
</thead>
<tbody>
@foreach (var orderItem in Model.OrderItems)
{
<tr>
<td>@orderItem.ParticipantName</td>
<td>@orderItem.MenuItem?.Name</td>
<td>@orderItem.Quantity</td>
<td>$@(orderItem.MenuItem?.Price * orderItem.Quantity ?? 0).ToString("F2")</td>
</tr>
}
</tbody>
</table>
<hr>
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th>Person</th>
<th>Owes</th>
</tr>
</thead>
<tbody>
@foreach (var person in Model.OrderItems.GroupBy(oi => oi.ParticipantName))
{
<tr>
<td>@person.Key</td>
<td>$@person.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</td>
</tr>
}
</tbody>
</table>
</div>
}
else
{
<p class="text-muted">No one has ordered yet</p>
}
</div>
</div>
<div class="card shadow">
<div class="card-body">
<h5>Order Total</h5>
<h3 class="text-success">$@Model.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</h3>
</div>
</div>
</div>
</div>
</div>
<script>
function updatePrice() {
const select = document.getElementById('menuItemId');
const quantity = document.getElementById('quantity').value;
const selectedOption = select.options[select.selectedIndex];
const price = parseFloat(selectedOption.dataset.price) || 0;
const total = (price * quantity).toFixed(2);
document.getElementById('totalPrice').textContent = total;
}
document.getElementById('quantity').addEventListener('change', updatePrice);
document.getElementById('menuItemId').addEventListener('change', updatePrice);
</script>