Adds new components for service employees and addons Introduces detailed views with selectable employees and add-ons Updates localization translations for new sections Implements time range slider functionality for availability
304 lines
12 KiB
C#
304 lines
12 KiB
C#
namespace PlanTempus.Application.Features.Services.Components;
|
|
|
|
/// <summary>
|
|
/// Shared catalog for service detail data.
|
|
/// Used by all ServiceDetail* ViewComponents.
|
|
/// </summary>
|
|
public static class ServiceDetailCatalog
|
|
{
|
|
private static readonly Dictionary<string, ServiceDetailRecord> 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<string> AllKeys => Services.Keys;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Complete service detail record used across all detail ViewComponents.
|
|
/// </summary>
|
|
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<ServiceTag> 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<PriceMatrixRow> 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<DurationVariant> 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<ServiceEmployee> Employees { get; init; } = new();
|
|
public List<ServiceAvailability> Availability { get; init; } = new();
|
|
|
|
// Tilvalg tab
|
|
public List<ServiceAddon> 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);
|