Enhances application menu and adds calendar feature
Adds new calendar page and module with comprehensive initialization Introduces quick actions group in side menu with create booking and sale options Updates menu service to include new menu groups and rearrange sort order Configures custom npm registry and esbuild configuration Adds localization for new menu items and calendar section Implements calendar controller with dependency injection and settings seeding
This commit is contained in:
parent
435d9f11b7
commit
51f3b92d69
14 changed files with 422 additions and 10 deletions
|
|
@ -7,7 +7,11 @@
|
||||||
"Bash(dir /s /b \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\")",
|
"Bash(dir /s /b \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\")",
|
||||||
"Bash(findstr:*)",
|
"Bash(findstr:*)",
|
||||||
"Bash(dir \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\wwwroot\\\\*.html\")",
|
"Bash(dir \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\wwwroot\\\\*.html\")",
|
||||||
"Bash(dir /s /b \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\Features\\\\OnlineBooking\\\\*.cs\" \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\Features\\\\OnlineBooking\\\\*.cshtml\")"
|
"Bash(dir /s /b \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\Features\\\\OnlineBooking\\\\*.cs\" \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\Features\\\\OnlineBooking\\\\*.cshtml\")",
|
||||||
|
"Bash(npm view:*)",
|
||||||
|
"Bash(tar:*)",
|
||||||
|
"Bash(find:*)",
|
||||||
|
"Bash(npm install:*)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
PlanTempus.Application/.npmrc
Normal file
2
PlanTempus.Application/.npmrc
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
@novadi:registry=http://npm.jarjarbinks:4873
|
||||||
|
registry=http://npm.jarjarbinks:4873
|
||||||
37
PlanTempus.Application/Features/Calendar/Pages/Index.cshtml
Normal file
37
PlanTempus.Application/Features/Calendar/Pages/Index.cshtml
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
@page "/kalender"
|
||||||
|
@using PlanTempus.Application.Features.Calendar.Pages
|
||||||
|
@model PlanTempus.Application.Features.Calendar.Pages.IndexModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Kalender";
|
||||||
|
}
|
||||||
|
|
||||||
|
@section Styles {
|
||||||
|
<link rel="stylesheet" href="~/lib/calendar/dist/css/calendar.css" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="calendar-wrapper">
|
||||||
|
<swp-calendar-container>
|
||||||
|
<swp-time-axis>
|
||||||
|
<swp-header-spacer></swp-header-spacer>
|
||||||
|
<swp-time-axis-content id="time-axis"></swp-time-axis-content>
|
||||||
|
</swp-time-axis>
|
||||||
|
<swp-grid-container>
|
||||||
|
<swp-header-viewport>
|
||||||
|
<swp-header-track>
|
||||||
|
<swp-calendar-header></swp-calendar-header>
|
||||||
|
</swp-header-track>
|
||||||
|
<swp-header-drawer></swp-header-drawer>
|
||||||
|
</swp-header-viewport>
|
||||||
|
<swp-content-viewport>
|
||||||
|
<swp-content-track>
|
||||||
|
<swp-scrollable-content>
|
||||||
|
<swp-time-grid>
|
||||||
|
<swp-grid-lines></swp-grid-lines>
|
||||||
|
<swp-day-columns></swp-day-columns>
|
||||||
|
</swp-time-grid>
|
||||||
|
</swp-scrollable-content>
|
||||||
|
</swp-content-track>
|
||||||
|
</swp-content-viewport>
|
||||||
|
</swp-grid-container>
|
||||||
|
</swp-calendar-container>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
namespace PlanTempus.Application.Features.Calendar.Pages;
|
||||||
|
|
||||||
|
public class IndexModel : PageModel
|
||||||
|
{
|
||||||
|
public void OnGet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
"home": "Dashboard",
|
"home": "Dashboard",
|
||||||
"calendar": "Kalender",
|
"calendar": "Kalender",
|
||||||
"pos": "Kasse",
|
"pos": "Kasse",
|
||||||
|
"createBooking": "Opret booking",
|
||||||
|
"createSale": "Opret salg",
|
||||||
"products": "Produkter & Lager",
|
"products": "Produkter & Lager",
|
||||||
"suppliers": "Leverandører",
|
"suppliers": "Leverandører",
|
||||||
"customers": "Kunder",
|
"customers": "Kunder",
|
||||||
|
|
@ -16,6 +18,7 @@
|
||||||
},
|
},
|
||||||
"groups": {
|
"groups": {
|
||||||
"overview": "Overblik",
|
"overview": "Overblik",
|
||||||
|
"quickActions": "Hurtigvalg",
|
||||||
"data": "Data",
|
"data": "Data",
|
||||||
"online": "Online",
|
"online": "Online",
|
||||||
"analytics": "Analyse",
|
"analytics": "Analyse",
|
||||||
|
|
@ -762,5 +765,9 @@
|
||||||
"modules": "Moduler",
|
"modules": "Moduler",
|
||||||
"tracking": "Tracking"
|
"tracking": "Tracking"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"calendar": {
|
||||||
|
"title": "Kalender",
|
||||||
|
"subtitle": "Se og administrer bookinger"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ public class MockMenuService : IMenuService
|
||||||
Id = "calendar",
|
Id = "calendar",
|
||||||
Label = "Kalender",
|
Label = "Kalender",
|
||||||
Icon = "ph-calendar",
|
Icon = "ph-calendar",
|
||||||
Url = "/poc-calendar.html",
|
Url = "/kalender",
|
||||||
MinimumRole = UserRole.Staff,
|
MinimumRole = UserRole.Staff,
|
||||||
SortOrder = 2
|
SortOrder = 2
|
||||||
},
|
},
|
||||||
|
|
@ -87,12 +87,41 @@ public class MockMenuService : IMenuService
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// QUICK ACTIONS GROUP
|
||||||
|
new MenuGroup
|
||||||
|
{
|
||||||
|
Id = "quickActions",
|
||||||
|
Label = "Hurtigvalg",
|
||||||
|
SortOrder = 2,
|
||||||
|
Items = new List<MenuItem>
|
||||||
|
{
|
||||||
|
new MenuItem
|
||||||
|
{
|
||||||
|
Id = "createBooking",
|
||||||
|
Label = "Opret booking",
|
||||||
|
Icon = "ph-calendar-plus",
|
||||||
|
Url = "/opret-booking",
|
||||||
|
MinimumRole = UserRole.Staff,
|
||||||
|
SortOrder = 1
|
||||||
|
},
|
||||||
|
new MenuItem
|
||||||
|
{
|
||||||
|
Id = "createSale",
|
||||||
|
Label = "Opret salg",
|
||||||
|
Icon = "ph-shopping-cart",
|
||||||
|
Url = "/opret-salg",
|
||||||
|
MinimumRole = UserRole.Staff,
|
||||||
|
SortOrder = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// DATA GROUP
|
// DATA GROUP
|
||||||
new MenuGroup
|
new MenuGroup
|
||||||
{
|
{
|
||||||
Id = "data",
|
Id = "data",
|
||||||
Label = "Data",
|
Label = "Data",
|
||||||
SortOrder = 2,
|
SortOrder = 3,
|
||||||
Items = new List<MenuItem>
|
Items = new List<MenuItem>
|
||||||
{
|
{
|
||||||
new MenuItem
|
new MenuItem
|
||||||
|
|
@ -148,7 +177,7 @@ public class MockMenuService : IMenuService
|
||||||
{
|
{
|
||||||
Id = "online",
|
Id = "online",
|
||||||
Label = "Online",
|
Label = "Online",
|
||||||
SortOrder = 3,
|
SortOrder = 4,
|
||||||
Items = new List<MenuItem>
|
Items = new List<MenuItem>
|
||||||
{
|
{
|
||||||
new MenuItem
|
new MenuItem
|
||||||
|
|
@ -177,7 +206,7 @@ public class MockMenuService : IMenuService
|
||||||
{
|
{
|
||||||
Id = "analytics",
|
Id = "analytics",
|
||||||
Label = "Analyse",
|
Label = "Analyse",
|
||||||
SortOrder = 4,
|
SortOrder = 5,
|
||||||
Items = new List<MenuItem>
|
Items = new List<MenuItem>
|
||||||
{
|
{
|
||||||
new MenuItem
|
new MenuItem
|
||||||
|
|
@ -197,7 +226,7 @@ public class MockMenuService : IMenuService
|
||||||
{
|
{
|
||||||
Id = "system",
|
Id = "system",
|
||||||
Label = "System",
|
Label = "System",
|
||||||
SortOrder = 5,
|
SortOrder = 6,
|
||||||
Items = new List<MenuItem>
|
Items = new List<MenuItem>
|
||||||
{
|
{
|
||||||
new MenuItem
|
new MenuItem
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@using PlanTempus.Application.Features.Menu
|
@using PlanTempus.Application.Features.Menu
|
||||||
@model SideMenuViewModel
|
@model SideMenuViewModel
|
||||||
|
|
||||||
<swp-side-menu>
|
<swp-side-menu>
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<swp-side-menu-nav>
|
<swp-side-menu-nav>
|
||||||
@foreach (var group in Model.Groups)
|
@foreach (var group in Model.Groups)
|
||||||
{
|
{
|
||||||
<swp-side-menu-group>
|
<swp-side-menu-group data-group="@group.Id">
|
||||||
<swp-side-menu-label>@group.Label</swp-side-menu-label>
|
<swp-side-menu-label>@group.Label</swp-side-menu-label>
|
||||||
@foreach (var item in group.Items)
|
@foreach (var item in group.Items)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
<swp-side-menu-nav>
|
<swp-side-menu-nav>
|
||||||
@foreach (var group in Model.Groups)
|
@foreach (var group in Model.Groups)
|
||||||
{
|
{
|
||||||
<swp-side-menu-group>
|
<swp-side-menu-group data-group="@group.Id">
|
||||||
<swp-side-menu-label>@group.Label</swp-side-menu-label>
|
<swp-side-menu-label>@group.Label</swp-side-menu-label>
|
||||||
@foreach (var item in group.Items)
|
@foreach (var item in group.Items)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
14
PlanTempus.Application/esbuild.config.js
Normal file
14
PlanTempus.Application/esbuild.config.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import * as esbuild from 'esbuild';
|
||||||
|
import { NovadiUnplugin } from '@novadi/core/unplugin';
|
||||||
|
|
||||||
|
await esbuild.build({
|
||||||
|
entryPoints: ['wwwroot/ts/app.ts'],
|
||||||
|
bundle: true,
|
||||||
|
format: 'esm',
|
||||||
|
outfile: 'wwwroot/js/app.js',
|
||||||
|
sourcemap: 'inline',
|
||||||
|
target: 'es2020',
|
||||||
|
keepNames: true,
|
||||||
|
platform: 'browser',
|
||||||
|
plugins: [NovadiUnplugin.esbuild()]
|
||||||
|
});
|
||||||
151
PlanTempus.Application/package-lock.json
generated
151
PlanTempus.Application/package-lock.json
generated
|
|
@ -5,7 +5,9 @@
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@novadi/core": "^0.6.0",
|
||||||
"@sevenweirdpeople/swp-charting": "^0.2.5",
|
"@sevenweirdpeople/swp-charting": "^0.2.5",
|
||||||
|
"calendar": "^0.1.7",
|
||||||
"fuse.js": "^7.1.0"
|
"fuse.js": "^7.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -473,6 +475,66 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
|
"version": "0.3.13",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
|
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.24"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/remapping": {
|
||||||
|
"version": "2.3.5",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
||||||
|
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.24"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/resolve-uri": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
|
"version": "1.5.5",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||||
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.31",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
||||||
|
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@novadi/core": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/@novadi/core/-/core-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-CU1134Nd7ULMg9OQbID5oP+FLtrMkNiLJ17+dmy4jjmPDcPK/dVzKTFxvJmbBvEfZEc9WtmkmJjqw11ABU7Jxw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"unplugin": "^2.3.10"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "^4.52.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@pkgjs/parseargs": {
|
"node_modules/@pkgjs/parseargs": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||||
|
|
@ -484,12 +546,37 @@
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
|
"version": "4.57.0",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.0.tgz",
|
||||||
|
"integrity": "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@sevenweirdpeople/swp-charting": {
|
"node_modules/@sevenweirdpeople/swp-charting": {
|
||||||
"version": "0.2.5",
|
"version": "0.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@sevenweirdpeople/swp-charting/-/swp-charting-0.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/@sevenweirdpeople/swp-charting/-/swp-charting-0.2.5.tgz",
|
||||||
"integrity": "sha512-bQa5FtAXsTjjFxsE79sD1+A74R7f9YgVp5fC1fsiHoaLXmapDEO2dWuGX/MQ8rEChDZFyN1ZlkV+OLUs6qtfZw==",
|
"integrity": "sha512-bQa5FtAXsTjjFxsE79sD1+A74R7f9YgVp5fC1fsiHoaLXmapDEO2dWuGX/MQ8rEChDZFyN1ZlkV+OLUs6qtfZw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/acorn": {
|
||||||
|
"version": "8.15.0",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/acorn/-/acorn-8.15.0.tgz",
|
||||||
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"acorn": "bin/acorn"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ansi-regex": {
|
"node_modules/ansi-regex": {
|
||||||
"version": "6.2.2",
|
"version": "6.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
|
||||||
|
|
@ -533,6 +620,17 @@
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/calendar": {
|
||||||
|
"version": "0.1.7",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/calendar/-/calendar-0.1.7.tgz",
|
||||||
|
"integrity": "sha512-9KLvHRMezHFwdpkpNSoOO0yi58D+tcXefo+2uSQznDK3hCKnUng1yBb6XG2XtUJD+SSyi5Y1/zOWRo9DxnxabA==",
|
||||||
|
"dependencies": {
|
||||||
|
"dayjs": "^1.11.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@novadi/core": "^0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
|
@ -591,6 +689,12 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dayjs": {
|
||||||
|
"version": "1.11.19",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/dayjs/-/dayjs-1.11.19.tgz",
|
||||||
|
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/eastasianwidth": {
|
"node_modules/eastasianwidth": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||||
|
|
@ -820,6 +924,18 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.6",
|
"version": "8.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||||
|
|
@ -1029,6 +1145,35 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.9.3",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/typescript/-/typescript-5.9.3.tgz",
|
||||||
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unplugin": {
|
||||||
|
"version": "2.3.11",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/unplugin/-/unplugin-2.3.11.tgz",
|
||||||
|
"integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/remapping": "^2.3.5",
|
||||||
|
"acorn": "^8.15.0",
|
||||||
|
"picomatch": "^4.0.3",
|
||||||
|
"webpack-virtual-modules": "^0.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
|
@ -1036,6 +1181,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/webpack-virtual-modules": {
|
||||||
|
"version": "0.6.2",
|
||||||
|
"resolved": "http://npm.jarjarbinks:4873/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
||||||
|
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@
|
||||||
"purgecss": "^6.0.0"
|
"purgecss": "^6.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "esbuild wwwroot/ts/app.ts --bundle --format=esm --outfile=wwwroot/js/app.js --sourcemap=inline --target=es2020 --keep-names --platform=browser",
|
"build": "node esbuild.config.js",
|
||||||
"analyze-css": "node analyze-css.js"
|
"analyze-css": "node analyze-css.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@novadi/core": "^0.6.0",
|
||||||
"@sevenweirdpeople/swp-charting": "^0.2.5",
|
"@sevenweirdpeople/swp-charting": "^0.2.5",
|
||||||
|
"calendar": "^0.1.7",
|
||||||
"fuse.js": "^7.1.0"
|
"fuse.js": "^7.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ swp-side-menu-group {
|
||||||
margin-bottom: var(--spacing-2);
|
margin-bottom: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
swp-side-menu-label {
|
swp-side-menu-label {
|
||||||
display: block;
|
display: block;
|
||||||
padding: var(--spacing-2) var(--spacing-4) 6px;
|
padding: var(--spacing-2) var(--spacing-4) 6px;
|
||||||
|
|
@ -125,6 +126,28 @@ a[is="swp-side-menu-item"] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===========================================
|
||||||
|
QUICK ACTIONS GROUP - Highlighted
|
||||||
|
=========================================== */
|
||||||
|
swp-side-menu-group[data-group="quickActions"] {
|
||||||
|
background: rgba(255, 235, 59, 0.15);
|
||||||
|
margin: var(--spacing-2) var(--spacing-2) var(--spacing-3);
|
||||||
|
padding: var(--spacing-2) 0;
|
||||||
|
border-radius: var(--border-radius-lg);
|
||||||
|
border: 1px solid rgba(255, 193, 7, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-side-menu-group[data-group="quickActions"] swp-side-menu-label {
|
||||||
|
padding-left: var(--spacing-3);
|
||||||
|
padding-right: var(--spacing-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-side-menu-group[data-group="quickActions"] a[is="swp-side-menu-item"] {
|
||||||
|
padding-left: var(--spacing-3);
|
||||||
|
padding-right: var(--spacing-3);
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===========================================
|
/* ===========================================
|
||||||
FOOTER
|
FOOTER
|
||||||
=========================================== */
|
=========================================== */
|
||||||
|
|
@ -223,6 +246,17 @@ swp-app-layout.menu-collapsed swp-side-menu-footer {
|
||||||
padding: var(--spacing-3) var(--spacing-2);
|
padding: var(--spacing-3) var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Quick Actions - Collapsed State */
|
||||||
|
swp-app-layout.menu-collapsed swp-side-menu-group[data-group="quickActions"] {
|
||||||
|
margin: var(--spacing-2) var(--spacing-1);
|
||||||
|
padding: var(--spacing-2) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-app-layout.menu-collapsed swp-side-menu-group[data-group="quickActions"] a[is="swp-side-menu-item"] {
|
||||||
|
padding: var(--spacing-3);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===========================================
|
/* ===========================================
|
||||||
TOOLTIP (Collapsed State)
|
TOOLTIP (Collapsed State)
|
||||||
=========================================== */
|
=========================================== */
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import { CustomersController } from './modules/customers';
|
||||||
import { SuppliersController } from './modules/suppliers';
|
import { SuppliersController } from './modules/suppliers';
|
||||||
import { TrackingController } from './modules/tracking';
|
import { TrackingController } from './modules/tracking';
|
||||||
import { ReportsController } from './modules/reports';
|
import { ReportsController } from './modules/reports';
|
||||||
|
import { CalendarController } from './modules/calendar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main application class
|
* Main application class
|
||||||
|
|
@ -35,6 +36,7 @@ export class App {
|
||||||
readonly suppliers: SuppliersController;
|
readonly suppliers: SuppliersController;
|
||||||
readonly tracking: TrackingController;
|
readonly tracking: TrackingController;
|
||||||
readonly reports: ReportsController;
|
readonly reports: ReportsController;
|
||||||
|
readonly calendar: CalendarController;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Initialize controllers
|
// Initialize controllers
|
||||||
|
|
@ -51,6 +53,7 @@ export class App {
|
||||||
this.suppliers = new SuppliersController();
|
this.suppliers = new SuppliersController();
|
||||||
this.tracking = new TrackingController();
|
this.tracking = new TrackingController();
|
||||||
this.reports = new ReportsController();
|
this.reports = new ReportsController();
|
||||||
|
this.calendar = new CalendarController();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
119
PlanTempus.Application/wwwroot/ts/modules/calendar.ts
Normal file
119
PlanTempus.Application/wwwroot/ts/modules/calendar.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
/**
|
||||||
|
* Calendar Controller
|
||||||
|
*
|
||||||
|
* Integrates the calendar package into PlanTempus.
|
||||||
|
* Uses NovaDI for dependency injection and IndexedDB for offline storage.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Container } from '@novadi/core';
|
||||||
|
import {
|
||||||
|
registerCoreServices,
|
||||||
|
CalendarApp,
|
||||||
|
IndexedDBContext,
|
||||||
|
SettingsService,
|
||||||
|
ViewConfigService,
|
||||||
|
EventBus,
|
||||||
|
CalendarEvents
|
||||||
|
} from 'calendar';
|
||||||
|
import { registerSchedules } from 'calendar/schedules';
|
||||||
|
|
||||||
|
export class CalendarController {
|
||||||
|
private app: Container | null = null;
|
||||||
|
private calendarApp: CalendarApp | null = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
const containerEl = document.querySelector('swp-calendar-container');
|
||||||
|
if (!containerEl) return;
|
||||||
|
this.init(containerEl as HTMLElement).catch(err => {
|
||||||
|
console.error('[CalendarController] Init failed:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async init(containerEl: HTMLElement): Promise<void> {
|
||||||
|
console.log('[CalendarController] Starting init...');
|
||||||
|
|
||||||
|
// Create DI container using the pattern from README
|
||||||
|
const container = new Container();
|
||||||
|
const builder = container.builder();
|
||||||
|
registerCoreServices(builder, {
|
||||||
|
dbConfig: { dbName: 'PlanTempusCalendarDB', dbVersion: 1 }
|
||||||
|
});
|
||||||
|
registerSchedules(builder);
|
||||||
|
this.app = builder.build();
|
||||||
|
console.log('[CalendarController] Container built');
|
||||||
|
|
||||||
|
// Initialize IndexedDB
|
||||||
|
const dbContext = this.app.resolveType<IndexedDBContext>();
|
||||||
|
await dbContext.initialize();
|
||||||
|
console.log('[CalendarController] IndexedDB initialized');
|
||||||
|
|
||||||
|
// Seed required settings
|
||||||
|
await this.seedSettings();
|
||||||
|
console.log('[CalendarController] Settings seeded');
|
||||||
|
|
||||||
|
// Initialize CalendarApp
|
||||||
|
this.calendarApp = this.app.resolveType<CalendarApp>();
|
||||||
|
await this.calendarApp.init(containerEl);
|
||||||
|
console.log('[CalendarController] CalendarApp initialized');
|
||||||
|
|
||||||
|
// Render default view
|
||||||
|
const eventBus = this.app.resolveType<EventBus>();
|
||||||
|
eventBus.emit(CalendarEvents.CMD_RENDER, { viewId: 'simple' });
|
||||||
|
console.log('[CalendarController] Render command emitted');
|
||||||
|
}
|
||||||
|
|
||||||
|
private async seedSettings(): Promise<void> {
|
||||||
|
if (!this.app) return;
|
||||||
|
|
||||||
|
const settingsService = this.app.resolveType<SettingsService>();
|
||||||
|
const viewConfigService = this.app.resolveType<ViewConfigService>();
|
||||||
|
|
||||||
|
// Grid settings
|
||||||
|
await settingsService.save({
|
||||||
|
id: 'grid',
|
||||||
|
dayStartHour: 8,
|
||||||
|
dayEndHour: 18,
|
||||||
|
workStartHour: 9,
|
||||||
|
workEndHour: 17,
|
||||||
|
hourHeight: 64,
|
||||||
|
snapInterval: 15,
|
||||||
|
syncStatus: 'synced'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Workweek settings
|
||||||
|
await settingsService.save({
|
||||||
|
id: 'workweek',
|
||||||
|
presets: {
|
||||||
|
standard: { id: 'standard', label: 'Standard', workDays: [1, 2, 3, 4, 5], periodDays: 7 }
|
||||||
|
},
|
||||||
|
defaultPreset: 'standard',
|
||||||
|
firstDayOfWeek: 1,
|
||||||
|
syncStatus: 'synced'
|
||||||
|
});
|
||||||
|
|
||||||
|
// View configuration
|
||||||
|
await viewConfigService.save({
|
||||||
|
id: 'simple',
|
||||||
|
groupings: [{ type: 'date', values: [], idProperty: 'date', derivedFrom: 'start' }],
|
||||||
|
syncStatus: 'synced'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
navigatePrev(): void {
|
||||||
|
if (!this.app) return;
|
||||||
|
const eventBus = this.app.resolveType<EventBus>();
|
||||||
|
eventBus.emit(CalendarEvents.CMD_NAVIGATE_PREV);
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateNext(): void {
|
||||||
|
if (!this.app) return;
|
||||||
|
const eventBus = this.app.resolveType<EventBus>();
|
||||||
|
eventBus.emit(CalendarEvents.CMD_NAVIGATE_NEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleDrawer(): void {
|
||||||
|
if (!this.app) return;
|
||||||
|
const eventBus = this.app.resolveType<EventBus>();
|
||||||
|
eventBus.emit(CalendarEvents.CMD_DRAWER_TOGGLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue