From 6b0a84a07e53ba015e9e6b8d614203e52a5f0475 Mon Sep 17 00:00:00 2001 From: "Janus C. H. Knudsen" Date: Mon, 19 Jan 2026 23:27:18 +0100 Subject: [PATCH] Adds comprehensive customer detail page with dynamic features Develops detailed customer profile view with multiple sections including overview, statistics, journal, appointments, and activity tracking Implements interactive UI components for customer management Includes dynamic tab switching, editable profile sections, and activity timeline --- .../Features/Customers/Pages/Detail.cshtml | 898 ++++++++++++++ .../Features/Customers/Pages/Detail.cshtml.cs | 14 + .../Features/Customers/Pages/Index.cshtml | 34 +- .../wwwroot/css/COMPONENT-CATALOG.md | 20 +- .../wwwroot/css/components.css | 5 + .../wwwroot/css/customers.css | 1052 +++++++++++++++++ 6 files changed, 2015 insertions(+), 8 deletions(-) create mode 100644 PlanTempus.Application/Features/Customers/Pages/Detail.cshtml create mode 100644 PlanTempus.Application/Features/Customers/Pages/Detail.cshtml.cs diff --git a/PlanTempus.Application/Features/Customers/Pages/Detail.cshtml b/PlanTempus.Application/Features/Customers/Pages/Detail.cshtml new file mode 100644 index 0000000..4ef9731 --- /dev/null +++ b/PlanTempus.Application/Features/Customers/Pages/Detail.cshtml @@ -0,0 +1,898 @@ +@page "/kunder/{id}" +@model PlanTempus.Application.Features.Customers.Pages.DetailModel +@{ + ViewData["Title"] = "Kundedetaljer - Sofie Nielsen"; +} + + + + + + + Tilbage til kunder + + + + + Slet kunde + + + + Gem + + + + + + SN + + + Sofie Nielsen + + VIP + + + + Booking tilladt + + + + +45 23 45 67 89 + | + sofie@email.dk + | + Kunde siden marts 2024 + + + + 14 + besog + + + 32 + dage interval + + + Emma L. + foretrukken frisor + + + 12.450 kr + total omsaetning + + + + + + + + Oversigt + Økonomi + Statistik + Journal + Aftaler + Gavekort + Aktivitet + + + + + + + + + + + + + + + Kontaktoplysninger + + + + + Telefon + +45 23 45 67 89 + + + Email + sofie@email.dk + + + Adresse + Hovedgaden 12 + + + Postnr + By + 2100 København Ø + + + + + + + + + + Profil + + + + + Hårtype + Medium - Bolget + + + Porøsitet + Medium + + + Hovedbund + Normal + + + Naturlig farve + Mørkblond (6) + + + + + + + + + + + + + Marketing + + + + Email marketing + + Ja + Nej + + + + SMS marketing + + Ja + Nej + + + + + + + + + + Betalingsindstillinger + + + + + Kræv forudbetaling + Kunden skal betale fuldt belob ved booking + + + Ja + Nej + + + + + Tillad delvis betaling + Kunden kan vaelge at betale et depositum + + + Ja + Nej + + + + + + + + + + Præferencer + + + + + Foretrukken frisor + Emma L. + + + Foretrukken dag + Tirsdag/Torsdag + + + Specielle onsker + Foretraekker kold tone, ikke for mork + + + + + + + + + + Advarsler + + + + + Allergier / Følsomhed + Parfumeallergi - brug uparfumerede produkter + + + + + + + + + + Kundegruppe & Relationer + + + + Kundegruppe: + + + + Standard + Premium + Erhverv + Medarbejder + Familie & Venner + + + + + + + EN + + Emil Nielsen + Barn + + + Åbn + × + + + + + LN + + Luna Nielsen + Barn + + + Åbn + × + + + + + + Tilføj relation + + + + + + + + + + + + + + Økonomi tab - kommer snart + + + + + + + + + + + Fremmøde & Pålidelighed + +
+ + 47 + Fremmøder + + + 3 + Aflysninger + + + 1 + No-shows + + + 92% + Pålidelighed + +
+ + 47 + 3 + 1 + +
+ + + + + + + Service-mønstre + +
+
+ Top 3 Services + + + 1 + Klip + Farve + 12× + + + 2 + Farve + + + + 3 + Klip + + + +
+
+ Top 3 Produkter + + + 1 + Olaplex No. 3 + + + + 2 + Shampoo + + + + 3 + Hårkur + + + +
+
+
+
+ + + + + + + Booking-adfærd + + + + Gns. bookingvarsel + 5 dage + + + Foretrukken dag + Tirsdag + + + Foretrukken tid + 10:00 - 12:00 + + + Online booking rate + 78% + + + Gns. aflysningsvarsel + 2 dage + + + + + + + + Loyalitet + +
+ + 1,8 år + Kunde siden + + + 13 + Dage siden sidst + + + + + + Lav + + + Churn-risiko + + + 32 dage + Gns. interval + +
+
+
+
+
+
+ + + + + + + + Alle + 5 + + + + Noter + 2 + + + + Farveformler + 2 + + + + Analyser + 1 + + + + + + + + + + + + Noter + + + Tilføj note + + + + Note + + + + Kunden foretrækker naturlige farver og ønsker lidt ekstra tid til konsultation. Husk at tjekke allergistatus inden farvebehandling. + + + 9. dec 2025 · Af: Emma + + + Alle + + + + + + + + + + Advarsel + + Allergi + + + + + PARFUMEALLERGI — Brug kun uparfumerede produkter. Havde reaktion på standard shampoo ved første besøg. + + + 15. mar 2024 · Af: Nina + + + Advarsel + + + + + + + + + + + Farveformler + + + Tilføj + + + + Farveformel + + + + Måltone: Kold
+ Oxidant: 6%
+ Formel: 7/1 + 7/0 (1:1)
+ Virketid: 35 min
+ Placering: Hele håret

+ Resultat: Flot ensartet farve, kunden meget tilfreds +
+ + 12. nov 2025 · Af: Emma + +
+
+
+ + + + + + + + + Analyser + + + Tilføj + + + + Håranalyse + + + + Tilstand: God, let tørt i spidserne
+ Porøsitet: Medium
+ Elasticitet: Normal

+ Anbefaling: Olaplex behandling hver 6. uge +
+ + 1. okt 2025 · Af: Maria + +
+
+
+
+
+
+ + + + + + + + + + Kommende aftaler + + + + Tirsdag 14. januar 2026 kl. 10:00 + + + Klip + Farve · Emma L. · 2 timer + + + Flyt + Aflys + + + + + + + + + + + Tidligere aftaler + + + + Dato + Service + Frisør + Varighed + Pris + + + 9. dec 2025 + Klip + Farve + Emma L. + 2 timer + 1.450 kr + + + 12. nov 2025 + Farve + Emma L. + 1t 30m + 1.200 kr + + + 15. okt 2025 + Klip + Emma L. + 45 min + 550 kr + + + 20. sep 2025 + Klip + Behandling + Nina K. + 1t 15m + 750 kr + + + 15. aug 2025 + Farve + Klip + Emma L. + 2t 15m + 1.600 kr + + + Se alle aftaler → + + + + + + + + + + + + + + + Aktive gavekort + + + + Gavekort #GK-2024-0892 + + + Saldo: 350 kr (af 500 kr) + + + + + Udløber: 15. marts 2026 + + + + + + + Klippekort + + + + 10-klip kort + + + Brugt: 7 af 10 klip + + + + + Udløber aldrig + + + + + + + + + + Udløbne / Brugte + + +

Ingen udløbne eller brugte kort

+
+
+
+
+
+
+ + + + + + Alle + Bookinger + Kommunikation + Ændringer + Betalinger + Login + + + + + + + I dag + + + + + + SMS påmindelse sendt om aftale i morgen + Auto + + + 14:00 + System + + + + + + + + + Kunde loggede ind via online booking + Online + + + 09:15 + + + + + + + + 9. december 2025 + + + + + + Booking gennemført + + + 12:30 + Farve + Behandling · Emma L. + + + + + + + + + Note tilføjet — Farveformel opdateret + + + 12:45 + Emma L. + + + + + + + + 15. november 2025 + + + + + + Allergi registreret — Parfumeallergi tilføjet til profil + + + 10:00 + Nina K. + + + + + + + + 1. marts 2024 + + + + + + Kunde oprettet via online booking + + + 14:22 + System + + + + + + + + + +@section Scripts { + +} diff --git a/PlanTempus.Application/Features/Customers/Pages/Detail.cshtml.cs b/PlanTempus.Application/Features/Customers/Pages/Detail.cshtml.cs new file mode 100644 index 0000000..26aa752 --- /dev/null +++ b/PlanTempus.Application/Features/Customers/Pages/Detail.cshtml.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace PlanTempus.Application.Features.Customers.Pages; + +public class DetailModel : PageModel +{ + [BindProperty(SupportsGet = true)] + public string Id { get; set; } = string.Empty; + + public void OnGet() + { + } +} diff --git a/PlanTempus.Application/Features/Customers/Pages/Index.cshtml b/PlanTempus.Application/Features/Customers/Pages/Index.cshtml index ba4a96c..8b75e69 100644 --- a/PlanTempus.Application/Features/Customers/Pages/Index.cshtml +++ b/PlanTempus.Application/Features/Customers/Pages/Index.cshtml @@ -255,15 +255,21 @@ -
+
Kundekort - - - + + + + Åbn fuld side + + + + + @@ -410,3 +416,23 @@
+ +@section Scripts { + +} diff --git a/PlanTempus.Application/wwwroot/css/COMPONENT-CATALOG.md b/PlanTempus.Application/wwwroot/css/COMPONENT-CATALOG.md index 2f3d4e7..47a5727 100644 --- a/PlanTempus.Application/wwwroot/css/COMPONENT-CATALOG.md +++ b/PlanTempus.Application/wwwroot/css/COMPONENT-CATALOG.md @@ -78,16 +78,26 @@ Standard icon wrapper (40×40px cirkel): | `swp-card-header` | Card header wrapper | Flex, space-between, border-bottom | | `swp-card-title` | Card title med ikon | Flex, icon + text | | `swp-section-action` | Action link i header | Teal, clickable | -| `swp-section-label` | Subsection label (inde i card) | Uppercase, 11px, border-bottom | +| `swp-section-label` | Subsection label (KUN til sekundære sektioner inde i card, ALDRIG som card header) | Uppercase, 11px, border-bottom | | `swp-card-content` | Card indhold | Block | ### Card Header Eksempler -**Standard card header (ANBEFALET):** +**VIGTIGT:** Brug ALTID `swp-card-header` + `swp-card-title` som første element i et card. + +❌ **FORKERT - brug IKKE `swp-section-label` som card header:** +```html + + Kontaktoplysninger + + +``` + +✅ **KORREKT - brug `swp-card-header` + `swp-card-title`:** ```html - Kontakter + Kontaktoplysninger @@ -117,7 +127,7 @@ Standard icon wrapper (40×40px cirkel): ``` -**Subsection label (inde i card):** +**Subsection label (KUN til sekundære sektioner inde i card):** ```html @@ -130,6 +140,8 @@ Standard icon wrapper (40×40px cirkel): ``` +**HUSK:** `swp-section-label` må ALDRIG bruges som erstatning for `swp-card-header`! + --- ## Stats Components (stats.css) diff --git a/PlanTempus.Application/wwwroot/css/components.css b/PlanTempus.Application/wwwroot/css/components.css index c64415c..321f803 100644 --- a/PlanTempus.Application/wwwroot/css/components.css +++ b/PlanTempus.Application/wwwroot/css/components.css @@ -1353,6 +1353,11 @@ swp-detail-grid { grid-template-columns: repeat(2, 1fr); gap: var(--card-gap); align-items: start; + + /* Full width cards span both columns */ + & > .full-width { + grid-column: 1 / -1; + } } /* =========================================== diff --git a/PlanTempus.Application/wwwroot/css/customers.css b/PlanTempus.Application/wwwroot/css/customers.css index 1609c05..4eb5733 100644 --- a/PlanTempus.Application/wwwroot/css/customers.css +++ b/PlanTempus.Application/wwwroot/css/customers.css @@ -73,6 +73,34 @@ swp-card.customers-list swp-data-table-cell:last-child { swp-edit-section/row (components.css), swp-toggle-row/slider (controls.css) =========================================== */ +/* Drawer header actions */ +swp-drawer-actions { + display: flex; + align-items: center; + gap: var(--spacing-4); +} + +.drawer-detail-link { + display: inline-flex; + align-items: center; + gap: var(--spacing-2); + padding: var(--spacing-2) var(--spacing-4); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--color-teal); + text-decoration: none; + border-radius: var(--radius-md); + transition: all var(--transition-fast); + + &:hover { + background: var(--bg-teal-subtle); + } + + i { + font-size: var(--font-size-base); + } +} + /* Customer Header */ swp-customer-header { display: flex; @@ -337,3 +365,1027 @@ swp-edit-input { } } } + +/* =========================================== + CUSTOMER DETAIL PAGE + Reuses: swp-sticky-header, swp-header-content (page.css), + swp-tab-bar/swp-tab (tabs.css), swp-detail-grid (components.css) + =========================================== */ + +/* Customer Detail Header (inside swp-header-content) */ +swp-customer-detail-header { + display: flex; + gap: var(--spacing-6); + margin-top: var(--spacing-6); +} + +swp-customer-detail-header swp-customer-avatar-large { + width: 80px; + height: 80px; + border-radius: var(--radius-full); + background: linear-gradient(135deg, var(--color-teal) 0%, #00695c 100%); + color: white; + font-size: var(--font-size-3xl); + font-weight: var(--font-weight-semibold); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +swp-customer-detail-info { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--spacing-2); +} + +/* Name row with name, tags, and booking exclusion toggle */ +swp-customer-name-row { + display: flex; + align-items: center; + gap: var(--spacing-4); +} + +swp-customer-detail-name { + font-size: var(--font-size-2xl); + font-weight: var(--font-weight-semibold); + color: var(--color-text); +} + +swp-customer-detail-tags { + display: flex; + gap: var(--spacing-2); +} + +/* Booking exclusion toggle */ +swp-booking-exclusion { + display: inline-flex; + align-items: center; + gap: var(--spacing-2); + padding: var(--spacing-2) var(--spacing-4); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + border-radius: var(--radius-md); + cursor: pointer; + transition: all var(--transition-fast); + margin-left: auto; + + &[data-excluded="false"] { + background: var(--color-background); + color: var(--color-text-secondary); + border: 1px solid var(--color-border); + } + + &[data-excluded="true"] { + background: var(--bg-red-subtle); + color: var(--color-red); + border: 1px solid var(--border-red); + } + + .icon { + font-size: var(--font-size-base); + } +} + +/* Contact line with phone, email, customer since */ +swp-contact-line { + display: flex; + align-items: center; + gap: var(--spacing-4); + font-size: var(--font-size-sm); + color: var(--color-text-secondary); + + a { + color: var(--color-teal); + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + .separator { + color: var(--color-border); + } +} + +/* Customer Group Row (in card) */ +swp-customer-group-row { + display: flex; + align-items: center; + gap: var(--spacing-4); + margin-bottom: var(--spacing-4); + padding-bottom: var(--spacing-4); + border-bottom: 1px solid var(--color-border); +} + +swp-customer-group-label { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +/* Relations List */ +swp-relations-list { + display: flex; + flex-direction: column; + gap: var(--spacing-3); +} + +swp-relation-item { + display: flex; + align-items: center; + gap: var(--spacing-4); + padding: var(--spacing-3) var(--spacing-4); + background: var(--color-background-alt); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); +} + +swp-relation-avatar { + width: 36px; + height: 36px; + border-radius: var(--radius-full); + background: var(--color-purple); + color: white; + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); + flex-shrink: 0; +} + +swp-relation-info { + flex: 1; +} + +swp-relation-name { + display: block; + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + color: var(--color-text); +} + +swp-relation-type { + display: block; + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +swp-relation-actions { + display: flex; + gap: var(--spacing-3); +} + +swp-relation-link { + font-size: var(--font-size-sm); + color: var(--color-teal); + cursor: pointer; + + &:hover { + text-decoration: underline; + } +} + +swp-relation-remove { + font-size: var(--font-size-lg); + color: var(--color-text-secondary); + cursor: pointer; + opacity: 0.6; + + &:hover { + opacity: 1; + color: var(--color-red); + } +} + +swp-add-relation { + display: flex; + align-items: center; + gap: var(--spacing-2); + padding: var(--spacing-3) var(--spacing-4); + border: 1px dashed var(--color-border); + border-radius: var(--radius-md); + color: var(--color-text-secondary); + font-size: var(--font-size-sm); + cursor: pointer; + transition: all var(--transition-fast); + + &:hover { + border-color: var(--color-teal); + color: var(--color-teal); + } +} + +/* Toggle info wrapper (for toggles with description) */ +swp-toggle-info { + display: flex; + flex-direction: column; + gap: var(--spacing-1); +} + +swp-toggle-desc { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +/* Profile box full-width variant */ +swp-profile-box.full-width { + grid-column: span 2; +} + +/* =========================================== + CUSTOMER DETAIL - APPOINTMENTS TABLE + =========================================== */ +swp-card.customer-appointments { + padding: 0; + overflow: hidden; +} + +swp-card.customer-appointments swp-card-header { + padding: var(--spacing-6); +} + +swp-card.customer-appointments swp-data-table { + grid-template-columns: 80px 60px 1fr 100px 110px; +} + +/* =========================================== + CUSTOMER DETAIL - GIFTCARDS TABLE + =========================================== */ +swp-card.customer-giftcards { + padding: 0; + overflow: hidden; +} + +swp-card.customer-giftcards swp-card-header { + padding: var(--spacing-6); +} + +swp-card.customer-giftcards swp-data-table { + grid-template-columns: 140px 100px 80px 80px 100px; +} + +/* =========================================== + CUSTOMER DETAIL - ACTIVITY LIST + =========================================== */ +swp-card.customer-activity { + padding: 0; + overflow: hidden; +} + +swp-card.customer-activity swp-card-header { + padding: var(--spacing-6); + border-bottom: 1px solid var(--color-border); +} + +swp-card.customer-activity swp-attention-list { + display: grid; + grid-template-columns: 56px 1fr 100px; + padding: var(--spacing-4); + gap: var(--spacing-3); +} + +swp-card.customer-activity swp-attention-item { + border-radius: var(--radius-md); + padding: var(--spacing-4); +} + +swp-card.customer-activity swp-attention-action { + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); +} + +/* =========================================== + CUSTOMER DETAIL - JOURNAL NOTES + Override notes-section when inside a card + =========================================== */ +swp-card swp-notes-section { + margin-top: 0; + padding-top: 0; + border-top: none; + padding: var(--spacing-6); + padding-top: 0; +} + +/* Override chart-section when inside a card */ +swp-card swp-chart-section { + margin-top: 0; + padding-top: 0; + border-top: none; + padding: var(--spacing-6); + padding-top: 0; +} + +/* =========================================== + CUSTOMER DETAIL - STATISTICS TAB + =========================================== */ + +/* Grid helpers */ +.grid-4 { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--spacing-4); +} + +.grid-2 { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: var(--spacing-6); +} + +.grid-2.compact { + gap: var(--spacing-3); +} + +/* Stat card variants */ +swp-stat-card.warning swp-stat-value { + color: var(--color-amber); +} + +swp-stat-card.danger swp-stat-value { + color: var(--color-red); +} + +swp-stat-card.success swp-stat-value { + color: var(--color-green); +} + +swp-stat-value.small { + font-size: var(--font-size-xl); +} + +/* Key-Value List */ +swp-kv-list { + display: flex; + flex-direction: column; +} + +swp-kv-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--spacing-4) 0; + border-bottom: 1px solid var(--color-border); +} + +swp-kv-row:last-child { + border-bottom: none; +} + +swp-kv-label { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +swp-kv-value { + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + font-family: var(--font-mono); + color: var(--color-text); +} + +/* Attendance Bar */ +swp-attendance-bar { + display: flex; + height: 24px; + border-radius: var(--radius-md); + overflow: hidden; + margin-top: var(--spacing-4); +} + +swp-attendance-segment { + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + color: white; +} + +swp-attendance-segment.attended { + background: var(--color-teal); +} + +swp-attendance-segment.cancelled { + background: var(--color-amber); +} + +swp-attendance-segment.noshow { + background: var(--color-red); +} + +/* Top List */ +swp-top-list { + display: flex; + flex-direction: column; + gap: var(--spacing-3); +} + +swp-top-item { + display: flex; + align-items: center; + gap: var(--spacing-4); + font-size: var(--font-size-sm); +} + +swp-top-rank { + width: 24px; + height: 24px; + border-radius: var(--radius-full); + background: var(--color-background); + color: var(--color-text-secondary); + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + flex-shrink: 0; +} + +swp-top-item:first-child swp-top-rank { + background: var(--bg-teal-subtle); + color: var(--color-teal); +} + +swp-top-name { + flex: 1; + color: var(--color-text); +} + +swp-top-count { + font-family: var(--font-mono); + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +/* Risk Indicator */ +swp-risk-indicator { + display: inline-flex; + align-items: center; + gap: var(--spacing-2); +} + +swp-risk-indicator.low swp-risk-dot { + background: var(--color-green); +} + +swp-risk-indicator.low span { + color: var(--color-green); +} + +swp-risk-indicator.medium swp-risk-dot { + background: var(--color-amber); +} + +swp-risk-indicator.medium span { + color: var(--color-amber); +} + +swp-risk-indicator.high swp-risk-dot { + background: var(--color-red); +} + +swp-risk-indicator.high span { + color: var(--color-red); +} + +swp-risk-dot { + width: 8px; + height: 8px; + border-radius: var(--radius-full); +} + +/* Section label small variant */ +swp-section-label.small { + font-size: 10px; + margin-bottom: var(--spacing-3); +} + +/* =========================================== + CUSTOMER DETAIL - JOURNAL TAB + =========================================== */ + +/* Journal Mini Tabs (filter tabs) */ +swp-journal-mini-tabs { + display: flex; + gap: var(--spacing-2); + margin-bottom: var(--spacing-6); +} + +swp-journal-mini-tab { + display: inline-flex; + align-items: center; + gap: var(--spacing-2); + padding: var(--spacing-2) var(--spacing-4); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--color-text-secondary); + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + cursor: pointer; + transition: all var(--transition-fast); +} + +swp-journal-mini-tab:hover { + border-color: var(--color-teal); + color: var(--color-teal); +} + +swp-journal-mini-tab.active { + background: var(--bg-teal-subtle); + border-color: var(--color-teal); + color: var(--color-teal); +} + +.tab-dot { + width: 8px; + height: 8px; + border-radius: var(--radius-full); +} + +.tab-dot.blue { + background: var(--color-blue); +} + +.tab-dot.amber { + background: var(--color-amber); +} + +.tab-dot.purple { + background: var(--color-purple); +} + +.tab-count { + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); +} + +/* Journal Color Dots */ +.col-dot { + width: 10px; + height: 10px; + border-radius: var(--radius-full); +} + +.col-dot.blue { + background: var(--color-blue); +} + +.col-dot.amber { + background: var(--color-amber); +} + +.col-dot.purple { + background: var(--color-purple); +} + +/* Journal Entry Card */ +swp-journal-entry { + display: flex; + flex-direction: column; + gap: var(--spacing-3); + padding: var(--spacing-5); + background: var(--color-background-alt); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); +} + +swp-journal-entry-header { + display: flex; + align-items: center; + gap: var(--spacing-3); +} + +swp-journal-entry-type { + display: inline-flex; + padding: var(--spacing-1) var(--spacing-3); + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + text-transform: uppercase; + letter-spacing: 0.5px; + border-radius: var(--radius-sm); +} + +swp-journal-entry-type.note { + background: var(--bg-blue-subtle); + color: var(--color-blue); +} + +swp-journal-entry-type.advarsel { + background: var(--bg-red-subtle); + color: var(--color-red); +} + +swp-journal-entry-type.farveformel { + background: var(--bg-amber-subtle); + color: var(--color-amber); +} + +swp-journal-entry-type.analyse { + background: var(--bg-purple-subtle); + color: var(--color-purple); +} + +swp-journal-entry-tags { + display: flex; + gap: var(--spacing-2); +} + +swp-journal-tag { + display: inline-flex; + padding: var(--spacing-1) var(--spacing-2); + font-size: 10px; + font-weight: var(--font-weight-semibold); + text-transform: uppercase; + border-radius: var(--radius-sm); +} + +swp-journal-tag.allergi { + background: var(--bg-red-subtle); + color: var(--color-red); +} + +swp-journal-entry-delete { + margin-left: auto; + color: var(--color-text-tertiary); + cursor: pointer; + opacity: 0.6; + transition: all var(--transition-fast); +} + +swp-journal-entry-delete:hover { + opacity: 1; + color: var(--color-red); +} + +swp-journal-entry-body { + font-size: var(--font-size-sm); + color: var(--color-text); + line-height: 1.6; +} + +swp-journal-entry-body .label { + color: var(--color-text-secondary); +} + +swp-journal-entry-body .mono { + font-family: var(--font-mono); +} + +swp-journal-entry-footer { + display: flex; + justify-content: space-between; + align-items: center; + padding-top: var(--spacing-3); + border-top: 1px solid var(--color-border); +} + +swp-journal-entry-date { + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); +} + +swp-journal-entry-visibility { + display: flex; + align-items: center; + gap: var(--spacing-2); + font-size: var(--font-size-xs); + color: var(--color-text-secondary); +} + +swp-journal-entry-visibility.warning { + color: var(--color-amber); +} + +/* =========================================== + CUSTOMER DETAIL - APPOINTMENTS TAB + =========================================== */ + +/* Appointment Card (for upcoming) */ +swp-appointment-card { + display: flex; + flex-direction: column; + gap: var(--spacing-3); + padding: var(--spacing-5); + background: var(--color-background-alt); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); +} + +swp-appointment-date { + font-size: var(--font-size-base); + font-weight: var(--font-weight-semibold); + color: var(--color-text); +} + +swp-appointment-details { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +swp-appointment-actions { + display: flex; + gap: var(--spacing-3); + margin-top: var(--spacing-2); +} + +/* Simple Table (for previous appointments) */ +swp-table { + display: flex; + flex-direction: column; +} + +swp-table-header { + display: grid; + grid-template-columns: 120px 1fr 100px 80px 100px; + padding: var(--spacing-3) 0; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--color-text-secondary); + border-bottom: 1px solid var(--color-border); +} + +swp-table-header span:last-child { + text-align: right; +} + +swp-table-row { + display: grid; + grid-template-columns: 120px 1fr 100px 80px 100px; + padding: var(--spacing-4) 0; + font-size: var(--font-size-sm); + color: var(--color-text); + border-bottom: 1px solid var(--color-border); +} + +swp-table-row:last-child { + border-bottom: none; +} + +swp-table-row span:last-child { + text-align: right; +} + +swp-table-row .mono { + font-family: var(--font-mono); +} + +/* See All Link */ +swp-see-all { + display: block; + padding-top: var(--spacing-4); + font-size: var(--font-size-sm); + color: var(--color-teal); + text-align: center; + cursor: pointer; +} + +swp-see-all:hover { + text-decoration: underline; +} + +/* Button */ +swp-btn { + display: inline-flex; + align-items: center; + gap: var(--spacing-2); + padding: var(--spacing-2) var(--spacing-4); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + border-radius: var(--radius-md); + border: none; + cursor: pointer; + transition: all var(--transition-fast); +} + +swp-btn.primary { + background: var(--color-teal); + color: white; +} + +swp-btn.primary:hover { + background: var(--color-teal-hover); +} + +swp-btn.secondary { + background: var(--color-surface); + color: var(--color-text); + border: 1px solid var(--color-border); +} + +swp-btn.secondary:hover { + background: var(--color-background); +} + +/* =========================================== + CUSTOMER DETAIL - GIFTCARDS TAB + =========================================== */ + +/* Giftcard Card */ +swp-giftcard { + display: flex; + flex-direction: column; + gap: var(--spacing-3); + padding: var(--spacing-5); + background: var(--color-background-alt); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); +} + +swp-giftcard-header { + font-size: var(--font-size-base); + font-weight: var(--font-weight-semibold); + color: var(--color-text); +} + +swp-giftcard-balance { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +swp-giftcard-balance strong { + color: var(--color-text); + font-weight: var(--font-weight-semibold); +} + +swp-giftcard-expires { + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); +} + +/* Progress Bar */ +swp-progress-bar { + height: 6px; + background: var(--color-border); + border-radius: var(--radius-full); + overflow: hidden; +} + +swp-progress-fill { + height: 100%; + background: var(--color-teal); + border-radius: var(--radius-full); +} + +/* =========================================== + CUSTOMER DETAIL - ACTIVITY TAB + =========================================== */ + +/* Activity Filters */ +swp-activity-filters { + display: flex; + gap: var(--spacing-2); + margin-bottom: var(--spacing-6); + flex-wrap: wrap; +} + +swp-activity-filter { + display: inline-flex; + align-items: center; + gap: var(--spacing-2); + padding: var(--spacing-2) var(--spacing-4); + font-size: var(--font-size-sm); + color: var(--color-text-secondary); + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + cursor: pointer; + transition: all var(--transition-fast); +} + +swp-activity-filter:hover { + border-color: var(--color-teal); + color: var(--color-teal); +} + +swp-activity-filter.active { + background: var(--bg-teal-subtle); + border-color: var(--color-teal); + color: var(--color-teal); +} + +swp-activity-filter i { + font-size: var(--font-size-base); + opacity: 0.7; +} + +/* Activity Timeline */ +swp-activity-timeline { + display: flex; + flex-direction: column; +} + +swp-activity-date-group { + display: flex; + flex-direction: column; + padding: var(--spacing-5); + border-bottom: 1px solid var(--color-border); +} + +swp-activity-date-group:last-child { + border-bottom: none; +} + +swp-activity-date-header { + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + color: var(--color-text-secondary); + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: var(--spacing-4); +} + +swp-activity-item { + display: flex; + gap: var(--spacing-4); + padding: var(--spacing-3) 0; +} + +swp-activity-icon { + width: 32px; + height: 32px; + border-radius: var(--radius-full); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + font-size: var(--font-size-base); +} + +swp-activity-icon.communication { + background: var(--bg-blue-subtle); + color: var(--color-blue); +} + +swp-activity-icon.customer { + background: var(--bg-purple-subtle); + color: var(--color-purple); +} + +swp-activity-icon.booking { + background: var(--bg-teal-subtle); + color: var(--color-teal); +} + +swp-activity-icon.edit { + background: var(--bg-amber-subtle); + color: var(--color-amber); +} + +swp-activity-icon.warning { + background: var(--bg-red-subtle); + color: var(--color-red); +} + +swp-activity-content { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--spacing-1); +} + +swp-activity-title { + font-size: var(--font-size-sm); + color: var(--color-text); + display: flex; + align-items: center; + gap: var(--spacing-3); + flex-wrap: wrap; +} + +swp-activity-badge { + display: inline-flex; + padding: var(--spacing-1) var(--spacing-2); + font-size: 10px; + font-weight: var(--font-weight-semibold); + text-transform: uppercase; + border-radius: var(--radius-sm); +} + +swp-activity-badge.auto { + background: var(--color-background); + color: var(--color-text-secondary); +} + +swp-activity-badge.online { + background: var(--bg-blue-subtle); + color: var(--color-blue); +} + +swp-activity-meta { + display: flex; + gap: var(--spacing-3); + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); +} + +swp-activity-time { + font-family: var(--font-mono); +} + +swp-activity-actor { + color: var(--color-text-secondary); +}