Added localization

This commit is contained in:
2025-11-29 22:34:54 +01:00
parent 6819d1e38b
commit f930d9e408
9 changed files with 605 additions and 91 deletions

View File

@@ -16,6 +16,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.0-rc.2.25502.107" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="10.0.0-rc.2.25502.107" /> <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.0-rc.2.25502.107" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,6 +1,9 @@
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Localization;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using OneForMe.Data; using OneForMe.Data;
using OneForMe.Services;
using System.Globalization;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@@ -8,6 +11,16 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddControllersWithViews(); builder.Services.AddControllersWithViews();
// Add Localization
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[] { new CultureInfo("en"), new CultureInfo("de") };
options.DefaultRequestCulture = new RequestCulture("en");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
// Add Swagger/OpenAPI // Add Swagger/OpenAPI
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options => builder.Services.AddSwaggerGen(options =>
@@ -37,6 +50,9 @@ builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
.AddEntityFrameworkStores<ApplicationDbContext>() .AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders(); .AddDefaultTokenProviders();
// Add LocalizationService
builder.Services.AddScoped<LocalizationService>();
var app = builder.Build(); var app = builder.Build();
// Create and migrate database on startup // Create and migrate database on startup
@@ -64,6 +80,7 @@ if (!app.Environment.IsDevelopment())
} }
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseRequestLocalization();
app.UseRouting(); app.UseRouting();
app.UseAuthentication(); app.UseAuthentication();

View File

@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="Welcome" xml:space="preserve">
<value>Willkommen bei OneForMe</value>
</data>
<data name="LoggedInAs" xml:space="preserve">
<value>Angemeldet als</value>
</data>
<data name="Logout" xml:space="preserve">
<value>Abmelden</value>
</data>
<data name="CreateOrder" xml:space="preserve">
<value>Bestellung erstellen</value>
</data>
<data name="OrderName" xml:space="preserve">
<value>Bestellname</value>
</data>
<data name="EnterOrderName" xml:space="preserve">
<value>Geben Sie den Bestellnamen ein</value>
</data>
<data name="Description" xml:space="preserve">
<value>Beschreibung</value>
</data>
<data name="EnterDescription" xml:space="preserve">
<value>Geben Sie eine Beschreibung ein (optional)</value>
</data>
<data name="Restaurant" xml:space="preserve">
<value>Restaurant</value>
</data>
<data name="EnterRestaurantName" xml:space="preserve">
<value>Geben Sie den Restaurantnamen ein</value>
</data>
<data name="ItemName" xml:space="preserve">
<value>Artikelname</value>
</data>
<data name="Price" xml:space="preserve">
<value>Preis</value>
</data>
<data name="Remove" xml:space="preserve">
<value>Entfernen</value>
</data>
<data name="AddMenuItem" xml:space="preserve">
<value>Artikel hinzufügen</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Abbrechen</value>
</data>
<data name="CreateNewOrder" xml:space="preserve">
<value>Neue Bestellung erstellen</value>
</data>
<data name="StartGroupOrder" xml:space="preserve">
<value>Starten Sie eine neue Gruppenbestellung und laden Sie Freunde ein</value>
</data>
<data name="JoinOrder" xml:space="preserve">
<value>Bestellung beitreten</value>
</data>
<data name="JoinExistingOrder" xml:space="preserve">
<value>Treten Sie einer bestehenden Bestellung mit dem Bestellcode bei</value>
</data>
<data name="EnterOrderCode" xml:space="preserve">
<value>Bestellcode eingeben</value>
</data>
<data name="Join" xml:space="preserve">
<value>Beitreten</value>
</data>
<data name="MyCreatedOrders" xml:space="preserve">
<value>Meine Bestellungen</value>
</data>
<data name="OrdersIJoined" xml:space="preserve">
<value>Bestellungen, denen ich beigetreten bin</value>
</data>
<data name="NoCreatedOrders" xml:space="preserve">
<value>Sie haben noch keine Bestellungen erstellt.</value>
</data>
<data name="NoJoinedOrders" xml:space="preserve">
<value>Sie sind noch keiner Bestellung beigetreten.</value>
</data>
<data name="View" xml:space="preserve">
<value>Ansicht</value>
</data>
<data name="CloseOrder" xml:space="preserve">
<value>Bestellung abschließen</value>
</data>
<data name="Closed" xml:space="preserve">
<value>Abgeschlossen</value>
</data>
<data name="Code" xml:space="preserve">
<value>Code</value>
</data>
<data name="CreatedBy" xml:space="preserve">
<value>Erstellt von</value>
</data>
<data name="Items" xml:space="preserve">
<value>Artikel</value>
</data>
<data name="Orders" xml:space="preserve">
<value>Bestellungen</value>
</data>
<data name="Total" xml:space="preserve">
<value>Gesamt</value>
</data>
<data name="IOwe" xml:space="preserve">
<value>Ich schulde</value>
</data>
<data name="AddMore" xml:space="preserve">
<value>Mehr hinzufügen</value>
</data>
<data name="Status" xml:space="preserve">
<value>Status</value>
</data>
<data name="Open" xml:space="preserve">
<value>Offen</value>
</data>
<data name="MenuItems" xml:space="preserve">
<value>Menüpunkte</value>
</data>
<data name="Item" xml:space="preserve">
<value>Artikel</value>
</data>
<data name="Price" xml:space="preserve">
<value>Preis</value>
</data>
<data name="NoItemsAdded" xml:space="preserve">
<value>Noch keine Artikel hinzugefügt</value>
</data>
<data name="Participant" xml:space="preserve">
<value>Teilnehmer</value>
</data>
<data name="Qty" xml:space="preserve">
<value>Menge</value>
</data>
<data name="NoOrdersYet" xml:space="preserve">
<value>Noch keine Bestellungen</value>
</data>
<data name="ShareOrder" xml:space="preserve">
<value>Bestellung teilen</value>
</data>
<data name="SendLinkToOthers" xml:space="preserve">
<value>Senden Sie diesen Link an andere:</value>
</data>
<data name="Copy" xml:space="preserve">
<value>Kopieren</value>
</data>
<data name="QuickStats" xml:space="preserve">
<value>Schnellstatistiken</value>
</data>
<data name="TotalItems" xml:space="preserve">
<value>Gesamtartikel</value>
</data>
<data name="TotalOrders" xml:space="preserve">
<value>Gesamtbestellungen</value>
</data>
<data name="TotalRevenue" xml:space="preserve">
<value>Gesamtumsatz</value>
</data>
<data name="LinkCopied" xml:space="preserve">
<value>Link in die Zwischenablage kopiert!</value>
</data>
<data name="OrdersIJJoined" xml:space="preserve">
<value>Bestellungen, denen ich beigetreten bin</value>
</data>
<data name="YourName" xml:space="preserve">
<value>Ihr Name</value>
</data>
<data name="EnterYourName" xml:space="preserve">
<value>Geben Sie Ihren Namen ein</value>
</data>
<data name="YourEmail" xml:space="preserve">
<value>Ihre E-Mail (optional)</value>
</data>
<data name="EnterYourEmail" xml:space="preserve">
<value>Geben Sie Ihre E-Mail ein</value>
</data>
<data name="SelectItem" xml:space="preserve">
<value>Artikel auswählen</value>
</data>
<data name="ChooseAnItem" xml:space="preserve">
<value>Wählen Sie einen Artikel</value>
</data>
<data name="AddToOrder" xml:space="preserve">
<value>Zur Bestellung hinzufügen</value>
</data>
<data name="BackToDashboard" xml:space="preserve">
<value>Zurück zum Dashboard</value>
</data>
<data name="NoItemsAvailable" xml:space="preserve">
<value>Keine Artikel verfügbar für diese Bestellung</value>
</data>
<data name="CurrentOrders" xml:space="preserve">
<value>Aktuelle Bestellungen</value>
</data>
<data name="Person" xml:space="preserve">
<value>Person</value>
</data>
<data name="Owes" xml:space="preserve">
<value>schuldet</value>
</data>
<data name="OrderTotal" xml:space="preserve">
<value>Bestellsumme</value>
</data>
<data name="RestaurantName" xml:space="preserve">
<value>Restaurantname</value>
</data>
<data name="EnterRestaurantName" xml:space="preserve">
<value>Geben Sie den Restaurantnamen ein</value>
</data>
<data name="Description" xml:space="preserve">
<value>Beschreibung</value>
</data>
<data name="EnterDescription" xml:space="preserve">
<value>Geben Sie eine Beschreibung ein (optional)</value>
</data>
<data name="ItemName" xml:space="preserve">
<value>Artikel-Name</value>
</data>
<data name="EnterItemName" xml:space="preserve">
<value>Geben Sie den Artikelnamen ein</value>
</data>
<data name="AddMenuItem" xml:space="preserve">
<value>Artikel hinzufügen</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Abbrechen</value>
</data>
<data name="Remove" xml:space="preserve">
<value>Entfernen</value>
</data>
<data name="GiveOrderName" xml:space="preserve">
<value>Geben Sie Ihrer Bestellung einen Namen</value>
</data>
<data name="AddItemsThatPeopleCanOrder" xml:space="preserve">
<value>Fügen Sie Artikel hinzu, die Menschen bestellen können</value>
</data>
</root>

View File

@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="Welcome" xml:space="preserve">
<value>Welcome to OneForMe</value>
</data>
<data name="LoggedInAs" xml:space="preserve">
<value>Logged in as</value>
</data>
<data name="Logout" xml:space="preserve">
<value>Logout</value>
</data>
<data name="CreateOrder" xml:space="preserve">
<value>Create Order</value>
</data>
<data name="OrderName" xml:space="preserve">
<value>Order Name</value>
</data>
<data name="EnterOrderName" xml:space="preserve">
<value>Enter order name</value>
</data>
<data name="Description" xml:space="preserve">
<value>Description</value>
</data>
<data name="EnterDescription" xml:space="preserve">
<value>Enter a description (optional)</value>
</data>
<data name="Restaurant" xml:space="preserve">
<value>Restaurant</value>
</data>
<data name="EnterRestaurantName" xml:space="preserve">
<value>Enter restaurant name</value>
</data>
<data name="ItemName" xml:space="preserve">
<value>Item Name</value>
</data>
<data name="Price" xml:space="preserve">
<value>Price</value>
</data>
<data name="Remove" xml:space="preserve">
<value>Remove</value>
</data>
<data name="AddMenuItem" xml:space="preserve">
<value>Add Item</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="CreateNewOrder" xml:space="preserve">
<value>Create New Order</value>
</data>
<data name="StartGroupOrder" xml:space="preserve">
<value>Start a new group order and invite friends</value>
</data>
<data name="JoinOrder" xml:space="preserve">
<value>Join Order</value>
</data>
<data name="JoinExistingOrder" xml:space="preserve">
<value>Join an existing order using the order code</value>
</data>
<data name="EnterOrderCode" xml:space="preserve">
<value>Enter order code</value>
</data>
<data name="Join" xml:space="preserve">
<value>Join</value>
</data>
<data name="MyCreatedOrders" xml:space="preserve">
<value>My Orders</value>
</data>
<data name="OrdersIJoined" xml:space="preserve">
<value>Orders I Joined</value>
</data>
<data name="NoCreatedOrders" xml:space="preserve">
<value>You haven't created any orders yet.</value>
</data>
<data name="NoJoinedOrders" xml:space="preserve">
<value>You haven't joined any orders yet.</value>
</data>
<data name="View" xml:space="preserve">
<value>View</value>
</data>
<data name="CloseOrder" xml:space="preserve">
<value>Close Order</value>
</data>
<data name="Closed" xml:space="preserve">
<value>Closed</value>
</data>
<data name="Code" xml:space="preserve">
<value>Code</value>
</data>
<data name="CreatedBy" xml:space="preserve">
<value>Created by</value>
</data>
<data name="Items" xml:space="preserve">
<value>Items</value>
</data>
<data name="Orders" xml:space="preserve">
<value>Orders</value>
</data>
<data name="Total" xml:space="preserve">
<value>Total</value>
</data>
<data name="IOwe" xml:space="preserve">
<value>I owe</value>
</data>
<data name="AddMore" xml:space="preserve">
<value>Add More</value>
</data>
<data name="Status" xml:space="preserve">
<value>Status</value>
</data>
<data name="Open" xml:space="preserve">
<value>Open</value>
</data>
<data name="MenuItems" xml:space="preserve">
<value>Menu Items</value>
</data>
<data name="Item" xml:space="preserve">
<value>Item</value>
</data>
<data name="Price" xml:space="preserve">
<value>Price</value>
</data>
<data name="NoItemsAdded" xml:space="preserve">
<value>No items added yet</value>
</data>
<data name="Participant" xml:space="preserve">
<value>Participant</value>
</data>
<data name="Qty" xml:space="preserve">
<value>Qty</value>
</data>
<data name="NoOrdersYet" xml:space="preserve">
<value>No orders yet</value>
</data>
<data name="ShareOrder" xml:space="preserve">
<value>Share Order</value>
</data>
<data name="SendLinkToOthers" xml:space="preserve">
<value>Send this link to others:</value>
</data>
<data name="Copy" xml:space="preserve">
<value>Copy</value>
</data>
<data name="QuickStats" xml:space="preserve">
<value>Quick Stats</value>
</data>
<data name="TotalItems" xml:space="preserve">
<value>Total Items</value>
</data>
<data name="TotalOrders" xml:space="preserve">
<value>Total Orders</value>
</data>
<data name="TotalRevenue" xml:space="preserve">
<value>Total Revenue</value>
</data>
<data name="LinkCopied" xml:space="preserve">
<value>Link copied to clipboard!</value>
</data>
<data name="OrdersIJJoined" xml:space="preserve">
<value>Orders I joined</value>
</data>
<data name="YourName" xml:space="preserve">
<value>Your Name</value>
</data>
<data name="EnterYourName" xml:space="preserve">
<value>Enter your name</value>
</data>
<data name="YourEmail" xml:space="preserve">
<value>Your Email (optional)</value>
</data>
<data name="EnterYourEmail" xml:space="preserve">
<value>Enter your email</value>
</data>
<data name="SelectItem" xml:space="preserve">
<value>Select Item</value>
</data>
<data name="ChooseAnItem" xml:space="preserve">
<value>Choose an item</value>
</data>
<data name="AddToOrder" xml:space="preserve">
<value>Add to Order</value>
</data>
<data name="BackToDashboard" xml:space="preserve">
<value>Back to Dashboard</value>
</data>
<data name="NoItemsAvailable" xml:space="preserve">
<value>No items available for this order</value>
</data>
<data name="CurrentOrders" xml:space="preserve">
<value>Current Orders</value>
</data>
<data name="Person" xml:space="preserve">
<value>Person</value>
</data>
<data name="Owes" xml:space="preserve">
<value>Owes</value>
</data>
<data name="OrderTotal" xml:space="preserve">
<value>Order Total</value>
</data>
<data name="RestaurantName" xml:space="preserve">
<value>Restaurant Name</value>
</data>
<data name="EnterRestaurantName" xml:space="preserve">
<value>Enter restaurant name</value>
</data>
<data name="Description" xml:space="preserve">
<value>Description</value>
</data>
<data name="EnterDescription" xml:space="preserve">
<value>Enter a description (optional)</value>
</data>
<data name="ItemName" xml:space="preserve">
<value>Item Name</value>
</data>
<data name="EnterItemName" xml:space="preserve">
<value>Enter item name</value>
</data>
<data name="AddMenuItem" xml:space="preserve">
<value>Add Menu Item</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Remove" xml:space="preserve">
<value>Remove</value>
</data>
<data name="GiveOrderName" xml:space="preserve">
<value>Give your order a name</value>
</data>
<data name="AddItemsThatPeopleCanOrder" xml:space="preserve">
<value>Add items that people can order</value>
</data>
</root>

View File

@@ -0,0 +1,17 @@
using Microsoft.Extensions.Localization;
namespace OneForMe.Services;
public class LocalizationService
{
private readonly IStringLocalizer _localizer;
public LocalizationService(IStringLocalizerFactory factory)
{
_localizer = factory.Create("SharedResources", "OneForMe");
}
public string Get(string key) => _localizer[key];
public string this[string key] => _localizer[key];
}

View File

@@ -1,16 +1,18 @@
@using OneForMe.Controllers @using Microsoft.AspNetCore.Localization
@using OneForMe.Services
@inject LocalizationService Localizer
@model DashboardViewModel @model DashboardViewModel
@{ @{
ViewData["Title"] = "Dashboard"; ViewData["Title"] = Localizer.Get("Welcome");
} }
<div class="container mt-5"> <div class="container mt-5">
<div class="row mb-4"> <div class="row mb-4">
<div class="col-md-12"> <div class="col-md-12">
<h1>Welcome to OneForMe</h1> <h1>@Localizer.Get("Welcome")</h1>
<p>Logged in as: <strong>@User.Identity?.Name</strong></p> <p>@Localizer.Get("LoggedInAs"): <strong>@User.Identity?.Name</strong></p>
<a href="/AuthView/Logout" class="btn btn-danger">Logout</a> <a href="/AuthViewController/Logout" class="btn btn-danger">@Localizer.Get("Logout")</a>
</div> </div>
</div> </div>
@@ -18,9 +20,9 @@
<div class="col-md-6"> <div class="col-md-6">
<div class="card shadow"> <div class="card shadow">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Create New Order</h5> <h5 class="card-title">@Localizer.Get("CreateNewOrder")</h5>
<p class="card-text">Start a new group order and invite friends</p> <p class="card-text">@Localizer.Get("StartGroupOrder")</p>
<a href="/order/create" class="btn btn-primary">Create Order</a> <a href="/order/create" class="btn btn-primary">@Localizer.Get("CreateNewOrder")</a>
</div> </div>
</div> </div>
</div> </div>
@@ -28,12 +30,12 @@
<div class="col-md-6"> <div class="col-md-6">
<div class="card shadow"> <div class="card shadow">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Join Order</h5> <h5 class="card-title">@Localizer.Get("JoinOrder")</h5>
<p class="card-text">Join an existing order using the order code</p> <p class="card-text">@Localizer.Get("JoinExistingOrder")</p>
<form method="get" action="/order/join" class="mb-3"> <form method="get" action="/order/join" class="mb-3">
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control" name="code" placeholder="Enter order code" required> <input type="text" class="form-control" name="code" placeholder="@Localizer.Get("EnterOrderCode")" required>
<button class="btn btn-success" type="submit">Join</button> <button class="btn btn-success" type="submit">@Localizer.Get("Join")</button>
</div> </div>
</form> </form>
</div> </div>
@@ -46,7 +48,7 @@
<!-- Created Orders --> <!-- Created Orders -->
<div class="row mb-4"> <div class="row mb-4">
<div class="col-md-12"> <div class="col-md-12">
<h3>My Created Orders</h3> <h3>@Localizer.Get("MyCreatedOrders")</h3>
@if (Model.CreatedOrders.Any()) @if (Model.CreatedOrders.Any())
{ {
<div class="row"> <div class="row">
@@ -57,20 +59,20 @@
<div class="card-body"> <div class="card-body">
<h5 class="card-title">@order.CreatorName</h5> <h5 class="card-title">@order.CreatorName</h5>
<p class="card-text"> <p class="card-text">
<small class="text-muted">Code: <strong>@order.OrderCode</strong></small><br> <small class="text-muted">@Localizer.Get("Code"): <strong>@order.OrderCode</strong></small><br>
<small class="text-muted">Created: @order.CreatedAt.ToString("MMM dd, yyyy HH:mm")</small><br> <small class="text-muted">@Localizer.Get("Created"): @order.CreatedAt.ToString("MMM dd, yyyy HH:mm")</small><br>
<small>Items: @order.MenuItems.Count | Orders: @order.OrderItems.Count</small> <small>@Localizer.Get("Items"): @order.MenuItems.Count | @Localizer.Get("Orders"): @order.OrderItems.Count</small>
</p> </p>
<p class="text-success"><strong>Total: $@order.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p> <p class="text-success"><strong>@Localizer.Get("Total"): $@order.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="/order/details?code=@order.OrderCode" class="btn btn-sm btn-primary">View</a> <a href="/order/details?code=@order.OrderCode" class="btn btn-sm btn-primary">@Localizer.Get("View")</a>
@if (!order.IsClosed) @if (!order.IsClosed)
{ {
<a href="/order/close?code=@order.OrderCode" class="btn btn-sm btn-danger">Close Order</a> <a href="/order/close?code=@order.OrderCode" class="btn btn-sm btn-danger">@Localizer.Get("CloseOrder")</a>
} }
else else
{ {
<span class="badge bg-secondary">Closed</span> <span class="badge bg-secondary">@Localizer.Get("Closed")</span>
} }
</div> </div>
</div> </div>
@@ -81,7 +83,7 @@
} }
else else
{ {
<div class="alert alert-info">You haven't created any orders yet.</div> <div class="alert alert-info">@Localizer.Get("NoCreatedOrders")</div>
} }
</div> </div>
</div> </div>
@@ -91,7 +93,7 @@
<!-- Joined Orders --> <!-- Joined Orders -->
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h3>Orders I Joined</h3> <h3>@Localizer.Get("OrdersIJJoined")</h3>
@if (Model.JoinedOrders.Any()) @if (Model.JoinedOrders.Any())
{ {
<div class="row"> <div class="row">
@@ -103,16 +105,16 @@
<div class="card-body"> <div class="card-body">
<h5 class="card-title">@order.CreatorName</h5> <h5 class="card-title">@order.CreatorName</h5>
<p class="card-text"> <p class="card-text">
<small class="text-muted">Code: <strong>@order.OrderCode</strong></small><br> <small class="text-muted">@Localizer.Get("Code"): <strong>@order.OrderCode</strong></small><br>
<small class="text-muted">Created by: @order.CreatorName</small><br> <small class="text-muted">@Localizer.Get("CreatedBy"): @order.CreatorName</small><br>
<small>My items: @myItems.Count</small> <small>@Localizer.Get("MyItems"): @myItems.Count</small>
</p> </p>
<p class="text-warning"><strong>I owe: $@myItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p> <p class="text-warning"><strong>@Localizer.Get("IOwe"): $@myItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="/order/join?code=@order.OrderCode" class="btn btn-sm btn-primary">View</a> <a href="/order/join?code=@order.OrderCode" class="btn btn-sm btn-primary">@Localizer.Get("View")</a>
@if (!order.IsClosed) @if (!order.IsClosed)
{ {
<a href="/order/join?code=@order.OrderCode" class="btn btn-sm btn-success">Add More</a> <a href="/order/join?code=@order.OrderCode" class="btn btn-sm btn-success">@Localizer.Get("AddMore")</a>
} }
</div> </div>
</div> </div>
@@ -123,7 +125,7 @@
} }
else else
{ {
<div class="alert alert-info">You haven't joined any orders yet.</div> <div class="alert alert-info">@Localizer.Get("NoJoinedOrders")</div>
} }
</div> </div>
</div> </div>

View File

@@ -1,5 +1,8 @@
@using OneForMe.Services
@inject LocalizationService Localizer
@{ @{
ViewData["Title"] = "Create Order"; ViewData["Title"] = Localizer["CreateOrder"];
} }
<div class="container mt-5"> <div class="container mt-5">
@@ -7,43 +10,43 @@
<div class="col-md-8"> <div class="col-md-8">
<div class="card shadow"> <div class="card shadow">
<div class="card-body p-5"> <div class="card-body p-5">
<h2 class="mb-4">Create New Order</h2> <h2 class="mb-4">@Localizer["CreateNewOrder"]</h2>
<form method="post" id="createOrderForm"> <form method="post" id="createOrderForm">
<div class="mb-3"> <div class="mb-3">
<label for="creatorName" class="form-label">Order Name</label> <label for="creatorName" class="form-label">@Localizer["OrderName"]</label>
<input type="text" class="form-control" id="creatorName" name="creatorName" placeholder="e.g., Pizza Party" required> <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> <small class="text-muted">@Localizer["GiveOrderName"]</small>
</div> </div>
<hr> <hr>
<h5 class="mb-3">Menu Items</h5> <h5 class="mb-3">@Localizer["MenuItems"]</h5>
<p class="text-muted">Add items that people can order</p> <p class="text-muted">@Localizer["AddItemsThatPeopleCanOrder"]</p>
<div id="itemsContainer"> <div id="itemsContainer">
<div class="item-row mb-3"> <div class="item-row mb-3">
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<input type="text" class="form-control" placeholder="Item name (e.g., Margherita Pizza)" name="itemNames[]"> <input type="text" class="form-control" placeholder="@Localizer["EnterItemName"]" name="itemNames[]">
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<div class="input-group"> <div class="input-group">
<span class="input-group-text">$</span> <span class="input-group-text">$</span>
<input type="number" class="form-control" placeholder="Price" name="itemPrices[]" step="0.01" min="0"> <input type="number" class="form-control" placeholder="@Localizer["Price"]" name="itemPrices[]" step="0.01" min="0">
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<button type="button" class="btn btn-secondary mb-3" id="addItemBtn">+ Add Another Item</button> <button type="button" class="btn btn-secondary mb-3" id="addItemBtn">+ @Localizer["AddMenuItem"]</button>
<hr> <hr>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Create Order</button> <button type="submit" class="btn btn-primary">@Localizer["CreateOrder"]</button>
<a href="/Home/Dashboard" class="btn btn-secondary">Cancel</a> <a href="/Home/Dashboard" class="btn btn-secondary">@Localizer["Cancel"]</a>
</div> </div>
</form> </form>
</div> </div>
@@ -60,13 +63,13 @@ document.getElementById('addItemBtn').addEventListener('click', function() {
newRow.innerHTML = ` newRow.innerHTML = `
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<input type="text" class="form-control" placeholder="Item name" name="itemNames[]"> <input type="text" class="form-control" placeholder="@Localizer["ItemName"]" name="itemNames[]">
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<div class="input-group"> <div class="input-group">
<span class="input-group-text">$</span> <span class="input-group-text">$</span>
<input type="number" class="form-control" placeholder="Price" name="itemPrices[]" step="0.01" min="0"> <input type="number" class="form-control" placeholder="@Localizer["Price"]" name="itemPrices[]" step="0.01" min="0">
<button type="button" class="btn btn-outline-danger" onclick="this.closest('.item-row').remove()">Remove</button> <button type="button" class="btn btn-outline-danger" onclick="this.closest('.item-row').remove()">@Localizer["Remove"]</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,7 +1,10 @@
@using Microsoft.AspNetCore.Localization
@using OneForMe.Services
@inject LocalizationService Localizer
@model OneForMe.Models.Order @model OneForMe.Models.Order
@{ @{
ViewData["Title"] = "Order Details"; ViewData["Title"] = Model.CreatorName;
} }
<div class="container mt-5"> <div class="container mt-5">
@@ -10,15 +13,15 @@
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-body"> <div class="card-body">
<h2>@Model.CreatorName</h2> <h2>@Model.CreatorName</h2>
<p class="text-muted">Order Code: <strong>@Model.OrderCode</strong></p> <p class="text-muted">@Localizer.Get("Code"): <strong>@Model.OrderCode</strong></p>
<p>Created by: <strong>@Model.CreatorName</strong></p> <p>@Localizer.Get("CreatedBy"): <strong>@Model.CreatorName</strong></p>
<p>Status: <span class="badge @(Model.IsClosed ? "bg-danger" : "bg-success")">@(Model.IsClosed ? "Closed" : "Open")</span></p> <p>@Localizer.Get("Status"): <span class="badge @(Model.IsClosed ? "bg-danger" : "bg-success")">@(Model.IsClosed ? Localizer.Get("Closed") : Localizer.Get("Open"))</span></p>
</div> </div>
</div> </div>
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-header bg-primary text-white"> <div class="card-header bg-primary text-white">
<h5 class="mb-0">Menu Items</h5> <h5 class="mb-0">@Localizer.Get("MenuItems")</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
@if (Model.MenuItems.Any()) @if (Model.MenuItems.Any())
@@ -26,8 +29,8 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr> <tr>
<th>Item</th> <th>@Localizer.Get("Item")</th>
<th>Price</th> <th>@Localizer.Get("Price")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -43,14 +46,14 @@
} }
else else
{ {
<p class="text-muted">No items added yet</p> <p class="text-muted">@Localizer.Get("NoItemsAdded")</p>
} }
</div> </div>
</div> </div>
<div class="card shadow"> <div class="card shadow">
<div class="card-header bg-info text-white"> <div class="card-header bg-info text-white">
<h5 class="mb-0">Orders (@Model.OrderItems.Count)</h5> <h5 class="mb-0">@Localizer.Get("Orders") (@Model.OrderItems.Count)</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
@if (Model.OrderItems.Any()) @if (Model.OrderItems.Any())
@@ -58,10 +61,10 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr> <tr>
<th>Participant</th> <th>@Localizer.Get("Participant")</th>
<th>Item</th> <th>@Localizer.Get("Item")</th>
<th>Qty</th> <th>@Localizer.Get("Qty")</th>
<th>Total</th> <th>@Localizer.Get("Total")</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -79,7 +82,7 @@
} }
else else
{ {
<p class="text-muted">No orders yet</p> <p class="text-muted">@Localizer.Get("NoOrdersYet")</p>
} }
</div> </div>
</div> </div>
@@ -88,27 +91,27 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="card shadow mb-4 bg-light"> <div class="card shadow mb-4 bg-light">
<div class="card-body"> <div class="card-body">
<h5>Share Order</h5> <h5>@Localizer.Get("ShareOrder")</h5>
<p>Send this link to others:</p> <p>@Localizer.Get("SendLinkToOthers")</p>
<div class="input-group"> <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> <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> <button class="btn btn-outline-primary" onclick="copyToClipboard()">@Localizer.Get("Copy")</button>
</div> </div>
</div> </div>
</div> </div>
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-body"> <div class="card-body">
<h5>Quick Stats</h5> <h5>@Localizer.Get("QuickStats")</h5>
<p>Total Items: <strong>@Model.MenuItems.Count</strong></p> <p>@Localizer.Get("TotalItems"): <strong>@Model.MenuItems.Count</strong></p>
<p>Total Orders: <strong>@Model.OrderItems.Count</strong></p> <p>@Localizer.Get("TotalOrders"): <strong>@Model.OrderItems.Count</strong></p>
<p>Total Revenue: <strong>$@Model.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p> <p>@Localizer.Get("TotalRevenue"): <strong>$@Model.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</strong></p>
</div> </div>
</div> </div>
@if (!Model.IsClosed) @if (!Model.IsClosed)
{ {
<a href="#" class="btn btn-danger w-100">Close Order</a> <a href="#" class="btn btn-danger w-100">@Localizer.Get("CloseOrder")</a>
} }
</div> </div>
</div> </div>
@@ -119,6 +122,6 @@ function copyToClipboard() {
const link = document.getElementById('shareLink'); const link = document.getElementById('shareLink');
link.select(); link.select();
document.execCommand('copy'); document.execCommand('copy');
alert('Link copied to clipboard!'); alert('@Localizer.Get("LinkCopied")');
} }
</script> </script>

View File

@@ -1,7 +1,10 @@
@using OneForMe.Services
@inject LocalizationService Localizer
@model OneForMe.Models.Order @model OneForMe.Models.Order
@{ @{
ViewData["Title"] = "Join Order"; ViewData["Title"] = Localizer["JoinOrder"];
} }
<div class="container mt-5"> <div class="container mt-5">
@@ -10,14 +13,14 @@
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-body"> <div class="card-body">
<h2>@Model.CreatorName</h2> <h2>@Model.CreatorName</h2>
<p class="text-muted">Order Code: <strong>@Model.OrderCode</strong></p> <p class="text-muted">@Localizer["Code"]: <strong>@Model.OrderCode</strong></p>
<p>Created by: <strong>@Model.CreatorName</strong></p> <p>@Localizer["CreatedBy"]: <strong>@Model.CreatorName</strong></p>
</div> </div>
</div> </div>
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-header bg-primary text-white"> <div class="card-header bg-primary text-white">
<h5 class="mb-0">Available Items</h5> <h5 class="mb-0">@Localizer["MenuItems"]</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
@if (Model.MenuItems.Any()) @if (Model.MenuItems.Any())
@@ -26,19 +29,19 @@
<input type="hidden" name="orderId" value="@Model.Id"> <input type="hidden" name="orderId" value="@Model.Id">
<div class="mb-3"> <div class="mb-3">
<label for="participantName" class="form-label">Your Name</label> <label for="participantName" class="form-label">@Localizer["YourName"]</label>
<input type="text" class="form-control" id="participantName" name="participantName" placeholder="Enter your name" required> <input type="text" class="form-control" id="participantName" name="participantName" placeholder="@Localizer["EnterYourName"]" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="participantEmail" class="form-label">Your Email (optional)</label> <label for="participantEmail" class="form-label">@Localizer["YourEmail"]</label>
<input type="email" class="form-control" id="participantEmail" name="participantEmail" placeholder="Enter your email"> <input type="email" class="form-control" id="participantEmail" name="participantEmail" placeholder="@Localizer["EnterYourEmail"]">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="menuItemId" class="form-label">Select Item</label> <label for="menuItemId" class="form-label">@Localizer["SelectItem"]</label>
<select class="form-select" id="menuItemId" name="menuItemId" required onchange="updatePrice()"> <select class="form-select" id="menuItemId" name="menuItemId" required onchange="updatePrice()">
<option value="">-- Choose an item --</option> <option value="">-- @Localizer["ChooseAnItem"] --</option>
@foreach (var item in Model.MenuItems) @foreach (var item in Model.MenuItems)
{ {
<option value="@item.Id" data-price="@item.Price.ToString("F2")">@item.Name - $@item.Price.ToString("F2")</option> <option value="@item.Id" data-price="@item.Price.ToString("F2")">@item.Name - $@item.Price.ToString("F2")</option>
@@ -47,21 +50,21 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="quantity" class="form-label">Quantity</label> <label for="quantity" class="form-label">@Localizer["Qty"]</label>
<input type="number" class="form-control" id="quantity" name="quantity" value="1" min="1" required> <input type="number" class="form-control" id="quantity" name="quantity" value="1" min="1" required>
</div> </div>
<div class="alert alert-info"> <div class="alert alert-info">
<strong>Total:</strong> $<span id="totalPrice">0.00</span> <strong>@Localizer["Total"]:</strong> $<span id="totalPrice">0.00</span>
</div> </div>
<button type="submit" class="btn btn-success">Add to Order</button> <button type="submit" class="btn btn-success">@Localizer["AddToOrder"]</button>
<a href="/Home/Dashboard" class="btn btn-secondary">Back to Dashboard</a> <a href="/Home/Dashboard" class="btn btn-secondary">@Localizer["BackToDashboard"]</a>
</form> </form>
} }
else else
{ {
<p class="text-muted">No items available for this order</p> <p class="text-muted">@Localizer["NoItemsAvailable"]</p>
} }
</div> </div>
</div> </div>
@@ -70,7 +73,7 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-header bg-info text-white"> <div class="card-header bg-info text-white">
<h5 class="mb-0">Current Orders (@Model.OrderItems.Count)</h5> <h5 class="mb-0">@Localizer["CurrentOrders"] (@Model.OrderItems.Count)</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
@if (Model.OrderItems.Any()) @if (Model.OrderItems.Any())
@@ -78,10 +81,10 @@
<table class="table table-sm table-hover"> <table class="table table-sm table-hover">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>@Localizer["Participant"]</th>
<th>Item</th> <th>@Localizer["Item"]</th>
<th>Qty</th> <th>@Localizer["Qty"]</th>
<th>Total</th> <th>@Localizer["Total"]</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -91,7 +94,7 @@
<td>@orderItem.ParticipantName</td> <td>@orderItem.ParticipantName</td>
<td>@orderItem.MenuItem?.Name</td> <td>@orderItem.MenuItem?.Name</td>
<td>@orderItem.Quantity</td> <td>@orderItem.Quantity</td>
<td>$@(orderItem.MenuItem?.Price * orderItem.Quantity ?? 0).ToString("F2")</td> <td>$@((orderItem.MenuItem?.Price * orderItem.Quantity ?? 0).ToString("F2"))</td>
</tr> </tr>
} }
</tbody> </tbody>
@@ -103,8 +106,8 @@
<table class="table table-sm"> <table class="table table-sm">
<thead> <thead>
<tr> <tr>
<th>Person</th> <th>@Localizer["Person"]</th>
<th>Owes</th> <th>@Localizer["Owes"]</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -121,14 +124,14 @@
} }
else else
{ {
<p class="text-muted">No one has ordered yet</p> <p class="text-muted">@Localizer["NoOrdersYet"]</p>
} }
</div> </div>
</div> </div>
<div class="card shadow"> <div class="card shadow">
<div class="card-body"> <div class="card-body">
<h5>Order Total</h5> <h5>@Localizer["OrderTotal"]</h5>
<h3 class="text-success">$@Model.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</h3> <h3 class="text-success">$@Model.OrderItems.Sum(oi => oi.MenuItem.Price * oi.Quantity).ToString("F2")</h3>
</div> </div>
</div> </div>