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) + } + + + + 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 - - - - - - + @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; }