Calendar/wwwroot/poc-customer-detail.html
Janus C. H. Knudsen 9c77d1f556 Refactors customer detail and list page components
Enhances UI/UX with more dynamic toggle sliders
Improves tag management and interaction
Updates marketing consent toggles with new design

Adds more interactive customer information display
2025-12-22 15:00:38 +01:00

2093 lines
58 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="da">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kundedetaljer - Sofie Nielsen</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
/* ==========================================
CSS VARIABLES (Design System)
========================================== */
:root {
/* Colors */
--color-surface: #fff;
--color-background: #f5f5f5;
--color-background-hover: #f0f0f0;
--color-background-alt: #fafafa;
--color-border: #e0e0e0;
--color-text: #333;
--color-text-secondary: #666;
--color-teal: #00897b;
--color-blue: #1976d2;
--color-red: #e53935;
--color-amber: #ffb300;
--color-purple: #8b5cf6;
--color-green: #43a047;
/* Typography */
--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
}
/* ==========================================
RESET & BASE
========================================== */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-family);
font-size: 14px;
color: var(--color-text);
background: var(--color-background);
line-height: 1.5;
}
/* ==========================================
TOPBAR
========================================== */
swp-topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 24px;
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 0;
z-index: 100;
}
swp-topbar-left {
display: flex;
align-items: center;
gap: 16px;
}
swp-back-link {
display: flex;
align-items: center;
gap: 6px;
color: var(--color-text-secondary);
text-decoration: none;
font-size: 13px;
cursor: pointer;
transition: color 150ms ease;
}
swp-back-link:hover {
color: var(--color-teal);
}
swp-back-link img {
width: 16px;
height: 16px;
opacity: 0.6;
}
swp-topbar-title {
font-size: 16px;
font-weight: 600;
color: var(--color-text);
}
swp-topbar-actions {
display: flex;
align-items: center;
gap: 12px;
}
swp-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
font-size: 13px;
font-weight: 500;
border-radius: 6px;
border: none;
cursor: pointer;
transition: all 150ms ease;
}
swp-btn.primary {
background: var(--color-teal);
color: white;
}
swp-btn.primary:hover {
background: #00796b;
}
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);
}
/* ==========================================
STICKY HEADER
========================================== */
swp-customer-header {
display: flex;
gap: 24px;
padding: 24px;
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 49px;
z-index: 90;
}
swp-customer-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(135deg, var(--color-teal) 0%, #00695c 100%);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
font-weight: 600;
flex-shrink: 0;
}
swp-customer-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
swp-customer-name-row {
display: flex;
align-items: center;
gap: 16px;
}
swp-customer-name {
font-size: 24px;
font-weight: 600;
color: var(--color-text);
}
swp-customer-name[contenteditable="true"] {
outline: none;
border-bottom: 1px dashed var(--color-border);
padding-bottom: 2px;
}
swp-customer-name[contenteditable="true"]:focus {
border-bottom-color: var(--color-teal);
}
/* Tags Editor */
swp-tags-editor {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
swp-tag {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.3px;
border-radius: 4px;
background: var(--color-background);
color: var(--color-text-secondary);
}
swp-tag.vip {
background: color-mix(in srgb, var(--color-amber) 20%, white);
color: #b8860b;
}
swp-tag.stamkunde {
background: color-mix(in srgb, var(--color-teal) 15%, white);
color: var(--color-teal);
}
swp-tag.ny {
background: color-mix(in srgb, var(--color-blue) 15%, white);
color: var(--color-blue);
}
swp-tag.allergi {
background: color-mix(in srgb, var(--color-red) 15%, white);
color: var(--color-red);
}
swp-tag.sensitiv {
background: color-mix(in srgb, var(--color-purple) 15%, white);
color: var(--color-purple);
}
swp-tag .remove {
cursor: pointer;
opacity: 0.6;
margin-left: 2px;
}
swp-tag .remove:hover {
opacity: 1;
}
swp-tag-add {
display: inline-flex;
align-items: center;
padding: 4px 10px;
font-size: 11px;
font-weight: 500;
color: var(--color-text-secondary);
border: 1px dashed var(--color-border);
border-radius: 4px;
cursor: pointer;
transition: all 150ms ease;
}
swp-tag-add:hover {
border-color: var(--color-teal);
color: var(--color-teal);
}
/* Booking Exclusion Toggle */
swp-booking-exclusion {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
font-size: 12px;
font-weight: 500;
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
margin-left: auto;
}
swp-booking-exclusion[data-excluded="false"] {
background: var(--color-background);
color: var(--color-text-secondary);
border: 1px solid var(--color-border);
}
swp-booking-exclusion[data-excluded="true"] {
background: color-mix(in srgb, var(--color-red) 12%, white);
color: var(--color-red);
border: 1px solid color-mix(in srgb, var(--color-red) 30%, white);
}
swp-booking-exclusion .icon {
font-size: 14px;
}
/* Customer Group Selector */
swp-customer-group {
display: inline-flex;
align-items: center;
gap: 8px;
position: relative;
}
swp-customer-group-label {
font-size: 12px;
color: var(--color-text-secondary);
}
swp-customer-group-select {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 10px;
font-size: 13px;
font-weight: 500;
color: var(--color-text);
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
}
swp-customer-group-select:hover {
border-color: var(--color-teal);
}
swp-customer-group-select .arrow {
font-size: 10px;
color: var(--color-text-secondary);
}
swp-customer-group-dropdown {
position: absolute;
top: 100%;
left: 0;
margin-top: 4px;
min-width: 180px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 200;
display: none;
}
swp-customer-group-dropdown.open {
display: block;
}
swp-customer-group-option {
display: block;
padding: 10px 14px;
font-size: 13px;
color: var(--color-text);
cursor: pointer;
transition: background 100ms ease;
}
swp-customer-group-option:first-child {
border-radius: 7px 7px 0 0;
}
swp-customer-group-option:last-child {
border-radius: 0 0 7px 7px;
}
swp-customer-group-option:hover {
background: var(--color-background);
}
swp-customer-group-option.selected {
background: color-mix(in srgb, var(--color-teal) 10%, white);
color: var(--color-teal);
font-weight: 500;
}
/* Relation Items */
swp-relations-list {
display: flex;
flex-direction: column;
gap: 8px;
}
swp-relation-item {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 12px;
background: var(--color-background-alt);
border: 1px solid var(--color-border);
border-radius: 6px;
}
swp-relation-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--color-purple);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: 600;
flex-shrink: 0;
}
swp-relation-info {
flex: 1;
}
swp-relation-name {
display: block;
font-size: 14px;
font-weight: 500;
color: var(--color-text);
}
swp-relation-type {
display: block;
font-size: 12px;
color: var(--color-text-secondary);
}
swp-relation-actions {
display: flex;
gap: 8px;
}
swp-relation-link {
font-size: 12px;
color: var(--color-teal);
cursor: pointer;
}
swp-relation-link:hover {
text-decoration: underline;
}
swp-relation-remove {
font-size: 14px;
color: var(--color-text-secondary);
cursor: pointer;
opacity: 0.6;
}
swp-relation-remove:hover {
opacity: 1;
color: var(--color-red);
}
swp-add-relation {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border: 1px dashed var(--color-border);
border-radius: 6px;
color: var(--color-text-secondary);
font-size: 13px;
cursor: pointer;
transition: all 150ms ease;
}
swp-add-relation:hover {
border-color: var(--color-teal);
color: var(--color-teal);
}
/* Customer Group in Card */
swp-customer-group-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid var(--color-border);
}
/* Contact Line */
swp-contact-line {
display: flex;
align-items: center;
gap: 16px;
font-size: 13px;
color: var(--color-text-secondary);
}
swp-contact-line a {
color: var(--color-teal);
text-decoration: none;
}
swp-contact-line a:hover {
text-decoration: underline;
}
swp-contact-line span.separator {
color: var(--color-border);
}
/* Fact Boxes Inline */
swp-fact-boxes-inline {
display: flex;
gap: 24px;
margin-top: 4px;
}
swp-fact-inline {
display: flex;
align-items: baseline;
gap: 6px;
}
swp-fact-inline-value {
font-size: 18px;
font-weight: 600;
font-family: var(--font-mono);
color: var(--color-text);
}
swp-fact-inline-label {
font-size: 12px;
color: var(--color-text-secondary);
}
/* ==========================================
TAB BAR
========================================== */
swp-tab-bar {
display: flex;
gap: 0;
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
padding: 0 24px;
position: sticky;
top: 193px;
z-index: 80;
}
swp-tab {
padding: 14px 24px;
font-size: 14px;
font-weight: 500;
color: var(--color-text-secondary);
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: all 150ms ease;
}
swp-tab:hover {
color: var(--color-text);
background: var(--color-background-alt);
}
swp-tab.active {
color: var(--color-teal);
border-bottom-color: var(--color-teal);
}
/* ==========================================
TAB CONTENT
========================================== */
swp-tab-content {
display: none;
padding: 24px;
max-width: 1200px;
margin: 0 auto;
}
swp-tab-content.active {
display: block;
}
/* ==========================================
COMMON COMPONENTS
========================================== */
/* Section Label */
swp-section-label {
display: block;
font-size: 11px;
font-weight: 600;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 12px;
}
/* Card */
swp-card {
display: block;
background: var(--color-surface);
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
padding: 20px;
margin-bottom: 20px;
}
/* Grid Layouts */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.grid-4 {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
}
/* Edit Section */
swp-edit-section {
display: flex;
flex-direction: column;
gap: 12px;
}
swp-edit-row {
display: grid;
grid-template-columns: 120px 1fr;
align-items: center;
gap: 12px;
}
swp-edit-label {
font-size: 13px;
color: var(--color-text-secondary);
}
swp-edit-value {
font-size: 14px;
color: var(--color-text);
padding: 8px 12px;
border: 1px solid transparent;
border-radius: 6px;
cursor: text;
transition: all 150ms ease;
}
swp-edit-value:hover {
background: var(--color-background-alt);
}
swp-edit-value:focus {
outline: none;
border-color: var(--color-teal);
background: var(--color-surface);
}
swp-edit-value[contenteditable="true"] {
cursor: text;
}
/* Toggle Slider (Ja/Nej) */
swp-toggle-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid var(--color-border);
}
swp-toggle-row:last-child {
border-bottom: none;
}
swp-toggle-label {
font-size: 14px;
color: var(--color-text);
}
swp-toggle-slider {
display: flex;
position: relative;
background: var(--color-background);
border-radius: 6px;
padding: 3px;
gap: 0;
}
swp-toggle-slider::before {
content: '';
position: absolute;
top: 3px;
left: 3px;
width: calc(50% - 3px);
height: calc(100% - 6px);
background: color-mix(in srgb, var(--color-green) 18%, white);
border-radius: 4px;
transition: transform 200ms ease, background 200ms ease;
z-index: 0;
}
swp-toggle-slider[data-value="no"]::before {
transform: translateX(100%);
background: color-mix(in srgb, var(--color-red) 18%, white);
}
swp-toggle-option {
position: relative;
z-index: 1;
padding: 5px 16px;
font-size: 12px;
font-weight: 500;
color: var(--color-text-secondary);
cursor: pointer;
transition: color 200ms ease;
user-select: none;
}
swp-toggle-slider[data-value="yes"] swp-toggle-option:first-child {
color: var(--color-green);
font-weight: 600;
}
swp-toggle-slider[data-value="no"] swp-toggle-option:last-child {
color: var(--color-red);
font-weight: 600;
}
/* Profile Boxes */
swp-profile-boxes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
swp-profile-box {
padding: 12px 14px;
background: var(--color-background-alt);
border-radius: 6px;
border: 1px solid var(--color-border);
}
swp-profile-box.warning {
background: color-mix(in srgb, var(--color-red) 8%, white);
border-color: color-mix(in srgb, var(--color-red) 30%, white);
}
swp-profile-box.full-width {
grid-column: span 2;
}
swp-profile-box-label {
display: block;
font-size: 11px;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 4px;
}
swp-profile-box-value {
font-size: 14px;
color: var(--color-text);
}
swp-profile-box.warning swp-profile-box-value {
color: var(--color-red);
}
/* Stat Cards */
swp-stat-card {
background: var(--color-surface);
border-radius: 8px;
padding: 16px 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
text-align: center;
}
swp-stat-value {
display: block;
font-size: 24px;
font-weight: 600;
color: var(--color-text);
font-family: var(--font-mono);
}
swp-stat-card.highlight swp-stat-value {
color: var(--color-teal);
}
swp-stat-label {
display: block;
font-size: 12px;
color: var(--color-text-secondary);
margin-top: 4px;
}
/* Chart Container */
swp-chart-container {
display: block;
background: var(--color-background-alt);
border-radius: 8px;
border: 1px solid var(--color-border);
min-height: 200px;
}
swp-chart-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
swp-chart-legend {
display: flex;
gap: 16px;
}
swp-chart-legend-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--color-text-secondary);
}
swp-chart-legend-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
swp-chart-legend-dot.services {
background: var(--color-teal);
}
swp-chart-legend-dot.products {
background: var(--color-blue);
}
/* Table */
swp-table {
display: block;
width: 100%;
}
swp-table-header {
display: grid;
padding: 12px 16px;
background: var(--color-background);
border-radius: 6px 6px 0 0;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--color-text-secondary);
}
swp-table-row {
display: grid;
padding: 12px 16px;
border-bottom: 1px solid var(--color-border);
font-size: 13px;
align-items: center;
}
swp-table-row:last-child {
border-bottom: none;
}
swp-table-row:hover {
background: var(--color-background-alt);
}
/* Journal Entry */
swp-journal-entry {
display: block;
padding: 16px;
background: var(--color-surface);
border-radius: 8px;
border: 1px solid var(--color-border);
margin-bottom: 12px;
}
swp-journal-entry:last-child {
margin-bottom: 0;
}
swp-journal-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
swp-journal-type {
display: inline-block;
padding: 3px 8px;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.3px;
border-radius: 4px;
}
swp-journal-type.farveformel {
background: color-mix(in srgb, var(--color-teal) 15%, white);
color: var(--color-teal);
}
swp-journal-type.analyse {
background: color-mix(in srgb, var(--color-purple) 15%, white);
color: var(--color-purple);
}
swp-journal-type.note {
background: color-mix(in srgb, var(--color-blue) 15%, white);
color: var(--color-blue);
}
swp-journal-type.advarsel {
background: color-mix(in srgb, var(--color-red) 15%, white);
color: var(--color-red);
}
swp-journal-date {
font-size: 12px;
color: var(--color-text-secondary);
}
swp-journal-content {
font-size: 14px;
color: var(--color-text);
line-height: 1.6;
}
swp-journal-author {
font-size: 12px;
color: var(--color-text-secondary);
margin-top: 8px;
}
/* Appointment Card */
swp-appointment-card {
display: block;
padding: 16px;
background: color-mix(in srgb, var(--color-teal) 5%, white);
border: 1px solid color-mix(in srgb, var(--color-teal) 20%, white);
border-radius: 8px;
margin-bottom: 12px;
}
swp-appointment-date {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 600;
color: var(--color-teal);
margin-bottom: 6px;
}
swp-appointment-details {
font-size: 13px;
color: var(--color-text);
margin-bottom: 12px;
}
swp-appointment-actions {
display: flex;
gap: 8px;
}
swp-appointment-actions swp-btn {
padding: 6px 12px;
font-size: 12px;
}
/* Giftcard */
swp-giftcard {
display: block;
padding: 16px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 8px;
margin-bottom: 12px;
}
swp-giftcard-header {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 600;
color: var(--color-text);
margin-bottom: 8px;
}
swp-giftcard-balance {
font-size: 13px;
color: var(--color-text);
margin-bottom: 4px;
}
swp-giftcard-balance strong {
font-family: var(--font-mono);
color: var(--color-teal);
}
swp-giftcard-expires {
font-size: 12px;
color: var(--color-text-secondary);
}
/* Progress Bar */
swp-progress-bar {
display: block;
height: 8px;
background: var(--color-background);
border-radius: 4px;
overflow: hidden;
margin: 8px 0;
}
swp-progress-fill {
display: block;
height: 100%;
background: var(--color-teal);
border-radius: 4px;
transition: width 300ms ease;
}
/* See All Link */
swp-see-all {
display: inline-block;
margin-top: 12px;
font-size: 13px;
color: var(--color-teal);
cursor: pointer;
}
swp-see-all:hover {
text-decoration: underline;
}
/* Add Button */
swp-add-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 10px 16px;
font-size: 13px;
font-weight: 500;
color: var(--color-teal);
background: color-mix(in srgb, var(--color-teal) 10%, white);
border: 1px solid color-mix(in srgb, var(--color-teal) 30%, white);
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
margin-bottom: 16px;
}
swp-add-btn:hover {
background: color-mix(in srgb, var(--color-teal) 15%, white);
}
/* Empty State */
swp-empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px;
text-align: center;
color: var(--color-text-secondary);
}
swp-empty-state p {
font-size: 14px;
}
/* ==========================================
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);
}
/* ==========================================
KEY-VALUE LIST
========================================== */
swp-kv-list {
display: flex;
flex-direction: column;
}
swp-kv-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid var(--color-border);
}
swp-kv-row:last-child {
border-bottom: none;
}
swp-kv-label {
font-size: 13px;
color: var(--color-text-secondary);
}
swp-kv-value {
font-size: 14px;
font-weight: 500;
font-family: var(--font-mono);
color: var(--color-text);
}
/* ==========================================
RATIO BAR
========================================== */
swp-ratio-container {
display: block;
margin-top: 16px;
}
swp-ratio-labels {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
font-size: 12px;
color: var(--color-text-secondary);
}
swp-ratio-bar {
display: flex;
height: 10px;
border-radius: 5px;
overflow: hidden;
background: var(--color-background);
}
swp-ratio-segment {
height: 100%;
transition: width 300ms ease;
}
swp-ratio-segment.services {
background: var(--color-teal);
}
swp-ratio-segment.products {
background: var(--color-blue);
}
/* ==========================================
RISK INDICATOR
========================================== */
swp-risk-indicator {
display: inline-flex;
align-items: center;
gap: 6px;
}
swp-risk-dot {
width: 10px;
height: 10px;
border-radius: 50%;
}
swp-risk-dot.low {
background: var(--color-green);
}
swp-risk-dot.medium {
background: var(--color-amber);
}
swp-risk-dot.high {
background: var(--color-red);
}
swp-risk-text {
font-size: 14px;
font-weight: 500;
}
swp-risk-text.low {
color: var(--color-green);
}
swp-risk-text.medium {
color: var(--color-amber);
}
swp-risk-text.high {
color: var(--color-red);
}
/* ==========================================
TOP LIST
========================================== */
swp-top-list {
display: flex;
flex-direction: column;
gap: 8px;
}
swp-top-item {
display: flex;
align-items: center;
gap: 12px;
font-size: 13px;
}
swp-top-rank {
width: 24px;
height: 24px;
border-radius: 50%;
background: var(--color-background);
color: var(--color-text-secondary);
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 600;
}
swp-top-item:first-child swp-top-rank {
background: color-mix(in srgb, var(--color-teal) 15%, white);
color: var(--color-teal);
}
swp-top-name {
flex: 1;
color: var(--color-text);
}
swp-top-count {
font-family: var(--font-mono);
font-size: 12px;
color: var(--color-text-secondary);
}
/* ==========================================
ATTENDANCE BAR
========================================== */
swp-attendance-bar {
display: flex;
height: 24px;
border-radius: 6px;
overflow: hidden;
margin-top: 12px;
}
swp-attendance-segment {
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 600;
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);
}
</style>
</head>
<body>
<!-- Topbar -->
<swp-topbar>
<swp-topbar-left>
<swp-back-link onclick="history.back()">
<img src="icons/angle-small-left.svg" alt="">
Tilbage til kunder
</swp-back-link>
</swp-topbar-left>
<swp-topbar-actions>
<swp-btn class="secondary">Slet kunde</swp-btn>
<swp-btn class="primary" id="saveBtn">Gem</swp-btn>
</swp-topbar-actions>
</swp-topbar>
<!-- Sticky Header -->
<swp-customer-header>
<swp-customer-avatar>SN</swp-customer-avatar>
<swp-customer-info>
<swp-customer-name-row>
<swp-customer-name contenteditable="true">Sofie Nielsen</swp-customer-name>
<swp-tags-editor>
<swp-tag class="vip">VIP <span class="remove">×</span></swp-tag>
<swp-tag-add>+ Tilføj tag</swp-tag-add>
</swp-tags-editor>
<swp-booking-exclusion data-excluded="false" id="bookingExclusion">
<span class="icon"></span>
<span class="text">Booking tilladt</span>
</swp-booking-exclusion>
</swp-customer-name-row>
<swp-contact-line>
<a href="tel:+4523456789">+45 23 45 67 89</a>
<span class="separator">|</span>
<a href="mailto:sofie@email.dk">sofie@email.dk</a>
<span class="separator">|</span>
<span>Kunde siden marts 2024</span>
</swp-contact-line>
<swp-fact-boxes-inline>
<swp-fact-inline>
<swp-fact-inline-value>14</swp-fact-inline-value>
<swp-fact-inline-label>besøg</swp-fact-inline-label>
</swp-fact-inline>
<swp-fact-inline>
<swp-fact-inline-value>32</swp-fact-inline-value>
<swp-fact-inline-label>dage interval</swp-fact-inline-label>
</swp-fact-inline>
<swp-fact-inline>
<swp-fact-inline-value>Emma L.</swp-fact-inline-value>
<swp-fact-inline-label>foretrukken frisør</swp-fact-inline-label>
</swp-fact-inline>
<swp-fact-inline>
<swp-fact-inline-value>12.450 kr</swp-fact-inline-value>
<swp-fact-inline-label>total omsætning</swp-fact-inline-label>
</swp-fact-inline>
</swp-fact-boxes-inline>
</swp-customer-info>
</swp-customer-header>
<!-- Tab Bar -->
<swp-tab-bar>
<swp-tab class="active" data-tab="overview">Oversigt</swp-tab>
<swp-tab data-tab="economy">Økonomi</swp-tab>
<swp-tab data-tab="statistics">Statistik</swp-tab>
<swp-tab data-tab="journal">Journal</swp-tab>
<swp-tab data-tab="appointments">Aftaler</swp-tab>
<swp-tab data-tab="giftcards">Gavekort</swp-tab>
</swp-tab-bar>
<!-- Tab Contents -->
<!-- OVERSIGT TAB -->
<swp-tab-content class="active" data-tab="overview">
<div class="grid-2">
<!-- Left Column -->
<div>
<swp-card>
<swp-section-label>Kontaktoplysninger</swp-section-label>
<swp-edit-section>
<swp-edit-row>
<swp-edit-label>Telefon</swp-edit-label>
<swp-edit-value contenteditable="true">+45 23 45 67 89</swp-edit-value>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Email</swp-edit-label>
<swp-edit-value contenteditable="true">sofie@email.dk</swp-edit-value>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Adresse</swp-edit-label>
<swp-edit-value contenteditable="true">Hovedgaden 12</swp-edit-value>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Postnr + By</swp-edit-label>
<swp-edit-value contenteditable="true">2100 København Ø</swp-edit-value>
</swp-edit-row>
</swp-edit-section>
</swp-card>
<swp-card>
<swp-section-label>Profil</swp-section-label>
<swp-profile-boxes>
<swp-profile-box>
<swp-profile-box-label>Hårtype</swp-profile-box-label>
<swp-profile-box-value>Medium · Bølget</swp-profile-box-value>
</swp-profile-box>
<swp-profile-box>
<swp-profile-box-label>Porøsitet</swp-profile-box-label>
<swp-profile-box-value>Medium</swp-profile-box-value>
</swp-profile-box>
<swp-profile-box>
<swp-profile-box-label>Hovedbund</swp-profile-box-label>
<swp-profile-box-value>Normal</swp-profile-box-value>
</swp-profile-box>
<swp-profile-box>
<swp-profile-box-label>Naturlig farve</swp-profile-box-label>
<swp-profile-box-value>Mørkblond (6)</swp-profile-box-value>
</swp-profile-box>
</swp-profile-boxes>
</swp-card>
</div>
<!-- Right Column -->
<div>
<swp-card>
<swp-section-label>Marketing</swp-section-label>
<swp-toggle-row>
<swp-toggle-label>Email marketing</swp-toggle-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<swp-toggle-label>SMS marketing</swp-toggle-label>
<swp-toggle-slider data-value="no">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
</swp-card>
<swp-card>
<swp-section-label>Præferencer</swp-section-label>
<swp-profile-boxes>
<swp-profile-box>
<swp-profile-box-label>Foretrukken frisør</swp-profile-box-label>
<swp-profile-box-value>Emma L.</swp-profile-box-value>
</swp-profile-box>
<swp-profile-box>
<swp-profile-box-label>Foretrukken dag</swp-profile-box-label>
<swp-profile-box-value>Tirsdag/Torsdag</swp-profile-box-value>
</swp-profile-box>
<swp-profile-box class="full-width">
<swp-profile-box-label>Specielle ønsker</swp-profile-box-label>
<swp-profile-box-value>Foretrækker kold tone, ikke for mørk</swp-profile-box-value>
</swp-profile-box>
</swp-profile-boxes>
</swp-card>
<swp-card>
<swp-section-label>Advarsler</swp-section-label>
<swp-profile-boxes>
<swp-profile-box class="warning full-width">
<swp-profile-box-label>Allergier / Følsomhed</swp-profile-box-label>
<swp-profile-box-value>Parfumeallergi - brug uparfumerede produkter</swp-profile-box-value>
</swp-profile-box>
</swp-profile-boxes>
</swp-card>
<swp-card>
<swp-section-label>Kundegruppe & Relationer</swp-section-label>
<swp-customer-group-row>
<swp-customer-group-label>Kundegruppe:</swp-customer-group-label>
<swp-customer-group>
<swp-customer-group-select id="customerGroupSelect">
<span class="value">Standard</span>
<span class="arrow"></span>
</swp-customer-group-select>
<swp-customer-group-dropdown id="customerGroupDropdown">
<swp-customer-group-option class="selected" data-value="standard">Standard</swp-customer-group-option>
<swp-customer-group-option data-value="premium">Premium</swp-customer-group-option>
<swp-customer-group-option data-value="erhverv">Erhverv</swp-customer-group-option>
<swp-customer-group-option data-value="medarbejder">Medarbejder</swp-customer-group-option>
<swp-customer-group-option data-value="familie">Familie & Venner</swp-customer-group-option>
</swp-customer-group-dropdown>
</swp-customer-group>
</swp-customer-group-row>
<swp-relations-list>
<swp-relation-item>
<swp-relation-avatar>EN</swp-relation-avatar>
<swp-relation-info>
<swp-relation-name>Emil Nielsen</swp-relation-name>
<swp-relation-type>Barn</swp-relation-type>
</swp-relation-info>
<swp-relation-actions>
<swp-relation-link>Åbn</swp-relation-link>
<swp-relation-remove>×</swp-relation-remove>
</swp-relation-actions>
</swp-relation-item>
<swp-relation-item>
<swp-relation-avatar>LN</swp-relation-avatar>
<swp-relation-info>
<swp-relation-name>Luna Nielsen</swp-relation-name>
<swp-relation-type>Barn</swp-relation-type>
</swp-relation-info>
<swp-relation-actions>
<swp-relation-link>Åbn</swp-relation-link>
<swp-relation-remove>×</swp-relation-remove>
</swp-relation-actions>
</swp-relation-item>
<swp-add-relation>
<span>+</span> Tilføj relation
</swp-add-relation>
</swp-relations-list>
</swp-card>
</div>
</div>
</swp-tab-content>
<!-- ØKONOMI TAB -->
<swp-tab-content data-tab="economy">
<div class="grid-4" style="margin-bottom: 24px;">
<swp-stat-card class="highlight">
<swp-stat-value>12.450 kr</swp-stat-value>
<swp-stat-label>I år (2025)</swp-stat-label>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value>9.800 kr</swp-stat-value>
<swp-stat-label>Sidste år</swp-stat-label>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value>889 kr</swp-stat-value>
<swp-stat-label>Gns. pr. besøg</swp-stat-label>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value>1.038 kr</swp-stat-value>
<swp-stat-label>Gns. pr. måned</swp-stat-label>
</swp-stat-card>
</div>
<swp-card>
<swp-chart-header>
<swp-section-label style="margin-bottom: 0;">Omsætning over tid</swp-section-label>
<swp-chart-legend>
<swp-chart-legend-item>
<swp-chart-legend-dot class="services"></swp-chart-legend-dot>
<span>Services</span>
</swp-chart-legend-item>
<swp-chart-legend-item>
<swp-chart-legend-dot class="products"></swp-chart-legend-dot>
<span>Produkter</span>
</swp-chart-legend-item>
</swp-chart-legend>
</swp-chart-header>
<swp-chart-container id="revenueChart"></swp-chart-container>
</swp-card>
<swp-card>
<swp-section-label>Købshistorik</swp-section-label>
<swp-table>
<swp-table-header style="grid-template-columns: 100px 80px 1fr 100px;">
<span>Dato</span>
<span>Type</span>
<span>Beskrivelse</span>
<span style="text-align: right;">Beløb</span>
</swp-table-header>
<swp-table-row style="grid-template-columns: 100px 80px 1fr 100px;">
<span>9. dec 2025</span>
<span><swp-journal-type class="farveformel" style="font-size: 9px;">Service</swp-journal-type></span>
<span>Klip + Farve</span>
<span style="text-align: right; font-family: var(--font-mono);">1.450 kr</span>
</swp-table-row>
<swp-table-row style="grid-template-columns: 100px 80px 1fr 100px;">
<span>9. dec 2025</span>
<span><swp-journal-type class="analyse" style="font-size: 9px;">Produkt</swp-journal-type></span>
<span>Olaplex No. 3</span>
<span style="text-align: right; font-family: var(--font-mono);">349 kr</span>
</swp-table-row>
<swp-table-row style="grid-template-columns: 100px 80px 1fr 100px;">
<span>12. nov 2025</span>
<span><swp-journal-type class="farveformel" style="font-size: 9px;">Service</swp-journal-type></span>
<span>Farve</span>
<span style="text-align: right; font-family: var(--font-mono);">1.200 kr</span>
</swp-table-row>
<swp-table-row style="grid-template-columns: 100px 80px 1fr 100px;">
<span>15. okt 2025</span>
<span><swp-journal-type class="farveformel" style="font-size: 9px;">Service</swp-journal-type></span>
<span>Klip</span>
<span style="text-align: right; font-family: var(--font-mono);">550 kr</span>
</swp-table-row>
</swp-table>
<swp-see-all>Se alle transaktioner →</swp-see-all>
</swp-card>
</swp-tab-content>
<!-- STATISTIK TAB -->
<swp-tab-content data-tab="statistics">
<!-- Fremmøde & Pålidelighed -->
<swp-card>
<swp-section-label>Fremmøde & Pålidelighed</swp-section-label>
<div class="grid-4">
<swp-stat-card class="highlight">
<swp-stat-value>47</swp-stat-value>
<swp-stat-label>Fremmøder</swp-stat-label>
</swp-stat-card>
<swp-stat-card class="warning">
<swp-stat-value>3</swp-stat-value>
<swp-stat-label>Aflysninger</swp-stat-label>
</swp-stat-card>
<swp-stat-card class="danger">
<swp-stat-value>1</swp-stat-value>
<swp-stat-label>No-shows</swp-stat-label>
</swp-stat-card>
<swp-stat-card class="success">
<swp-stat-value>92%</swp-stat-value>
<swp-stat-label>Pålidelighed</swp-stat-label>
</swp-stat-card>
</div>
<swp-attendance-bar>
<swp-attendance-segment class="attended" style="width: 92%;">47</swp-attendance-segment>
<swp-attendance-segment class="cancelled" style="width: 6%;">3</swp-attendance-segment>
<swp-attendance-segment class="noshow" style="width: 2%;">1</swp-attendance-segment>
</swp-attendance-bar>
</swp-card>
<div class="grid-2">
<!-- Booking-adfærd -->
<swp-card>
<swp-section-label>Booking-adfærd</swp-section-label>
<swp-kv-list>
<swp-kv-row>
<swp-kv-label>Gns. bookingvarsel</swp-kv-label>
<swp-kv-value>5 dage</swp-kv-value>
</swp-kv-row>
<swp-kv-row>
<swp-kv-label>Foretrukken dag</swp-kv-label>
<swp-kv-value>Tirsdag</swp-kv-value>
</swp-kv-row>
<swp-kv-row>
<swp-kv-label>Foretrukken tid</swp-kv-label>
<swp-kv-value>10:00 - 12:00</swp-kv-value>
</swp-kv-row>
<swp-kv-row>
<swp-kv-label>Online booking rate</swp-kv-label>
<swp-kv-value>78%</swp-kv-value>
</swp-kv-row>
<swp-kv-row>
<swp-kv-label>Gns. aflysningsvarsel</swp-kv-label>
<swp-kv-value>2 dage</swp-kv-value>
</swp-kv-row>
</swp-kv-list>
</swp-card>
<!-- Loyalitet -->
<swp-card>
<swp-section-label>Loyalitet</swp-section-label>
<div class="grid-2" style="gap: 12px;">
<swp-stat-card>
<swp-stat-value style="font-size: 20px;">1,8 år</swp-stat-value>
<swp-stat-label>Kunde siden</swp-stat-label>
</swp-stat-card>
<swp-stat-card class="success">
<swp-stat-value style="font-size: 20px;">13</swp-stat-value>
<swp-stat-label>Dage siden sidst</swp-stat-label>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value style="font-size: 20px;">
<swp-risk-indicator>
<swp-risk-dot class="low"></swp-risk-dot>
<swp-risk-text class="low">Lav</swp-risk-text>
</swp-risk-indicator>
</swp-stat-value>
<swp-stat-label>Churn-risiko</swp-stat-label>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value style="font-size: 20px;">32 dage</swp-stat-value>
<swp-stat-label>Gns. interval</swp-stat-label>
</swp-stat-card>
</div>
</swp-card>
</div>
<!-- Service-mønstre -->
<swp-card>
<swp-section-label>Service-mønstre</swp-section-label>
<div class="grid-2">
<div>
<swp-section-label style="font-size: 10px; margin-bottom: 10px;">Top 3 Services</swp-section-label>
<swp-top-list>
<swp-top-item>
<swp-top-rank>1</swp-top-rank>
<swp-top-name>Klip + Farve</swp-top-name>
<swp-top-count>12×</swp-top-count>
</swp-top-item>
<swp-top-item>
<swp-top-rank>2</swp-top-rank>
<swp-top-name>Farve</swp-top-name>
<swp-top-count>8×</swp-top-count>
</swp-top-item>
<swp-top-item>
<swp-top-rank>3</swp-top-rank>
<swp-top-name>Klip</swp-top-name>
<swp-top-count>6×</swp-top-count>
</swp-top-item>
</swp-top-list>
</div>
<div>
<swp-section-label style="font-size: 10px; margin-bottom: 10px;">Top 3 Produkter</swp-section-label>
<swp-top-list>
<swp-top-item>
<swp-top-rank>1</swp-top-rank>
<swp-top-name>Olaplex No. 3</swp-top-name>
<swp-top-count>5×</swp-top-count>
</swp-top-item>
<swp-top-item>
<swp-top-rank>2</swp-top-rank>
<swp-top-name>Shampoo</swp-top-name>
<swp-top-count>3×</swp-top-count>
</swp-top-item>
<swp-top-item>
<swp-top-rank>3</swp-top-rank>
<swp-top-name>Hårkur</swp-top-name>
<swp-top-count>2×</swp-top-count>
</swp-top-item>
</swp-top-list>
</div>
</div>
<swp-ratio-container>
<swp-ratio-labels>
<span>Services (85%)</span>
<span>Produkter (15%)</span>
</swp-ratio-labels>
<swp-ratio-bar>
<swp-ratio-segment class="services" style="width: 85%;"></swp-ratio-segment>
<swp-ratio-segment class="products" style="width: 15%;"></swp-ratio-segment>
</swp-ratio-bar>
</swp-ratio-container>
</swp-card>
</swp-tab-content>
<!-- JOURNAL TAB -->
<swp-tab-content data-tab="journal">
<swp-add-btn>+ Tilføj note</swp-add-btn>
<!-- Farveformler Section -->
<swp-card>
<swp-section-label>Farveformler</swp-section-label>
<swp-journal-entry>
<swp-journal-meta>
<swp-journal-type class="farveformel">Farveformel</swp-journal-type>
<swp-journal-date>12. nov 2025</swp-journal-date>
</swp-journal-meta>
<swp-journal-content>
<strong>Formel:</strong> 7/1 + 7/0 (1:1) · Oxidant 6% · Virketid 35 min<br>
<strong>Resultat:</strong> Flot ensartet farve, kunden meget tilfreds
</swp-journal-content>
<swp-journal-author>— Emma L.</swp-journal-author>
</swp-journal-entry>
<swp-journal-entry>
<swp-journal-meta>
<swp-journal-type class="farveformel">Farveformel</swp-journal-type>
<swp-journal-date>15. sep 2025</swp-journal-date>
</swp-journal-meta>
<swp-journal-content>
<strong>Formel:</strong> 8/0 + 7/1 (2:1) · Oxidant 6% · Virketid 30 min<br>
<strong>Resultat:</strong> Lidt for varm, juster næste gang
</swp-journal-content>
<swp-journal-author>— Emma L.</swp-journal-author>
</swp-journal-entry>
</swp-card>
<!-- Analyser Section -->
<swp-card>
<swp-section-label>Analyser</swp-section-label>
<swp-journal-entry>
<swp-journal-meta>
<swp-journal-type class="analyse">Håranalyse</swp-journal-type>
<swp-journal-date>10. aug 2025</swp-journal-date>
</swp-journal-meta>
<swp-journal-content>
<strong>Porøsitet:</strong> Medium<br>
<strong>Elasticitet:</strong> Normal<br>
<strong>Tilstand:</strong> Let tørt i spidserne<br>
<strong>Anbefaling:</strong> Fugtgivende behandling hver 6. uge
</swp-journal-content>
<swp-journal-author>— Nina K.</swp-journal-author>
</swp-journal-entry>
</swp-card>
<!-- Noter Section -->
<swp-card>
<swp-section-label>Noter</swp-section-label>
<swp-journal-entry>
<swp-journal-meta>
<swp-journal-type class="note">Note</swp-journal-type>
<swp-journal-date>9. dec 2025</swp-journal-date>
</swp-journal-meta>
<swp-journal-content>
Kunden foretrækker naturlige farver og ønsker lidt ekstra tid til konsultation. Husk at tjekke allergistatus inden farvebehandling.
</swp-journal-content>
<swp-journal-author>— Emma L.</swp-journal-author>
</swp-journal-entry>
<swp-journal-entry>
<swp-journal-meta>
<swp-journal-type class="advarsel">Advarsel</swp-journal-type>
<swp-journal-date>15. mar 2024</swp-journal-date>
</swp-journal-meta>
<swp-journal-content>
<strong>PARFUMEALLERGI</strong> - Brug kun uparfumerede produkter. Havde reaktion på standard shampoo ved første besøg.
</swp-journal-content>
<swp-journal-author>— Nina K.</swp-journal-author>
</swp-journal-entry>
</swp-card>
</swp-tab-content>
<!-- AFTALER TAB -->
<swp-tab-content data-tab="appointments">
<swp-card>
<swp-section-label>Kommende aftaler</swp-section-label>
<swp-appointment-card>
<swp-appointment-date>
Tirsdag 14. januar 2026 kl. 10:00
</swp-appointment-date>
<swp-appointment-details>
Klip + Farve · Emma L. · 2 timer
</swp-appointment-details>
<swp-appointment-actions>
<swp-btn class="secondary">Flyt</swp-btn>
<swp-btn class="secondary">Aflys</swp-btn>
</swp-appointment-actions>
</swp-appointment-card>
</swp-card>
<swp-card>
<swp-section-label>Tidligere aftaler</swp-section-label>
<swp-table>
<swp-table-header style="grid-template-columns: 120px 1fr 100px 80px 100px;">
<span>Dato</span>
<span>Service</span>
<span>Frisør</span>
<span>Varighed</span>
<span style="text-align: right;">Pris</span>
</swp-table-header>
<swp-table-row style="grid-template-columns: 120px 1fr 100px 80px 100px;">
<span>9. dec 2025</span>
<span>Klip + Farve</span>
<span>Emma L.</span>
<span>2 timer</span>
<span style="text-align: right; font-family: var(--font-mono);">1.450 kr</span>
</swp-table-row>
<swp-table-row style="grid-template-columns: 120px 1fr 100px 80px 100px;">
<span>12. nov 2025</span>
<span>Farve</span>
<span>Emma L.</span>
<span>1t 30m</span>
<span style="text-align: right; font-family: var(--font-mono);">1.200 kr</span>
</swp-table-row>
<swp-table-row style="grid-template-columns: 120px 1fr 100px 80px 100px;">
<span>15. okt 2025</span>
<span>Klip</span>
<span>Emma L.</span>
<span>45 min</span>
<span style="text-align: right; font-family: var(--font-mono);">550 kr</span>
</swp-table-row>
<swp-table-row style="grid-template-columns: 120px 1fr 100px 80px 100px;">
<span>20. sep 2025</span>
<span>Klip + Behandling</span>
<span>Nina K.</span>
<span>1t 15m</span>
<span style="text-align: right; font-family: var(--font-mono);">750 kr</span>
</swp-table-row>
<swp-table-row style="grid-template-columns: 120px 1fr 100px 80px 100px;">
<span>15. aug 2025</span>
<span>Farve + Klip</span>
<span>Emma L.</span>
<span>2t 15m</span>
<span style="text-align: right; font-family: var(--font-mono);">1.600 kr</span>
</swp-table-row>
</swp-table>
<swp-see-all>Se alle aftaler →</swp-see-all>
</swp-card>
</swp-tab-content>
<!-- GAVEKORT TAB -->
<swp-tab-content data-tab="giftcards">
<swp-card>
<swp-section-label>Aktive gavekort</swp-section-label>
<swp-giftcard>
<swp-giftcard-header>
Gavekort #GK-2024-0892
</swp-giftcard-header>
<swp-giftcard-balance>
Saldo: <strong>350 kr</strong> (af 500 kr)
</swp-giftcard-balance>
<swp-progress-bar>
<swp-progress-fill style="width: 70%;"></swp-progress-fill>
</swp-progress-bar>
<swp-giftcard-expires>Udløber: 15. marts 2026</swp-giftcard-expires>
</swp-giftcard>
</swp-card>
<swp-card>
<swp-section-label>Klippekort</swp-section-label>
<swp-giftcard>
<swp-giftcard-header>
10-klip kort
</swp-giftcard-header>
<swp-giftcard-balance>
Brugt: <strong>7 af 10</strong> klip
</swp-giftcard-balance>
<swp-progress-bar>
<swp-progress-fill style="width: 70%;"></swp-progress-fill>
</swp-progress-bar>
<swp-giftcard-expires>Udløber aldrig</swp-giftcard-expires>
</swp-giftcard>
</swp-card>
<swp-card>
<swp-section-label>Udløbne / Brugte</swp-section-label>
<swp-empty-state>
<p>Ingen udløbne eller brugte kort</p>
</swp-empty-state>
</swp-card>
</swp-tab-content>
<script>
// ==========================================
// TAB SWITCHING
// ==========================================
document.querySelectorAll('swp-tab').forEach(tab => {
tab.addEventListener('click', () => {
const tabName = tab.dataset.tab;
// Update tab active state
document.querySelectorAll('swp-tab').forEach(t => t.classList.remove('active'));
tab.classList.add('active');
// Update content visibility
document.querySelectorAll('swp-tab-content').forEach(content => {
content.classList.remove('active');
if (content.dataset.tab === tabName) {
content.classList.add('active');
}
});
});
});
// ==========================================
// TOGGLE SLIDERS (Ja/Nej)
// ==========================================
document.querySelectorAll('swp-toggle-slider').forEach(slider => {
const options = slider.querySelectorAll('swp-toggle-option');
options.forEach((option, index) => {
option.addEventListener('click', () => {
slider.dataset.value = index === 0 ? 'yes' : 'no';
});
});
});
// ==========================================
// TAG REMOVAL
// ==========================================
document.querySelectorAll('swp-tag .remove').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
btn.closest('swp-tag').remove();
});
});
// ==========================================
// BOOKING EXCLUSION TOGGLE
// ==========================================
const bookingExclusion = document.getElementById('bookingExclusion');
bookingExclusion.addEventListener('click', () => {
const isExcluded = bookingExclusion.dataset.excluded === 'true';
bookingExclusion.dataset.excluded = isExcluded ? 'false' : 'true';
const icon = bookingExclusion.querySelector('.icon');
const text = bookingExclusion.querySelector('.text');
if (isExcluded) {
icon.textContent = '✓';
text.textContent = 'Booking tilladt';
} else {
icon.textContent = '✕';
text.textContent = 'Udelukket fra booking';
}
});
// ==========================================
// CUSTOMER GROUP DROPDOWN
// ==========================================
const customerGroupSelect = document.getElementById('customerGroupSelect');
const customerGroupDropdown = document.getElementById('customerGroupDropdown');
customerGroupSelect.addEventListener('click', (e) => {
e.stopPropagation();
customerGroupDropdown.classList.toggle('open');
});
document.querySelectorAll('swp-customer-group-option').forEach(option => {
option.addEventListener('click', () => {
// Update selection
document.querySelectorAll('swp-customer-group-option').forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
// Update display
customerGroupSelect.querySelector('.value').textContent = option.textContent;
// Close dropdown
customerGroupDropdown.classList.remove('open');
});
});
// Close dropdown when clicking outside
document.addEventListener('click', () => {
customerGroupDropdown.classList.remove('open');
});
// ==========================================
// RELATION REMOVE
// ==========================================
document.querySelectorAll('swp-relation-remove').forEach(btn => {
btn.addEventListener('click', () => {
btn.closest('swp-relation-item').remove();
});
});
// ==========================================
// SAVE BUTTON
// ==========================================
const saveBtn = document.getElementById('saveBtn');
saveBtn.addEventListener('click', () => {
// Simulate save
saveBtn.textContent = 'Gemt!';
saveBtn.style.background = 'var(--color-green)';
setTimeout(() => {
saveBtn.textContent = 'Gem';
saveBtn.style.background = '';
}, 2000);
});
// ==========================================
// CHART (lazy load)
// ==========================================
let chartLoaded = false;
function loadChart() {
if (chartLoaded) return;
import('https://unpkg.com/@sevenweirdpeople/swp-charting@latest/dist/index.js')
.then(module => {
const { createChart } = module;
createChart(document.getElementById('revenueChart'), {
width: 1100,
height: 200,
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec']
},
series: [
{
name: 'Services',
color: '#00897b',
data: [
{ x: 'Mar', y: 1200 },
{ x: 'Apr', y: 800 },
{ x: 'Jun', y: 1500 },
{ x: 'Aug', y: 1600 },
{ x: 'Sep', y: 750 },
{ x: 'Okt', y: 550 },
{ x: 'Nov', y: 1200 },
{ x: 'Dec', y: 1450 }
]
},
{
name: 'Produkter',
color: '#1976d2',
data: [
{ x: 'Apr', y: 250 },
{ x: 'Jun', y: 180 },
{ x: 'Sep', y: 320 },
{ x: 'Dec', y: 349 }
]
}
],
legend: false
});
chartLoaded = true;
});
}
// Load chart when Økonomi tab is shown
document.querySelector('swp-tab[data-tab="economy"]').addEventListener('click', loadChart);
</script>
</body>
</html>