namespace PlanTempus.Application.Features.Services.Components;
///
/// Shared catalog for service detail data.
/// Used by all ServiceDetail* ViewComponents.
///
public static class ServiceDetailCatalog
{
private static readonly Dictionary Services = new()
{
["service-1"] = new ServiceDetailRecord
{
Key = "service-1",
Name = "Klip & Farve",
Category = "Kombi-behandlinger",
CalendarColor = "deep-orange",
IsActive = true,
DurationRange = "60-120",
FromPrice = "795 kr",
EmployeeCount = "4",
BookingsThisYear = "156",
Tags = new() { new("Populær", "popular"), new("Kombi", "combo"), new("Farve", "color") },
InternalNotes = "Komplet farvebehandling med klip. Husk konsultation ved første besøg. Anbefal Olaplex til kemisk behandlet hår.",
CanBookAsMain = true,
CanBookAsAddon = false,
ShowInOnlineBooking = true,
IsFeatured = false,
Description = "Forkæl dig selv med en komplet forvandling! Vores Klip & Farve behandling inkluderer professionel farverådgivning, farvning tilpasset din hudtone, præcisionsklip og styling. Perfekt til dig der ønsker et helt nyt look.",
// Priser
PriceMode = PriceMode.Matrix,
PriceMatrix = new()
{
new("Junior", "795", "895", "995", "1.095"),
new("Senior", "895", "995", "1.095", "1.195"),
new("Master", "995", "1.095", "1.195", "1.295")
},
VatRate = "25",
ProductCost = "85 kr",
Commission = "standard",
MemberDiscount = true,
GiftCardPayment = true,
LoyaltyPoints = true,
// Varighed
DurationVariants = new()
{
new("Kort hår", 60),
new("Mellem hår", 90),
new("Langt hår", 120),
new("Ekstra langt hår", 150)
},
BufferBefore = "15",
BufferAfter = "10",
CleanupTime = "5",
// Regler
MinNotice = "24",
MaxAdvanceBooking = "3",
CancellationDeadline = "24",
NoShowFee = "50",
RequiresConsultation = false,
RequiresPatchTest = true,
AgeRestriction = false,
ShowInOnlineBookingRules = true,
AllowEmployeeSelection = true,
ShowPrice = true,
ShowDuration = true,
// Medarbejdere
Employees = new()
{
new("emp-1", "Anna Sørensen", "AS", "Master Stylist", "master", true, "Standard"),
new("emp-2", "Mette Jensen", "MJ", "Senior Stylist", "senior", true, "+15 min"),
new("emp-3", "Louise Nielsen", "LN", "Senior Stylist", "senior", true, "Standard"),
new("emp-4", "Katrine Pedersen", "KP", "Stylist", "junior", true, "+15 min"),
new("emp-5", "Sofie Andersen", "SA", "Junior Stylist", "junior", false, "—", "Ikke certificeret")
},
Availability = new()
{
new("Mandag", true, "08:00", "18:00"),
new("Tirsdag", true, "08:00", "18:00"),
new("Onsdag", true, "08:00", "18:00"),
new("Torsdag", true, "08:00", "12:00"),
new("Fredag", true, "08:00", "18:00"),
new("Lørdag", false, "08:00", "18:00"),
new("Søndag", false, "08:00", "18:00")
},
// Tilvalg
Addons = new()
{
new("addon-1", "Olaplex Behandling", "+250 kr", "+15 min", "Valgfri", true),
new("addon-2", "Kerastase Hårkur", "+195 kr", "+10 min", "Valgfri", true),
new("addon-3", "Styling / Curls", "+150 kr", "+20 min", "Valgfri", true),
new("addon-4", "Hovedbundsmassage", "+75 kr", "+5 min", "Valgfri", true),
new("addon-5", "Patch Test", "Gratis", "48t før", "Påkrævet (nye)", false, true)
}
},
["service-2"] = new ServiceDetailRecord
{
Key = "service-2",
Name = "Herreklip",
Category = "Klip",
CalendarColor = "blue",
IsActive = true,
DurationRange = "30",
FromPrice = "295 kr",
EmployeeCount = "6",
BookingsThisYear = "312",
Tags = new() { new("Populær", "popular") },
InternalNotes = "Standard herreklip. Inkluderer vask og styling.",
CanBookAsMain = true,
CanBookAsAddon = false,
ShowInOnlineBooking = true,
IsFeatured = true,
Description = "Klassisk herreklip med vask, klip og styling. Vores erfarne stylister sikrer dig et skarpt og velplejet look."
},
["service-3"] = new ServiceDetailRecord
{
Key = "service-3",
Name = "Dameklip",
Category = "Klip",
CalendarColor = "teal",
IsActive = true,
DurationRange = "45-60",
FromPrice = "395 kr",
EmployeeCount = "5",
BookingsThisYear = "248",
Tags = new() { new("Populær", "popular") },
InternalNotes = "Standard dameklip. Altid konsultation først.",
CanBookAsMain = true,
CanBookAsAddon = false,
ShowInOnlineBooking = true,
IsFeatured = true,
Description = "Professionel dameklip tilpasset din ansigtsform og ønsker. Inkluderer vask, klip og føn."
},
["service-4"] = new ServiceDetailRecord
{
Key = "service-4",
Name = "Balayage",
Category = "Farve",
CalendarColor = "purple",
IsActive = true,
DurationRange = "120-180",
FromPrice = "1.295 kr",
EmployeeCount = "3",
BookingsThisYear = "89",
Tags = new() { new("Farve", "color"), new("Premium", "popular") },
InternalNotes = "Avanceret farveteknik. Kun certificerede stylister. Kræver tid til konsultation.",
CanBookAsMain = true,
CanBookAsAddon = false,
ShowInOnlineBooking = true,
IsFeatured = false,
Description = "Smuk, naturlig farveeffekt med håndmalede highlights. Perfekt til dig der ønsker et solkysset look med lavt vedligehold."
},
["service-5"] = new ServiceDetailRecord
{
Key = "service-5",
Name = "Olaplex Behandling",
Category = "Behandlinger",
CalendarColor = "green",
IsActive = true,
DurationRange = "30",
FromPrice = "295 kr",
EmployeeCount = "6",
BookingsThisYear = "134",
Tags = new() { new("Tilvalg", "combo") },
InternalNotes = "Kan tilføjes til alle farvebehandlinger. Anbefales ved kemisk behandlet hår.",
CanBookAsMain = false,
CanBookAsAddon = true,
ShowInOnlineBooking = true,
IsFeatured = false,
Description = "Intensiv hårbehandling der reparerer og styrker håret. Ideel som tilvalg til farvebehandlinger."
},
["service-6"] = new ServiceDetailRecord
{
Key = "service-6",
Name = "Bryllupsfrisure",
Category = "Styling",
CalendarColor = "amber",
IsActive = false,
DurationRange = "90-120",
FromPrice = "895 kr",
EmployeeCount = "2",
BookingsThisYear = "24",
Tags = new() { new("Premium", "popular"), new("Sæson", "combo") },
InternalNotes = "Kun Maria og Anna kan bookes til dette. Kræver prøve-session 2 uger før.",
CanBookAsMain = true,
CanBookAsAddon = false,
ShowInOnlineBooking = false,
IsFeatured = false,
Description = "Eksklusiv bryllupsfrisure med forudgående konsultation og prøvesession. Vi skaber din drømmefrisure til den store dag."
}
};
public static ServiceDetailRecord Get(string key)
{
if (!Services.TryGetValue(key, out var service))
throw new KeyNotFoundException($"Service with key '{key}' not found");
return service;
}
public static IEnumerable AllKeys => Services.Keys;
}
///
/// Complete service detail record used across all detail ViewComponents.
///
public record ServiceDetailRecord
{
// Identity
public required string Key { get; init; }
public required string Name { get; init; }
public required string Category { get; init; }
public required string CalendarColor { get; init; }
public required bool IsActive { get; init; }
// Stats (header)
public required string DurationRange { get; init; }
public required string FromPrice { get; init; }
public required string EmployeeCount { get; init; }
public required string BookingsThisYear { get; init; }
// Tags
public List Tags { get; init; } = new();
// Generelt tab - Grundlæggende
public required string InternalNotes { get; init; }
// Generelt tab - Bookingtype
public required bool CanBookAsMain { get; init; }
public required bool CanBookAsAddon { get; init; }
// Generelt tab - Online booking
public required bool ShowInOnlineBooking { get; init; }
public required bool IsFeatured { get; init; }
public required string Description { get; init; }
// Priser tab
public PriceMode PriceMode { get; init; } = PriceMode.Simple;
public string SimplePrice { get; init; } = "995 kr";
public List PriceMatrix { get; init; } = new();
public string VatRate { get; init; } = "25";
public string ProductCost { get; init; } = "85 kr";
public string Commission { get; init; } = "standard";
public bool MemberDiscount { get; init; } = true;
public bool GiftCardPayment { get; init; } = true;
public bool LoyaltyPoints { get; init; } = true;
// Varighed tab
public List DurationVariants { get; init; } = new();
public string BufferBefore { get; init; } = "15";
public string BufferAfter { get; init; } = "10";
public string CleanupTime { get; init; } = "5";
// Regler tab
public string MinNotice { get; init; } = "24";
public string MaxAdvanceBooking { get; init; } = "3";
public string CancellationDeadline { get; init; } = "24";
public string NoShowFee { get; init; } = "50";
public bool RequiresConsultation { get; init; } = false;
public bool RequiresPatchTest { get; init; } = false;
public bool AgeRestriction { get; init; } = false;
public bool ShowInOnlineBookingRules { get; init; } = true;
public bool AllowEmployeeSelection { get; init; } = true;
public bool ShowPrice { get; init; } = true;
public bool ShowDuration { get; init; } = true;
// Medarbejdere tab
public List Employees { get; init; } = new();
public List Availability { get; init; } = new();
// Tilvalg tab
public List Addons { get; init; } = new();
}
public enum PriceMode { Simple, Matrix }
public record PriceMatrixRow(string Level, string ShortHair, string MediumHair, string LongHair, string ExtraLongHair);
public record DurationVariant(string Name, int Minutes);
public record ServiceTag(string Text, string CssClass);
public record ServiceEmployee(
string Id,
string Name,
string Initials,
string Level,
string LevelCssClass,
bool Selected,
string OverrideValue,
string? Warning = null);
public record ServiceAddon(
string Id,
string Name,
string Price,
string Duration,
string Type,
bool Selected,
bool Required = false);
public record ServiceAvailability(
string Day,
bool Enabled,
string StartTime,
string EndTime);