diff --git a/PlanTempus.Application/Features/Customers/Components/CustomerRow/CustomerRowViewComponent.cs b/PlanTempus.Application/Features/Customers/Components/CustomerRow/CustomerRowViewComponent.cs
new file mode 100644
index 0000000..b99737c
--- /dev/null
+++ b/PlanTempus.Application/Features/Customers/Components/CustomerRow/CustomerRowViewComponent.cs
@@ -0,0 +1,11 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace PlanTempus.Application.Features.Customers.Components;
+
+public class CustomerRowViewComponent : ViewComponent
+{
+ public IViewComponentResult Invoke(CustomerItemViewModel customer)
+ {
+ return View(customer);
+ }
+}
diff --git a/PlanTempus.Application/Features/Customers/Components/CustomerRow/Default.cshtml b/PlanTempus.Application/Features/Customers/Components/CustomerRow/Default.cshtml
new file mode 100644
index 0000000..965d94c
--- /dev/null
+++ b/PlanTempus.Application/Features/Customers/Components/CustomerRow/Default.cshtml
@@ -0,0 +1,38 @@
+@model PlanTempus.Application.Features.Customers.Components.CustomerItemViewModel
+
+
+
+ @Model.Initials
+
+
+
+ @Model.FullName
+
+ @Model.Phone
+ @Model.Email
+ @Model.Visits
+ @Model.LastVisit
+ @Model.PreferredHairdresser
+ @Model.CreatedAt
+
+ @foreach (var tag in Model.Tags)
+ {
+ @GetTagLabel(tag)
+ }
+
+
+
+@functions {
+ string GetTagLabel(string tag)
+ {
+ return tag switch
+ {
+ "vip" => "VIP",
+ "ny" => "Ny",
+ "allergi" => "Allergi",
+ "sensitiv" => "Sensitiv",
+ "stamkunde" => "Stamkunde",
+ _ => tag
+ };
+ }
+}
diff --git a/PlanTempus.Application/Features/Customers/Components/CustomerTable/CustomerTableViewComponent.cs b/PlanTempus.Application/Features/Customers/Components/CustomerTable/CustomerTableViewComponent.cs
new file mode 100644
index 0000000..3e205a1
--- /dev/null
+++ b/PlanTempus.Application/Features/Customers/Components/CustomerTable/CustomerTableViewComponent.cs
@@ -0,0 +1,139 @@
+using System.Globalization;
+using System.Text.Json;
+using Microsoft.AspNetCore.Mvc;
+using PlanTempus.Application.Features.Localization.Services;
+
+namespace PlanTempus.Application.Features.Customers.Components;
+
+public class CustomerTableViewComponent : ViewComponent
+{
+ private readonly ILocalizationService _localization;
+ private readonly IWebHostEnvironment _env;
+
+ public CustomerTableViewComponent(ILocalizationService localization, IWebHostEnvironment env)
+ {
+ _localization = localization;
+ _env = env;
+ }
+
+ public IViewComponentResult Invoke()
+ {
+ var data = LoadCustomerData();
+ var model = new CustomerTableViewModel
+ {
+ SearchPlaceholder = _localization.Get("customers.searchPlaceholder"),
+ ExportButtonText = _localization.Get("customers.export"),
+ CreateButtonText = _localization.Get("customers.create"),
+ ColumnName = _localization.Get("customers.column.name"),
+ ColumnPhone = _localization.Get("customers.column.phone"),
+ ColumnEmail = _localization.Get("customers.column.email"),
+ ColumnVisits = _localization.Get("customers.column.visits"),
+ ColumnLastVisit = _localization.Get("customers.column.lastVisit"),
+ ColumnHairdresser = _localization.Get("customers.column.hairdresser"),
+ ColumnCreated = _localization.Get("customers.column.created"),
+ ColumnTags = _localization.Get("customers.column.tags"),
+ EmptySearchText = _localization.Get("customers.emptySearch"),
+ Customers = data.Customers
+ .OrderBy(c => c.FirstName)
+ .ThenBy(c => c.LastName)
+ .Select(c => new CustomerItemViewModel
+ {
+ Id = c.Id,
+ FullName = $"{c.FirstName} {c.LastName}",
+ Initials = c.Initials,
+ Phone = c.Phone,
+ Email = c.Email,
+ Visits = c.Visits,
+ LastVisit = FormatLastVisit(c.LastVisit),
+ PreferredHairdresser = c.PreferredHairdresser,
+ CreatedAt = FormatCreatedAt(c.CreatedAt),
+ Tags = c.Tags,
+ AvatarColor = c.AvatarColor
+ })
+ .ToList()
+ };
+
+ return View(model);
+ }
+
+ private CustomerMockData LoadCustomerData()
+ {
+ var jsonPath = Path.Combine(_env.ContentRootPath, "Features", "Customers", "Data", "customersMock.json");
+ var json = System.IO.File.ReadAllText(jsonPath);
+ return JsonSerializer.Deserialize(json, new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ }) ?? new CustomerMockData();
+ }
+
+ private static string FormatLastVisit(string dateStr)
+ {
+ if (DateTime.TryParse(dateStr, out var date))
+ {
+ return date.ToString("d. MMM", new CultureInfo("da-DK")).TrimEnd('.');
+ }
+ return dateStr;
+ }
+
+ private static string FormatCreatedAt(string dateStr)
+ {
+ if (DateTime.TryParse(dateStr, out var date))
+ {
+ return date.ToString("MMM yyyy", new CultureInfo("da-DK"));
+ }
+ return dateStr;
+ }
+}
+
+public class CustomerTableViewModel
+{
+ public required string SearchPlaceholder { get; init; }
+ public required string ExportButtonText { get; init; }
+ public required string CreateButtonText { get; init; }
+ public required string ColumnName { get; init; }
+ public required string ColumnPhone { get; init; }
+ public required string ColumnEmail { get; init; }
+ public required string ColumnVisits { get; init; }
+ public required string ColumnLastVisit { get; init; }
+ public required string ColumnHairdresser { get; init; }
+ public required string ColumnCreated { get; init; }
+ public required string ColumnTags { get; init; }
+ public required string EmptySearchText { get; init; }
+ public required IReadOnlyList Customers { get; init; }
+}
+
+public class CustomerItemViewModel
+{
+ public required string Id { get; init; }
+ public required string FullName { get; init; }
+ public required string Initials { get; init; }
+ public required string Phone { get; init; }
+ public required string Email { get; init; }
+ public int Visits { get; init; }
+ public required string LastVisit { get; init; }
+ public required string PreferredHairdresser { get; init; }
+ public required string CreatedAt { get; init; }
+ public required IReadOnlyList Tags { get; init; }
+ public string? AvatarColor { get; init; }
+}
+
+internal class CustomerMockData
+{
+ public List Customers { get; set; } = new();
+}
+
+internal class CustomerData
+{
+ public string Id { get; set; } = "";
+ public string FirstName { get; set; } = "";
+ public string LastName { get; set; } = "";
+ public string Initials { get; set; } = "";
+ public string Phone { get; set; } = "";
+ public string Email { get; set; } = "";
+ public int Visits { get; set; }
+ public string LastVisit { get; set; } = "";
+ public string PreferredHairdresser { get; set; } = "";
+ public string CreatedAt { get; set; } = "";
+ public List Tags { get; set; } = new();
+ public string? AvatarColor { get; set; }
+}
diff --git a/PlanTempus.Application/Features/Customers/Components/CustomerTable/Default.cshtml b/PlanTempus.Application/Features/Customers/Components/CustomerTable/Default.cshtml
new file mode 100644
index 0000000..8b25c9f
--- /dev/null
+++ b/PlanTempus.Application/Features/Customers/Components/CustomerTable/Default.cshtml
@@ -0,0 +1,42 @@
+@model PlanTempus.Application.Features.Customers.Components.CustomerTableViewModel
+
+
+
+
+
+
+
+
+
+ @Model.ExportButtonText
+
+
+
+ @Model.CreateButtonText
+
+
+
+
+
+
+
+ @Model.ColumnName
+ @Model.ColumnPhone
+ @Model.ColumnEmail
+ @Model.ColumnVisits
+ @Model.ColumnLastVisit
+ @Model.ColumnHairdresser
+ @Model.ColumnCreated
+ @Model.ColumnTags
+
+ @foreach (var customer in Model.Customers)
+ {
+ @await Component.InvokeAsync("CustomerRow", customer)
+ }
+
+
+
+
+ @Model.EmptySearchText
+
+
diff --git a/PlanTempus.Application/Features/Customers/Data/customersMock.json b/PlanTempus.Application/Features/Customers/Data/customersMock.json
new file mode 100644
index 0000000..17bd5c3
--- /dev/null
+++ b/PlanTempus.Application/Features/Customers/Data/customersMock.json
@@ -0,0 +1,172 @@
+{
+ "customers": [
+ {
+ "id": "anna-jensen",
+ "firstName": "Anna",
+ "lastName": "Jensen",
+ "initials": "AJ",
+ "phone": "+45 22 33 44 55",
+ "email": "anna.j@hotmail.dk",
+ "visits": 6,
+ "lastVisit": "2025-11-15",
+ "preferredHairdresser": "Nina K.",
+ "createdAt": "2024-09-01",
+ "tags": [],
+ "avatarColor": null
+ },
+ {
+ "id": "camilla-holm",
+ "firstName": "Camilla",
+ "lastName": "Holm",
+ "initials": "CH",
+ "phone": "+45 66 77 88 99",
+ "email": "camilla.h@outlook.dk",
+ "visits": 25,
+ "lastVisit": "2025-10-28",
+ "preferredHairdresser": "Emma L.",
+ "createdAt": "2022-12-01",
+ "tags": ["vip"],
+ "avatarColor": null
+ },
+ {
+ "id": "emma-larsen",
+ "firstName": "Emma",
+ "lastName": "Larsen",
+ "initials": "EL",
+ "phone": "+45 12 34 56 78",
+ "email": "emma.l@gmail.com",
+ "visits": 8,
+ "lastVisit": "2025-12-05",
+ "preferredHairdresser": "Nina K.",
+ "createdAt": "2024-06-01",
+ "tags": [],
+ "avatarColor": null
+ },
+ {
+ "id": "freja-christensen",
+ "firstName": "Freja",
+ "lastName": "Christensen",
+ "initials": "FC",
+ "phone": "+45 55 66 77 88",
+ "email": "freja.c@outlook.dk",
+ "visits": 31,
+ "lastVisit": "2025-11-20",
+ "preferredHairdresser": "Emma L.",
+ "createdAt": "2022-08-01",
+ "tags": ["vip", "allergi"],
+ "avatarColor": null
+ },
+ {
+ "id": "ida-andersen",
+ "firstName": "Ida",
+ "lastName": "Andersen",
+ "initials": "IA",
+ "phone": "+45 11 22 33 44",
+ "email": "ida@firma.dk",
+ "visits": 3,
+ "lastVisit": "2025-11-28",
+ "preferredHairdresser": "Sofie M.",
+ "createdAt": "2025-10-01",
+ "tags": ["ny"],
+ "avatarColor": null
+ },
+ {
+ "id": "katrine-berg",
+ "firstName": "Katrine",
+ "lastName": "Berg",
+ "initials": "KB",
+ "phone": "+45 55 66 77 88",
+ "email": "katrine.b@firma.dk",
+ "visits": 12,
+ "lastVisit": "2025-11-01",
+ "preferredHairdresser": "Nina K.",
+ "createdAt": "2024-04-01",
+ "tags": [],
+ "avatarColor": null
+ },
+ {
+ "id": "line-frost",
+ "firstName": "Line",
+ "lastName": "Frost",
+ "initials": "LF",
+ "phone": "+45 88 99 00 11",
+ "email": "line.f@mail.dk",
+ "visits": 9,
+ "lastVisit": "2025-10-15",
+ "preferredHairdresser": "Nina K.",
+ "createdAt": "2024-05-01",
+ "tags": ["sensitiv"],
+ "avatarColor": null
+ },
+ {
+ "id": "louise-hansen",
+ "firstName": "Louise",
+ "lastName": "Hansen",
+ "initials": "LH",
+ "phone": "+45 33 44 55 66",
+ "email": "louise.h@gmail.com",
+ "visits": 18,
+ "lastVisit": "2025-11-10",
+ "preferredHairdresser": "Emma L.",
+ "createdAt": "2023-02-01",
+ "tags": ["stamkunde"],
+ "avatarColor": "purple"
+ },
+ {
+ "id": "maja-petersen",
+ "firstName": "Maja",
+ "lastName": "Petersen",
+ "initials": "MP",
+ "phone": "+45 98 76 54 32",
+ "email": "maja.p@mail.dk",
+ "visits": 22,
+ "lastVisit": "2025-12-01",
+ "preferredHairdresser": "Emma L.",
+ "createdAt": "2023-01-01",
+ "tags": ["stamkunde"],
+ "avatarColor": "blue"
+ },
+ {
+ "id": "maria-olsen",
+ "firstName": "Maria",
+ "lastName": "Olsen",
+ "initials": "MO",
+ "phone": "+45 44 55 66 77",
+ "email": "maria.o@mail.dk",
+ "visits": 2,
+ "lastVisit": "2025-11-05",
+ "preferredHairdresser": "Sofie M.",
+ "createdAt": "2025-11-01",
+ "tags": ["ny"],
+ "avatarColor": "amber"
+ },
+ {
+ "id": "rikke-skov",
+ "firstName": "Rikke",
+ "lastName": "Skov",
+ "initials": "RS",
+ "phone": "+45 77 88 99 00",
+ "email": "rikke.s@gmail.com",
+ "visits": 4,
+ "lastVisit": "2025-10-20",
+ "preferredHairdresser": "Sofie M.",
+ "createdAt": "2025-08-01",
+ "tags": [],
+ "avatarColor": null
+ },
+ {
+ "id": "sofie-nielsen",
+ "firstName": "Sofie",
+ "lastName": "Nielsen",
+ "initials": "SN",
+ "phone": "+45 23 45 67 89",
+ "email": "sofie@email.dk",
+ "visits": 14,
+ "lastVisit": "2025-12-09",
+ "preferredHairdresser": "Emma L.",
+ "createdAt": "2024-03-01",
+ "tags": ["vip"],
+ "avatarColor": null
+ }
+ ]
+}
diff --git a/PlanTempus.Application/Features/Customers/Pages/Index.cshtml b/PlanTempus.Application/Features/Customers/Pages/Index.cshtml
index cf3787e..2122810 100644
--- a/PlanTempus.Application/Features/Customers/Pages/Index.cshtml
+++ b/PlanTempus.Application/Features/Customers/Pages/Index.cshtml
@@ -31,288 +31,7 @@
-
-
-
-
-
-
-
-
- Eksporter
-
-
-
- Ny kunde
-
-
-
-
-
-
-
-
- Navn
- Telefon
- Email
- Besøg
- Sidste
- Frisør
- Oprettet
- Tags
-
-
-
-
-
-
-
-
-
- AJ
- Anna Jensen
-
- +45 22 33 44 55
- anna.j@hotmail.dk
- 6
- 15. nov
- Nina K.
- Sep 2024
-
-
-
-
-
-
-
-
-
-
- CH
- Camilla Holm
-
- +45 66 77 88 99
- camilla.h@outlook.dk
- 25
- 28. okt
- Emma L.
- Dec 2022
-
- VIP
-
-
-
-
-
-
-
-
-
-
- EL
- Emma Larsen
-
- +45 12 34 56 78
- emma.l@gmail.com
- 8
- 5. dec
- Nina K.
- Jun 2024
-
-
-
-
-
-
-
-
-
-
- FC
- Freja Christensen
-
- +45 55 66 77 88
- freja.c@outlook.dk
- 31
- 20. nov
- Emma L.
- Aug 2022
-
- VIP
- Allergi
-
-
-
-
-
-
-
-
-
-
- IA
- Ida Andersen
-
- +45 11 22 33 44
- ida@firma.dk
- 3
- 28. nov
- Sofie M.
- Okt 2025
-
- Ny
-
-
-
-
-
-
-
-
-
-
- KB
- Katrine Berg
-
- +45 55 66 77 88
- katrine.b@firma.dk
- 12
- 1. nov
- Nina K.
- Apr 2024
-
-
-
-
-
-
-
-
-
-
- LF
- Line Frost
-
- +45 88 99 00 11
- line.f@mail.dk
- 9
- 15. okt
- Nina K.
- Maj 2024
-
- Sensitiv
-
-
-
-
-
-
-
-
-
-
- LH
- Louise Hansen
-
- +45 33 44 55 66
- louise.h@gmail.com
- 18
- 10. nov
- Emma L.
- Feb 2023
-
- Stamkunde
-
-
-
-
-
-
-
-
-
-
- MP
- Maja Petersen
-
- +45 98 76 54 32
- maja.p@mail.dk
- 22
- 1. dec
- Emma L.
- Jan 2023
-
- Stamkunde
-
-
-
-
-
-
-
-
-
-
- MO
- Maria Olsen
-
- +45 44 55 66 77
- maria.o@mail.dk
- 2
- 5. nov
- Sofie M.
- Nov 2025
-
- Ny
-
-
-
-
-
-
-
-
-
-
- RS
- Rikke Skov
-
- +45 77 88 99 00
- rikke.s@gmail.com
- 4
- 20. okt
- Sofie M.
- Aug 2025
-
-
-
-
-
-
-
-
-
-
- SN
- Sofie Nielsen
-
- +45 23 45 67 89
- sofie@email.dk
- 14
- 9. dec
- Emma L.
- Mar 2024
-
- VIP
-
-
-
-
-
-
- Ingen kunder matcher din søgning
-
-
+ @await Component.InvokeAsync("CustomerTable")
diff --git a/PlanTempus.Application/Features/Localization/Translations/da.json b/PlanTempus.Application/Features/Localization/Translations/da.json
index eea1fb3..b310564 100644
--- a/PlanTempus.Application/Features/Localization/Translations/da.json
+++ b/PlanTempus.Application/Features/Localization/Translations/da.json
@@ -562,5 +562,54 @@
"dailysummary": "Email med daglig oversigt"
}
}
+ },
+ "customers": {
+ "title": "Kunder",
+ "subtitle": "Administrer kunder og kundekort",
+ "searchPlaceholder": "Søg kunde (navn, telefon, email...)",
+ "export": "Eksporter",
+ "create": "Ny kunde",
+ "emptySearch": "Ingen kunder matcher din søgning",
+ "column": {
+ "name": "Navn",
+ "phone": "Telefon",
+ "email": "Email",
+ "visits": "Besøg",
+ "lastVisit": "Sidste",
+ "hairdresser": "Frisør",
+ "created": "Oprettet",
+ "tags": "Tags"
+ },
+ "stats": {
+ "total": "Total kunder",
+ "newThisMonth": "Nye denne måned",
+ "avgVisits": "Gns. besøg"
+ },
+ "drawer": {
+ "title": "Kundekort",
+ "visits": "Besøg",
+ "avgInterval": "Gns. interval",
+ "preferredHairdresser": "Foretrukken frisør",
+ "contactInfo": "Kontaktoplysninger",
+ "phone": "Telefon",
+ "email": "Email",
+ "address": "Adresse",
+ "zipCity": "Postnr + By",
+ "marketing": "Marketing",
+ "emailMarketing": "Email marketing",
+ "smsMarketing": "SMS marketing",
+ "profile": "Profil",
+ "hairType": "Hårtype",
+ "porosity": "Porøsitet",
+ "preference": "Præference",
+ "warnings": "Advarsler",
+ "revenueChart": "Omsætning (sidste 6 mdr)",
+ "services": "Services",
+ "products": "Produkter",
+ "recentNotes": "Seneste noter",
+ "noteType": "Note",
+ "colorFormula": "Farveformel",
+ "seeAllNotes": "Se alle noter →"
+ }
}
}
diff --git a/PlanTempus.Application/Features/Services/Components/ServiceDetailPrices/Default.cshtml b/PlanTempus.Application/Features/Services/Components/ServiceDetailPrices/Default.cshtml
index 8ed8e70..d9b63b0 100644
--- a/PlanTempus.Application/Features/Services/Components/ServiceDetailPrices/Default.cshtml
+++ b/PlanTempus.Application/Features/Services/Components/ServiceDetailPrices/Default.cshtml
@@ -1,117 +1,124 @@
@model PlanTempus.Application.Features.Services.Components.ServiceDetailPricesViewModel
-
-
- @Model.LabelPriceStructure
-
-
- @Model.LabelSimplePrice
- @Model.LabelMatrixPrice
-
-
-
-
-
-
- @Model.LabelPrice
- @Model.SimplePrice
-
-
-
-
-
-
-
-
- @Model.LabelLevel
- @Model.LabelShortHair
- @Model.LabelMediumHair
- @Model.LabelLongHair
- @Model.LabelExtraLongHair
-
- @foreach (var row in Model.PriceMatrix)
- {
-
- @row.Level
- @row.ShortHair kr
- @row.MediumHair kr
- @row.LongHair kr
- @row.ExtraLongHair kr
-
- }
-
-
-
-
- @Model.LabelAddLevel
-
-
-
-
-
-
- @Model.LabelEconomy
-
-
-
- @Model.LabelVatRate
-
-
-
- 25% (standard)
- 0% (momsfri)
-
-
-
-
- @Model.LabelProductCost
- @Model.ProductCost
-
-
- @Model.LabelCommission
-
-
-
- Standard (fra lønsats)
- Fast beløb
- Procent af pris
-
-
-
-
-
+
+
+
+
+ @Model.LabelEconomy
+
+
+
+ @Model.LabelVatRate
+
+
+
+ 25% (standard)
+ 0% (momsfri)
+
+
+
+
+ @Model.LabelProductCost
+ @Model.ProductCost
+
+
+ @Model.LabelCommission
+
+
+
+ Standard (fra lønsats)
+ Fast beløb
+ Procent af pris
+
+
+
+
+
+
-
+
+
+
+
+ @Model.LabelDiscounts
+
+
+ @Model.LabelMemberDiscount
+
+ @Model.ToggleYes
+ @Model.ToggleNo
+
+
+
+ @Model.LabelGiftCardPayment
+
+ @Model.ToggleYes
+ @Model.ToggleNo
+
+
+
+ @Model.LabelLoyaltyPoints
+
+ @Model.ToggleYes
+ @Model.ToggleNo
+
+
+
+
+
+
+
- @Model.LabelDiscounts
+ @Model.LabelPriceStructure
-
- @Model.LabelMemberDiscount
-
- @Model.ToggleYes
- @Model.ToggleNo
-
-
-
- @Model.LabelGiftCardPayment
-
- @Model.ToggleYes
- @Model.ToggleNo
-
-
-
- @Model.LabelLoyaltyPoints
-
- @Model.ToggleYes
- @Model.ToggleNo
-
-
+
+ @Model.LabelSimplePrice
+ @Model.LabelMatrixPrice
+
+
+
+
+
+
+ @Model.LabelPrice
+ @Model.SimplePrice
+
+
+
+
+
+
+
+
+ @Model.LabelLevel
+ @Model.LabelShortHair
+ @Model.LabelMediumHair
+ @Model.LabelLongHair
+ @Model.LabelExtraLongHair
+
+ @foreach (var row in Model.PriceMatrix)
+ {
+
+ @row.Level
+ @row.ShortHair kr
+ @row.MediumHair kr
+ @row.LongHair kr
+ @row.ExtraLongHair kr
+
+ }
+
+
+
+
+ @Model.LabelAddLevel
+
+
diff --git a/PlanTempus.Application/Features/Settings/Components/SettingsModules/Default.cshtml b/PlanTempus.Application/Features/Settings/Components/SettingsModules/Default.cshtml
index 9cdc418..b36f60f 100644
--- a/PlanTempus.Application/Features/Settings/Components/SettingsModules/Default.cshtml
+++ b/PlanTempus.Application/Features/Settings/Components/SettingsModules/Default.cshtml
@@ -7,25 +7,75 @@
-
+
-
- Løn & Økonomi
+
+ Tillægsmoduler
-
+
+
+
+
+ Online Booking
+ Lad kunder booke tider online via din egen bookingside. Integreres med kalender og påmindelser.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+ Inkluderet
+
+ Indstillinger
+
+
+
+
+
+
+
+
+
+
+ Gavekort
+ Sælg og administrer digitale gavekort. Kunderne kan købe online eller i butikken, og indløse ved betaling.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+ Inkluderet
+
+ Indstillinger
+
+
+
+
+
+
+
- Lønberegning
- Beregn løn, overtid, provision og ferie automatisk. Grundmodul for løneksport til eksterne systemer.
+ Kasseafstemning
+ Daglig kasseopgørelse og afstemning. Hold styr på kontanter, kort og andre betalingsmetoder.
@@ -42,15 +92,15 @@
-
+
-
-
+
+
- Intect
- Eksporter direkte til Intect lønsystem i StandardMapping-format.
+ Stregkodescanner
+ Scan EAN-koder og få AI-genererede produktbeskrivelser automatisk. Opret nye produkter på sekunder.
@@ -62,92 +112,21 @@
Inkluderet
+ AI
Indstillinger
-
-
-
-
-
-
-
- Proløn
- Eksporter direkte til Proløn lønsystem.
-
-
-
- Til
- Fra
-
-
-
-
-
- Kommer
-
-
-
-
-
-
-
-
-
-
-
- Danløn
- Eksporter direkte til Danløn lønsystem.
-
-
-
- Til
- Fra
-
-
-
-
-
- Kommer
-
-
-
-
-
-
-
-
-
-
-
- Salary.dk
- Eksporter direkte til Salary.dk lønsystem.
-
-
-
- Til
- Fra
-
-
-
-
-
- Kommer
-
-
-
-
-
+
-
+
- Zenegy
- Eksporter direkte til Zenegy lønsystem. Automatisk overførsel af timer og provision.
+ Website Builder
+ Byg din salons hjemmeside med drag-and-drop blokke. Vælg mellem færdige designs, tilpas farver og fonte, og integrer din booking.
@@ -158,8 +137,53 @@
- Kommer
+ +149 kr/md
+ Ny
+ Åbn Builder
+
+
+
+
+
+
+
+
+
+
+ HR & Dokumenter
+ Komplet medarbejderstyring med alle de værktøjer du behøver for at holde styr på dit team.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+
+ Kontrakter med udløbspåmindelser
+
+
+
+ Certificeringer og kursusstyring
+
+
+
+ Ferie-saldo, sygefravær og barsel
+
+
+
+ Dokumenter gemmes på dit eget Google Drive eller OneDrive
+
+
+
+
+ Inkluderet
+
+ Indstillinger
@@ -345,170 +369,6 @@
-
-
-
-
-
- Tillægsmoduler
-
-
-
-
-
-
-
-
-
-
-
- Online Booking
- Lad kunder booke tider online via din egen bookingside. Integreres med kalender og påmindelser.
-
-
-
- Til
- Fra
-
-
-
-
-
- Inkluderet
-
- Indstillinger
-
-
-
-
-
-
-
-
-
-
- Gavekort
- Sælg og administrer digitale gavekort. Kunderne kan købe online eller i butikken, og indløse ved betaling.
-
-
-
- Til
- Fra
-
-
-
-
-
- Inkluderet
-
- Indstillinger
-
-
-
-
-
-
-
-
-
-
- Kasseafstemning
- Daglig kasseopgørelse og afstemning. Hold styr på kontanter, kort og andre betalingsmetoder.
-
-
-
- Til
- Fra
-
-
-
-
-
- Inkluderet
-
- Indstillinger
-
-
-
-
-
-
-
-
-
-
- Stregkodescanner
- Scan EAN-koder og få AI-genererede produktbeskrivelser automatisk. Opret nye produkter på sekunder.
-
-
-
- Til
- Fra
-
-
-
-
-
- Inkluderet
- AI
-
- Indstillinger
-
-
-
-
-
-
-
-
-
-
- Website Builder
- Byg din salons hjemmeside med drag-and-drop blokke. Vælg mellem færdige designs, tilpas farver og fonte, og integrer din booking.
-
-
-
- Til
- Fra
-
-
-
-
-
- +149 kr/md
- Ny
-
- Åbn Builder
-
-
-
-
-
-
-
-
-
-
- HR & Dokumenter
- Komplet medarbejderstyring: Kontrakter, certificeringer, kurser, ferie-saldo, sygefravær og barsel. Upload dokumenter og få påmindelser om udløbsdatoer.
-
-
-
- Til
- Fra
-
-
-
-
-
- Inkluderet
-
- Indstillinger
-
-
-
-
-
@@ -602,3 +462,161 @@
+
+
+
+
+
+
+ Løn & Økonomi
+
+
+
+
+
+
+
+
+
+
+
+ Lønberegning
+ Beregn løn, overtid, provision og ferie automatisk. Grundmodul for løneksport til eksterne systemer.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+ Inkluderet
+
+ Indstillinger
+
+
+
+
+
+
+
+
+
+
+ Intect
+ Eksporter direkte til Intect lønsystem i StandardMapping-format.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+ Inkluderet
+
+ Indstillinger
+
+
+
+
+
+
+
+
+
+
+ Proløn
+ Eksporter direkte til Proløn lønsystem.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+ Kommer
+
+
+
+
+
+
+
+
+
+
+
+ Danløn
+ Eksporter direkte til Danløn lønsystem.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+ Kommer
+
+
+
+
+
+
+
+
+
+
+
+ Salary.dk
+ Eksporter direkte til Salary.dk lønsystem.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+ Kommer
+
+
+
+
+
+
+
+
+
+
+
+ Zenegy
+ Eksporter direkte til Zenegy lønsystem. Automatisk overførsel af timer og provision.
+
+
+
+ Til
+ Fra
+
+
+
+
+
+ Kommer
+
+
+
+
+
diff --git a/PlanTempus.Application/wwwroot/css/customers.css b/PlanTempus.Application/wwwroot/css/customers.css
index a2591d8..a1d7b70 100644
--- a/PlanTempus.Application/wwwroot/css/customers.css
+++ b/PlanTempus.Application/wwwroot/css/customers.css
@@ -18,9 +18,9 @@ swp-card.customers-list {
overflow: hidden;
}
-/* Table columns: QuickView(40px) | Navn(1fr) | Tlf(120px) | Email(180px) | Besøg(70px) | Sidste(90px) | Frisør(100px) | Oprettet(90px) | Tags(140px) */
+/* Table columns: Navn(1fr) | Tlf(120px) | Email(180px) | Besøg(70px) | Sidste(90px) | Frisør(100px) | Oprettet(90px) | Tags(140px) */
swp-card.customers-list swp-data-table {
- grid-template-columns: 40px minmax(200px, 1fr) 120px 180px 70px 90px 100px 90px 140px;
+ grid-template-columns: minmax(200px, 1fr) 120px 180px 70px 90px 100px 90px 140px;
}
swp-card.customers-list swp-data-table-header,
@@ -41,29 +41,22 @@ swp-card.customers-list swp-data-table-cell {
padding: var(--spacing-5) 0;
}
-/* Quick-view cell (first column) */
+/* Name cell with avatar and quick-view button */
swp-card.customers-list swp-data-table-cell:first-child {
display: flex;
align-items: center;
- justify-content: center;
+ gap: var(--spacing-3);
}
-/* Name cell with avatar (second column) */
-swp-card.customers-list swp-data-table-cell:nth-child(2) {
- display: flex;
- align-items: center;
- gap: var(--spacing-4);
-}
-
-/* Mono font for visits column (fifth column) */
-swp-card.customers-list swp-data-table-row swp-data-table-cell:nth-child(5) {
+/* Mono font for visits column */
+swp-card.customers-list swp-data-table-row swp-data-table-cell:nth-child(4) {
font-family: var(--font-mono);
text-align: center;
}
-/* Muted text for email and created columns (4th and 8th) */
-swp-card.customers-list swp-data-table-row swp-data-table-cell:nth-child(4),
-swp-card.customers-list swp-data-table-row swp-data-table-cell:nth-child(8) {
+/* Muted text for email and created columns */
+swp-card.customers-list swp-data-table-row swp-data-table-cell:nth-child(3),
+swp-card.customers-list swp-data-table-row swp-data-table-cell:nth-child(7) {
color: var(--color-text-secondary);
}
diff --git a/PlanTempus.Application/wwwroot/css/settings.css b/PlanTempus.Application/wwwroot/css/settings.css
index 7e6437d..3e3d892 100644
--- a/PlanTempus.Application/wwwroot/css/settings.css
+++ b/PlanTempus.Application/wwwroot/css/settings.css
@@ -233,7 +233,7 @@ swp-modules-badge {
display: inline-flex;
align-items: center;
padding: var(--spacing-1) var(--spacing-3);
- font-size: var(--font-size-xs);
+ font-size: var(--font-size-sm);
font-weight: var(--font-weight-semibold);
border-radius: var(--radius-sm);
background: var(--bg-purple-strong);
@@ -251,14 +251,17 @@ swp-modules-header {
display: flex;
align-items: center;
justify-content: space-between;
+ margin-top: var(--spacing-24);
margin-bottom: var(--spacing-5);
+ padding-top: var(--spacing-12);
+ border-top: 1px solid var(--color-border);
}
swp-modules-title {
display: flex;
align-items: center;
gap: var(--spacing-3);
- font-size: var(--font-size-lg);
+ font-size: var(--font-size-xl);
font-weight: var(--font-weight-semibold);
color: var(--color-text);
@@ -303,9 +306,9 @@ swp-module-card {
swp-module-header {
display: flex;
- align-items: center;
+ align-items: flex-start;
gap: var(--spacing-5);
- padding: var(--card-padding);
+ padding: var(--spacing-6);
}
swp-module-icon {
@@ -350,21 +353,23 @@ swp-module-icon {
swp-module-info {
flex: 1;
min-width: 0;
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-2);
}
swp-module-title {
display: block;
- font-size: var(--font-size-md);
+ font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
color: var(--color-text);
- margin-bottom: var(--spacing-1);
}
swp-module-desc {
display: block;
- font-size: var(--font-size-sm);
+ font-size: var(--font-size-md);
color: var(--color-text-secondary);
- line-height: 1.4;
+ line-height: 1.6;
}
swp-module-toggle {
@@ -390,7 +395,7 @@ swp-module-tag {
display: inline-flex;
align-items: center;
padding: var(--spacing-1) var(--spacing-3);
- font-size: var(--font-size-xs);
+ font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
border-radius: var(--radius-sm);
background: var(--color-background);
@@ -440,8 +445,8 @@ swp-module-card.featured {
swp-module-features {
display: flex;
- flex-wrap: wrap;
- gap: var(--spacing-2) var(--spacing-5);
+ flex-direction: column;
+ gap: var(--spacing-2);
padding: 0 var(--card-padding) var(--spacing-5);
}
@@ -449,7 +454,7 @@ swp-module-feature {
display: flex;
align-items: center;
gap: var(--spacing-2);
- font-size: var(--font-size-sm);
+ font-size: var(--font-size-md);
color: var(--color-text-secondary);
& i {
@@ -487,7 +492,7 @@ swp-module-stat {
swp-module-stat-value {
display: block;
- font-size: var(--font-size-xl);
+ font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
font-family: var(--font-mono);
color: var(--color-green);
@@ -495,7 +500,7 @@ swp-module-stat-value {
swp-module-stat-label {
display: block;
- font-size: var(--font-size-xs);
+ font-size: var(--font-size-sm);
color: var(--color-text-secondary);
margin-top: var(--spacing-1);
}
@@ -530,8 +535,9 @@ swp-tracking-hint {
/* Modules tab max-width */
swp-tab-content[data-tab="modules"] swp-page-container {
- max-width: 900px;
+ max-width: 1100px;
margin: 0 auto;
+ padding-bottom: var(--spacing-16);
}
/* Tracking tab uses 2-column grid layout */
@@ -539,7 +545,7 @@ swp-tab-content[data-tab="tracking"] swp-page-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
- max-width: 900px;
+ max-width: 1100px;
margin: 0 auto;
}