Enhances IndexedDB service with booking and resource support

Updates IndexedDB database schema to version 2
Adds support for bookings, customers, and resources stores
Includes new serialization methods for booking data
Extends events store with additional indexes for improved querying
This commit is contained in:
Janus C. H. Knudsen 2025-11-16 19:56:31 +01:00
parent 6174dc895e
commit 88cccb3456
6 changed files with 990 additions and 1 deletions

306
wwwroot/data/bookings.json Normal file
View file

@ -0,0 +1,306 @@
[
{
"id": "BOOK001",
"customerId": "CUST001",
"status": "arrived",
"createdAt": "2025-08-05T08:00:00Z",
"services": [
{
"serviceId": "SRV001",
"serviceName": "Klipning og styling",
"baseDuration": 60,
"basePrice": 500,
"customPrice": 500,
"resourceId": "EMP001"
}
],
"totalPrice": 500,
"notes": "Kunde ønsker lidt kortere"
},
{
"id": "BOOK002",
"customerId": "CUST002",
"status": "paid",
"createdAt": "2025-08-05T09:00:00Z",
"services": [
{
"serviceId": "SRV002",
"serviceName": "Hårvask",
"baseDuration": 30,
"basePrice": 100,
"customPrice": 100,
"resourceId": "STUDENT001"
},
{
"serviceId": "SRV003",
"serviceName": "Bundfarve",
"baseDuration": 90,
"basePrice": 800,
"customPrice": 800,
"resourceId": "EMP001"
}
],
"totalPrice": 900,
"notes": "Split booking: Elev laver hårvask, master laver farve"
},
{
"id": "BOOK003",
"customerId": "CUST003",
"status": "created",
"createdAt": "2025-08-05T07:00:00Z",
"services": [
{
"serviceId": "SRV004A",
"serviceName": "Bryllupsfrisure - Del 1",
"baseDuration": 60,
"basePrice": 750,
"customPrice": 750,
"resourceId": "EMP001"
},
{
"serviceId": "SRV004B",
"serviceName": "Bryllupsfrisure - Del 2",
"baseDuration": 60,
"basePrice": 750,
"customPrice": 750,
"resourceId": "EMP002"
}
],
"totalPrice": 1500,
"notes": "Equal-split: To master stylister arbejder sammen"
},
{
"id": "BOOK004",
"customerId": "CUST004",
"status": "arrived",
"createdAt": "2025-08-05T10:00:00Z",
"services": [
{
"serviceId": "SRV005",
"serviceName": "Herreklipning",
"baseDuration": 30,
"basePrice": 350,
"customPrice": 350,
"resourceId": "EMP003"
}
],
"totalPrice": 350
},
{
"id": "BOOK005",
"customerId": "CUST005",
"status": "paid",
"createdAt": "2025-08-05T11:00:00Z",
"services": [
{
"serviceId": "SRV006",
"serviceName": "Balayage langt hår",
"baseDuration": 120,
"basePrice": 1200,
"customPrice": 1200,
"resourceId": "EMP002"
}
],
"totalPrice": 1200,
"notes": "Kunde ønsker naturlig blond tone"
},
{
"id": "BOOK006",
"customerId": "CUST006",
"status": "created",
"createdAt": "2025-08-06T08:00:00Z",
"services": [
{
"serviceId": "SRV007",
"serviceName": "Permanent",
"baseDuration": 90,
"basePrice": 900,
"customPrice": 900,
"resourceId": "EMP004"
}
],
"totalPrice": 900
},
{
"id": "BOOK007",
"customerId": "CUST007",
"status": "arrived",
"createdAt": "2025-08-06T09:00:00Z",
"services": [
{
"serviceId": "SRV008",
"serviceName": "Highlights",
"baseDuration": 90,
"basePrice": 850,
"customPrice": 850,
"resourceId": "EMP001"
},
{
"serviceId": "SRV009",
"serviceName": "Styling",
"baseDuration": 30,
"basePrice": 200,
"customPrice": 200,
"resourceId": "EMP001"
}
],
"totalPrice": 1050,
"notes": "Highlights + styling samme stylist"
},
{
"id": "BOOK008",
"customerId": "CUST008",
"status": "paid",
"createdAt": "2025-08-06T10:00:00Z",
"services": [
{
"serviceId": "SRV010",
"serviceName": "Klipning",
"baseDuration": 45,
"basePrice": 450,
"customPrice": 450,
"resourceId": "EMP004"
}
],
"totalPrice": 450
},
{
"id": "BOOK009",
"customerId": "CUST001",
"status": "created",
"createdAt": "2025-08-07T08:00:00Z",
"services": [
{
"serviceId": "SRV011",
"serviceName": "Farve behandling",
"baseDuration": 120,
"basePrice": 950,
"customPrice": 950,
"resourceId": "EMP002"
}
],
"totalPrice": 950
},
{
"id": "BOOK010",
"customerId": "CUST002",
"status": "arrived",
"createdAt": "2025-08-07T09:00:00Z",
"services": [
{
"serviceId": "SRV012",
"serviceName": "Skæg trimning",
"baseDuration": 20,
"basePrice": 200,
"customPrice": 200,
"resourceId": "EMP003"
}
],
"totalPrice": 200
},
{
"id": "BOOK011",
"customerId": "CUST003",
"status": "paid",
"createdAt": "2025-08-07T10:00:00Z",
"services": [
{
"serviceId": "SRV002",
"serviceName": "Hårvask",
"baseDuration": 30,
"basePrice": 100,
"customPrice": 100,
"resourceId": "STUDENT002"
},
{
"serviceId": "SRV013",
"serviceName": "Ombré",
"baseDuration": 100,
"basePrice": 1100,
"customPrice": 1100,
"resourceId": "EMP002"
}
],
"totalPrice": 1200,
"notes": "Split booking: Student hårvask, master ombré"
},
{
"id": "BOOK012",
"customerId": "CUST004",
"status": "created",
"createdAt": "2025-08-08T08:00:00Z",
"services": [
{
"serviceId": "SRV014",
"serviceName": "Føntørring",
"baseDuration": 30,
"basePrice": 250,
"customPrice": 250,
"resourceId": "STUDENT001"
}
],
"totalPrice": 250
},
{
"id": "BOOK013",
"customerId": "CUST005",
"status": "arrived",
"createdAt": "2025-08-08T09:00:00Z",
"services": [
{
"serviceId": "SRV015",
"serviceName": "Opsætning",
"baseDuration": 60,
"basePrice": 700,
"customPrice": 700,
"resourceId": "EMP004"
}
],
"totalPrice": 700,
"notes": "Fest opsætning"
},
{
"id": "BOOK014",
"customerId": "CUST006",
"status": "created",
"createdAt": "2025-08-09T08:00:00Z",
"services": [
{
"serviceId": "SRV016A",
"serviceName": "Ekstensions - Del 1",
"baseDuration": 90,
"basePrice": 1250,
"customPrice": 1250,
"resourceId": "EMP001"
},
{
"serviceId": "SRV016B",
"serviceName": "Ekstensions - Del 2",
"baseDuration": 90,
"basePrice": 1250,
"customPrice": 1250,
"resourceId": "EMP004"
}
],
"totalPrice": 2500,
"notes": "Equal-split: To stylister arbejder sammen om extensions"
},
{
"id": "BOOK015",
"customerId": "CUST007",
"status": "noshow",
"createdAt": "2025-08-09T09:00:00Z",
"services": [
{
"serviceId": "SRV001",
"serviceName": "Klipning og styling",
"baseDuration": 60,
"basePrice": 500,
"customPrice": 500,
"resourceId": "EMP002"
}
],
"totalPrice": 500,
"notes": "Kunde mødte ikke op"
}
]

View file

@ -0,0 +1,49 @@
[
{
"id": "CUST001",
"name": "Sofie Nielsen",
"phone": "+45 23 45 67 89",
"email": "sofie.nielsen@email.dk"
},
{
"id": "CUST002",
"name": "Emma Andersen",
"phone": "+45 31 24 56 78",
"email": "emma.andersen@email.dk"
},
{
"id": "CUST003",
"name": "Freja Christensen",
"phone": "+45 42 67 89 12",
"email": "freja.christensen@email.dk"
},
{
"id": "CUST004",
"name": "Laura Pedersen",
"phone": "+45 51 98 76 54"
},
{
"id": "CUST005",
"name": "Ida Larsen",
"phone": "+45 29 87 65 43",
"email": "ida.larsen@email.dk"
},
{
"id": "CUST006",
"name": "Caroline Jensen",
"phone": "+45 38 76 54 32",
"email": "caroline.jensen@email.dk"
},
{
"id": "CUST007",
"name": "Mathilde Hansen",
"phone": "+45 47 65 43 21",
"email": "mathilde.hansen@email.dk"
},
{
"id": "CUST008",
"name": "Olivia Sørensen",
"phone": "+45 56 54 32 10",
"email": "olivia.sorensen@email.dk"
}
]

485
wwwroot/data/events.json Normal file
View file

@ -0,0 +1,485 @@
[
{
"id": "EVT001",
"title": "Sofie Nielsen - Klipning og styling",
"start": "2025-08-05T10:00:00Z",
"end": "2025-08-05T11:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK001",
"resourceId": "EMP001",
"customerId": "CUST001"
},
{
"id": "EVT002",
"title": "Emma Andersen - Hårvask",
"start": "2025-08-05T11:00:00Z",
"end": "2025-08-05T11:30:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK002",
"resourceId": "STUDENT001",
"customerId": "CUST002"
},
{
"id": "EVT003",
"title": "Emma Andersen - Bundfarve",
"start": "2025-08-05T11:30:00Z",
"end": "2025-08-05T13:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK002",
"resourceId": "EMP001",
"customerId": "CUST002"
},
{
"id": "EVT004",
"title": "Freja Christensen - Bryllupsfrisure (Camilla)",
"start": "2025-08-05T08:00:00Z",
"end": "2025-08-05T10:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK003",
"resourceId": "EMP001",
"customerId": "CUST003",
"metadata": {
"note": "To stylister arbejder sammen"
}
},
{
"id": "EVT005",
"title": "Freja Christensen - Bryllupsfrisure (Isabella)",
"start": "2025-08-05T08:00:00Z",
"end": "2025-08-05T10:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK003",
"resourceId": "EMP002",
"customerId": "CUST003",
"metadata": {
"note": "To stylister arbejder sammen"
}
},
{
"id": "EVT006",
"title": "Laura Pedersen - Herreklipning",
"start": "2025-08-05T11:00:00Z",
"end": "2025-08-05T11:30:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK004",
"resourceId": "EMP003",
"customerId": "CUST004"
},
{
"id": "EVT007",
"title": "Ida Larsen - Balayage langt hår",
"start": "2025-08-05T13:00:00Z",
"end": "2025-08-05T15:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK005",
"resourceId": "EMP002",
"customerId": "CUST005"
},
{
"id": "EVT008",
"title": "Frokostpause",
"start": "2025-08-05T12:00:00Z",
"end": "2025-08-05T12:30:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP003"
},
{
"id": "EVT009",
"title": "Caroline Jensen - Permanent",
"start": "2025-08-06T09:00:00Z",
"end": "2025-08-06T10:30:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK006",
"resourceId": "EMP004",
"customerId": "CUST006"
},
{
"id": "EVT010",
"title": "Mathilde Hansen - Highlights",
"start": "2025-08-06T10:00:00Z",
"end": "2025-08-06T11:30:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK007",
"resourceId": "EMP001",
"customerId": "CUST007"
},
{
"id": "EVT011",
"title": "Mathilde Hansen - Styling",
"start": "2025-08-06T11:30:00Z",
"end": "2025-08-06T12:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK007",
"resourceId": "EMP001",
"customerId": "CUST007"
},
{
"id": "EVT012",
"title": "Olivia Sørensen - Klipning",
"start": "2025-08-06T13:00:00Z",
"end": "2025-08-06T13:45:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK008",
"resourceId": "EMP004",
"customerId": "CUST008"
},
{
"id": "EVT013",
"title": "Team møde - Salgsmål",
"start": "2025-08-06T08:00:00Z",
"end": "2025-08-06T08:30:00Z",
"type": "meeting",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP001",
"metadata": {
"attendees": ["EMP001", "EMP002", "EMP003", "EMP004"]
}
},
{
"id": "EVT014",
"title": "Frokostpause",
"start": "2025-08-06T12:00:00Z",
"end": "2025-08-06T12:30:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP002"
},
{
"id": "EVT015",
"title": "Sofie Nielsen - Farve behandling",
"start": "2025-08-07T10:00:00Z",
"end": "2025-08-07T12:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK009",
"resourceId": "EMP002",
"customerId": "CUST001"
},
{
"id": "EVT016",
"title": "Emma Andersen - Skæg trimning",
"start": "2025-08-07T09:00:00Z",
"end": "2025-08-07T09:20:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK010",
"resourceId": "EMP003",
"customerId": "CUST002"
},
{
"id": "EVT017",
"title": "Freja Christensen - Hårvask",
"start": "2025-08-07T11:00:00Z",
"end": "2025-08-07T11:30:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK011",
"resourceId": "STUDENT002",
"customerId": "CUST003"
},
{
"id": "EVT018",
"title": "Freja Christensen - Ombré",
"start": "2025-08-07T11:30:00Z",
"end": "2025-08-07T13:10:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK011",
"resourceId": "EMP002",
"customerId": "CUST003"
},
{
"id": "EVT019",
"title": "Frokostpause",
"start": "2025-08-07T12:00:00Z",
"end": "2025-08-07T12:30:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP001"
},
{
"id": "EVT020",
"title": "Laura Pedersen - Føntørring",
"start": "2025-08-08T09:00:00Z",
"end": "2025-08-08T09:30:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK012",
"resourceId": "STUDENT001",
"customerId": "CUST004"
},
{
"id": "EVT021",
"title": "Ida Larsen - Opsætning",
"start": "2025-08-08T10:00:00Z",
"end": "2025-08-08T11:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK013",
"resourceId": "EMP004",
"customerId": "CUST005"
},
{
"id": "EVT022",
"title": "Produktleverance møde",
"start": "2025-08-08T08:00:00Z",
"end": "2025-08-08T08:30:00Z",
"type": "meeting",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP001",
"metadata": {
"attendees": ["EMP001", "EMP004"]
}
},
{
"id": "EVT023",
"title": "Frokostpause",
"start": "2025-08-08T12:00:00Z",
"end": "2025-08-08T12:30:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP004"
},
{
"id": "EVT024",
"title": "Caroline Jensen - Ekstensions (Camilla)",
"start": "2025-08-09T09:00:00Z",
"end": "2025-08-09T12:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK014",
"resourceId": "EMP001",
"customerId": "CUST006",
"metadata": {
"note": "To stylister arbejder sammen"
}
},
{
"id": "EVT025",
"title": "Caroline Jensen - Ekstensions (Viktor)",
"start": "2025-08-09T09:00:00Z",
"end": "2025-08-09T12:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK014",
"resourceId": "EMP004",
"customerId": "CUST006",
"metadata": {
"note": "To stylister arbejder sammen"
}
},
{
"id": "EVT026",
"title": "Mathilde Hansen - Klipning og styling",
"start": "2025-08-09T10:00:00Z",
"end": "2025-08-09T11:00:00Z",
"type": "customer",
"allDay": false,
"syncStatus": "synced",
"bookingId": "BOOK015",
"resourceId": "EMP002",
"customerId": "CUST007",
"metadata": {
"note": "NOSHOW - kunde mødte ikke op"
}
},
{
"id": "EVT027",
"title": "Ferie - Spanien",
"start": "2025-08-10T00:00:00Z",
"end": "2025-08-17T23:59:59Z",
"type": "vacation",
"allDay": true,
"syncStatus": "synced",
"resourceId": "EMP003",
"metadata": {
"destination": "Mallorca"
}
},
{
"id": "EVT028",
"title": "Frokostpause",
"start": "2025-08-09T12:00:00Z",
"end": "2025-08-09T12:30:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP002"
},
{
"id": "EVT029",
"title": "Kaffepause",
"start": "2025-08-05T14:00:00Z",
"end": "2025-08-05T14:15:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP004"
},
{
"id": "EVT030",
"title": "Kursus - Nye farvningsteknikker",
"start": "2025-08-11T09:00:00Z",
"end": "2025-08-11T16:00:00Z",
"type": "meeting",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP001",
"metadata": {
"location": "København",
"type": "external_course"
}
},
{
"id": "EVT031",
"title": "Supervision - Elev",
"start": "2025-08-05T15:00:00Z",
"end": "2025-08-05T15:30:00Z",
"type": "meeting",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP001",
"metadata": {
"attendees": ["EMP001", "STUDENT001"]
}
},
{
"id": "EVT032",
"title": "Aftensmad pause",
"start": "2025-08-06T17:00:00Z",
"end": "2025-08-06T17:30:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP001"
},
{
"id": "EVT033",
"title": "Supervision - Elev",
"start": "2025-08-07T15:00:00Z",
"end": "2025-08-07T15:30:00Z",
"type": "meeting",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP002",
"metadata": {
"attendees": ["EMP002", "STUDENT002"]
}
},
{
"id": "EVT034",
"title": "Rengøring af arbejdsstation",
"start": "2025-08-08T16:00:00Z",
"end": "2025-08-08T16:30:00Z",
"type": "blocked",
"allDay": false,
"syncStatus": "synced",
"resourceId": "STUDENT001"
},
{
"id": "EVT035",
"title": "Rengøring af arbejdsstation",
"start": "2025-08-08T16:00:00Z",
"end": "2025-08-08T16:30:00Z",
"type": "blocked",
"allDay": false,
"syncStatus": "synced",
"resourceId": "STUDENT002"
},
{
"id": "EVT036",
"title": "Leverandør møde",
"start": "2025-08-09T14:00:00Z",
"end": "2025-08-09T15:00:00Z",
"type": "meeting",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP004",
"metadata": {
"attendees": ["EMP004"]
}
},
{
"id": "EVT037",
"title": "Sygedag",
"start": "2025-08-12T00:00:00Z",
"end": "2025-08-12T23:59:59Z",
"type": "vacation",
"allDay": true,
"syncStatus": "synced",
"resourceId": "STUDENT001",
"metadata": {
"reason": "sick_leave"
}
},
{
"id": "EVT038",
"title": "Frokostpause",
"start": "2025-08-05T12:00:00Z",
"end": "2025-08-05T12:30:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "STUDENT001"
},
{
"id": "EVT039",
"title": "Frokostpause",
"start": "2025-08-05T12:00:00Z",
"end": "2025-08-05T12:30:00Z",
"type": "break",
"allDay": false,
"syncStatus": "synced",
"resourceId": "STUDENT002"
},
{
"id": "EVT040",
"title": "Morgen briefing",
"start": "2025-08-05T08:30:00Z",
"end": "2025-08-05T08:45:00Z",
"type": "meeting",
"allDay": false,
"syncStatus": "synced",
"resourceId": "EMP004",
"metadata": {
"attendees": ["EMP001", "EMP002", "EMP003", "EMP004", "STUDENT001", "STUDENT002"]
}
}
]

View file

@ -0,0 +1,80 @@
[
{
"id": "EMP001",
"name": "camilla.jensen",
"displayName": "Camilla Jensen",
"type": "person",
"avatarUrl": "/avatars/camilla.jpg",
"color": "#9c27b0",
"isActive": true,
"metadata": {
"role": "master stylist",
"specialties": ["balayage", "color", "bridal"]
}
},
{
"id": "EMP002",
"name": "isabella.hansen",
"displayName": "Isabella Hansen",
"type": "person",
"avatarUrl": "/avatars/isabella.jpg",
"color": "#e91e63",
"isActive": true,
"metadata": {
"role": "master stylist",
"specialties": ["highlights", "ombre", "styling"]
}
},
{
"id": "EMP003",
"name": "alexander.nielsen",
"displayName": "Alexander Nielsen",
"type": "person",
"avatarUrl": "/avatars/alexander.jpg",
"color": "#3f51b5",
"isActive": true,
"metadata": {
"role": "master stylist",
"specialties": ["men's cuts", "beard", "fade"]
}
},
{
"id": "EMP004",
"name": "viktor.andersen",
"displayName": "Viktor Andersen",
"type": "person",
"avatarUrl": "/avatars/viktor.jpg",
"color": "#009688",
"isActive": true,
"metadata": {
"role": "stylist",
"specialties": ["cuts", "styling", "perms"]
}
},
{
"id": "STUDENT001",
"name": "line.pedersen",
"displayName": "Line Pedersen (Elev)",
"type": "person",
"avatarUrl": "/avatars/line.jpg",
"color": "#8bc34a",
"isActive": true,
"metadata": {
"role": "student",
"specialties": ["wash", "blow-dry", "basic cuts"]
}
},
{
"id": "STUDENT002",
"name": "mads.larsen",
"displayName": "Mads Larsen (Elev)",
"type": "person",
"avatarUrl": "/avatars/mads.jpg",
"color": "#ff9800",
"isActive": true,
"metadata": {
"role": "student",
"specialties": ["wash", "styling assistance"]
}
}
]