Skip to content

Commit

Permalink
Implemented area management section of layout builder
Browse files Browse the repository at this point in the history
  • Loading branch information
fuj1n committed Jun 10, 2022
1 parent 49dea3b commit 604ee6d
Show file tree
Hide file tree
Showing 45 changed files with 41,700 additions and 110 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
# Logs
**/Logs/*

# Generated files
*.gen.*
*.gen

# Common IntelliJ Platform excludes

# User specific
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,15 +1,120 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using ReservationSystem_Server.Areas.Admin.Models;
using ReservationSystem_Server.Areas.Admin.Models.LayoutBuilder;
using ReservationSystem_Server.Data;
using ReservationSystem_Server.Data.Visual.Layout;

namespace ReservationSystem_Server.Areas.Admin.Controllers;

[Area("Admin")]
[Authorize(Roles = "Manager")]
[ApiController]
[Route("[area]/[controller]")]
#if DEBUG
[AllowAnonymous]
#endif
public class LayoutBuilderController : Controller
{
// GET
public IActionResult Index()
private readonly ApplicationDbContext _context;

public LayoutBuilderController(ApplicationDbContext context)
{
_context = context;
}

[HttpGet("{*path}", Order = 999)] // Catch all route, so that the underlying react app can use navigation links
public IActionResult Index(string? path)
{
return View();
}

[HttpGet("AreaLayout")]
public async Task<IActionResult> GetAreaLayout()
{
return Ok(
await _context.RestaurantAreas
.GroupJoin(_context.RestaurantAreaVisuals.DefaultIfEmpty(),
a => a.Id,
v => v.AreaId,
(a, v) => new { a, v })
.SelectMany(val => val.v.DefaultIfEmpty(), (val, v) => new AreaLayoutModel
{
Id = val.a.Id,
Name = val.a.Name,
Rect = LayoutModel.Rect.FromRectangleVisual(v != null ? v.Rect : null)
}).ToArrayAsync());
}

[HttpPut("AreaLayout")]
public async Task<IActionResult> PutAreaLayout(AreaLayoutModel[] areas)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

foreach (AreaLayoutModel model in areas)
{
RestaurantArea? area = await _context.RestaurantAreas.FirstOrDefaultAsync(a => a.Id == model.Id);

if (area == null)
{
// New area
area = new RestaurantArea
{
Name = model.Name,
RestaurantId = 1
};

_context.RestaurantAreas.Add(area);
await _context.SaveChangesAsync();

model.Id = area.Id;
}
else
{
// Update area
area.Name = model.Name;
}

RestaurantAreaVisual? visual =
await _context.RestaurantAreaVisuals.Include(v => v.Rect)
.FirstOrDefaultAsync(v => v.AreaId == area.Id);
if (visual == null)
{
visual = new RestaurantAreaVisual
{
AreaId = area.Id,
Rect = LayoutModel.Rect.ToRectangleVisual(model.Rect),
};

_context.RestaurantAreaVisuals.Add(visual);
}
else
{
RectangleVisual changedRect = LayoutModel.Rect.ToRectangleVisual(model.Rect);

visual.Rect.X = changedRect.X;
visual.Rect.Y = changedRect.Y;
visual.Rect.Width = changedRect.Width;
visual.Rect.Height = changedRect.Height;
visual.Rect.R = changedRect.R;
visual.Rect.G = changedRect.G;
visual.Rect.B = changedRect.B;
visual.Rect.A = changedRect.A;
}
}

// ToArray as EF couldn't translate areas.All({lambda})
foreach (RestaurantArea area in (await _context.RestaurantAreas.ToArrayAsync()).Where(a => areas.All(m => a.Id != m.Id)))
{
_context.RestaurantAreas.Remove(area);
}

await _context.SaveChangesAsync();
return Ok();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ReservationSystem_Server.Areas.Admin.Models.LayoutBuilder;

public class AreaLayoutModel
{
public int Id { get; set; }
public string Name { get; set; } = null!;

public LayoutModel.Rect Rect { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Drawing;
using System.Numerics;
using JetBrains.Annotations;
using ReservationSystem_Server.Data.Visual.Layout;

namespace ReservationSystem_Server.Areas.Admin.Models;

Expand Down Expand Up @@ -45,6 +46,31 @@ public Rect(float x, float y, float width, float height, Color color)
Height = height;
Color = color;
}

public static Rect FromRectangleVisual(RectangleVisual? visual)
{
if (visual is null)
return new Rect(50 - 25 / 2F, 50 - 25 / 2F, 25, 25, Color.Chocolate);

Color color = Color.FromArgb(visual.A, visual.R, visual.G, visual.B);
return new Rect(visual.X, visual.Y, visual.Width, visual.Height, color);
}

public static RectangleVisual ToRectangleVisual(Rect rect)
{
return new RectangleVisual
{
X = rect.X,
Y = rect.Y,
Width = rect.Width,
Height = rect.Height,

R = rect.Color.R,
G = rect.Color.G,
B = rect.Color.B,
A = rect.Color.A,
};
}
}

[PublicAPI]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,11 @@
@model ReservationSystem_Server.Areas.Admin.Models.LayoutModel

@{
@{
ViewBag.Title = "Layout Builder";
}

<ul class="nav nav-tabs" id="area-selector" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#home-tab-pane" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="true">Areas Layout</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#profile-tab-pane" type="button" role="tab" aria-controls="profile-tab-pane" aria-selected="false">Profile</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#contact-tab-pane" type="button" role="tab" aria-controls="contact-tab-pane" aria-selected="false">Contact</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="disabled-tab" data-bs-toggle="tab" data-bs-target="#disabled-tab-pane" type="button" role="tab" aria-controls="disabled-tab-pane" aria-selected="false" disabled>Disabled</button>
</li>
</ul>
<div class="tab-content" id="area-selector-content">
<div class="tab-pane fade show active" id="home-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
Tab 1
</div>
<div class="tab-pane fade" id="profile-tab-pane" role="tabpanel" aria-labelledby="profile-tab" tabindex="0">
Tab 2
</div>
<div class="tab-pane fade" id="contact-tab-pane" role="tabpanel" aria-labelledby="contact-tab" tabindex="0">
Tab 3
</div>
<div class="tab-pane fade" id="disabled-tab-pane" role="tabpanel" aria-labelledby="disabled-tab" tabindex="0">
Tab 4
</div>
</div>
<config
baseurl="@Url.Action("", "LayoutBuilder", new { Area = "Admin" }, Context.Request.Scheme)/"
root="@Url.Action("", "LayoutBuilder", new { Area = "Admin" })">
</config>
<div id="root"></div>

<script defer src="~/js/layout-builder.gen.js"></script>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@*The distiller is a partial view that renders the restaurant server-side without any client-side JS necessary*@
@*A distiller that renders the restaurant server-side without any client-side JS necessary*@

@using ReservationSystem_Server.Areas.Admin.Models
@using System.Drawing
Expand All @@ -11,19 +11,19 @@
LayoutModel layout = await LayoutUtility.BuildLayoutModel();

Queue<IHtmlContent> topmost = new();

// Transform child from parent percentage coordinate to SVG percentage coordinate
LayoutModel.Rect Transform(LayoutModel.Rect parent, LayoutModel.Rect child)
{
return new LayoutModel.Rect(
parent.X + (child.X * parent.Width / 100),
parent.Y + (child.Y * parent.Height / 100),
child.Width/* * parent.Width / 100*/, // size is relative to the canvas, so we don't transform it
child.Height/* * parent.Height / 100*/,
child.Width /* * parent.Width / 100*/, // size is relative to the canvas, so we don't transform it
child.Height /* * parent.Height / 100*/,
child.Color
);
}

IHtmlContent DrawRect(LayoutModel.Rect rect)
{
string c = ColorTranslator.ToHtml(rect.Color);
Expand All @@ -47,21 +47,21 @@
}

<svg>
<rect fill="#6c757d" x="0" y="0" width="100%" height="100%" />
<rect fill="#6c757d" x="0" y="0" width="100%" height="100%"/>
@foreach (LayoutModel.Area area in layout.Areas)
{
@DrawRect(area.Rect)
topmost.Enqueue(DrawLabel(area.Rect.X + 1.25f, area.Rect.Y + 1.25f, area.Name, area.Rect.Color.Darken(2)));

if (!layout.Tables.ContainsKey(area.Id)) break;
foreach(LayoutModel.Table table in layout.Tables[area.Id])
if (!layout.Tables.ContainsKey(area.Id)) continue;

foreach (LayoutModel.Table table in layout.Tables[area.Id])
{
if(!layout.TableTypes.ContainsKey(table.TableTypeId))
if (!layout.TableTypes.ContainsKey(table.TableTypeId))
{
LayoutModel.Rect relative = new(table.Position.X, table.Position.Y, 5, 5, Color.Red);
LayoutModel.Rect absolute = Transform(area.Rect, relative);

@DrawRect(absolute)
@DrawCenterLabel(absolute, "Invalid table type", Color.Red.Darken(2))
continue;
Expand All @@ -70,23 +70,24 @@
LayoutModel.TableType tableType = layout.TableTypes[table.TableTypeId];
LayoutModel.Rect tableRect = new(table.Position.X, table.Position.Y, tableType.CanvasSize.X, tableType.CanvasSize.Y, Color.Transparent);
tableRect = Transform(area.Rect, tableRect);

float accX = 0, accY = 0;
foreach(LayoutModel.Rect rect in tableType.Rectangles)

foreach (LayoutModel.Rect rect in tableType.Rectangles)
{
LayoutModel.Rect absolute = Transform(tableRect, rect);
accX += absolute.X + absolute.Width / 2;
accY += absolute.Y + absolute.Height / 2;

@DrawRect(absolute)
}

LayoutModel.Rect tableLabel = new(accX / tableType.Rectangles.Length, accY / tableType.Rectangles.Length, 0, 0, Color.Transparent);
@DrawCenterLabel(tableLabel, table.Name, Color.Black)
}

while (topmost.TryDequeue(out IHtmlContent? next))
@next
}
@while (topmost.TryDequeue(out IHtmlContent? next))
{
@next
}
</svg>
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<span class="d-flex flex-nowrap">
<li class="nav-item">
<div class="d-flex flex-nowrap">
<span class="nav-item">
<a class="nav-link" style="color: #941925" asp-area="" asp-controller="Home" asp-action="Index" cth-active>Exit Admin Area</a>
</li>
<li class="nav-item">
</span>
<span class="nav-item">
<a class="nav-link" asp-area="Admin" asp-controller="Home" asp-action="Index" cth-active>Admin Home</a>
</li>
<li class="nav-item">
</span>
<span class="nav-item">
<a class="nav-link" asp-area="Admin" asp-controller="Sitting" asp-action="Index" cth-active>Sittings</a>
</li>
<li class="nav-item">
</span>
<span class="nav-item">
<a class="nav-link" asp-area="Admin" asp-controller="Reservation" asp-action="Index" cth-active>Reservations</a>
</li>
<li class="nav-item">
</span>
<span class="nav-item">
<a class="nav-link" asp-area="Admin" asp-controller="Employee" asp-action="Index" cth-active>Employees</a>
</li>
<li class="nav-item">
</span>
<span class="nav-item">
<a class="nav-link" asp-area="Admin" asp-controller="Restaurant" asp-action="Index" cth-active>Restaurant</a>
</li>
</span>
</span>
</div>
Loading

0 comments on commit 604ee6d

Please sign in to comment.