import { useState } from “react”; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell, Legend, LabelList, } from “recharts”; // โ”€โ”€ KPI DATA โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const KPI = { “Bri Foster”: { October: {appt:129,invoices:129,totalSales:6836.75,avgInvoice:53,guests:100,newGuestPct:28,rebookedPct:0,newGuests:28,svcQty:199,svcSales:6836.75,avgSvcVal:53,saleCount:199,svcSalesCount:199,svcInvoiceCount:129,prodInvoiceCount:0,prodSalesCount:0,prodSales:0,boughtProdPct:0,avgProdVal:0,prodSvcPct:0,prodTotalPct:0,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:0}, November: {appt:110,invoices:123,totalSales:31313.42,avgInvoice:254.58,guests:100,newGuestPct:20,rebookedPct:2.73,newGuests:20,svcQty:163,svcSales:15102.16,avgSvcVal:134.84,saleCount:185,svcSalesCount:167,svcInvoiceCount:112,prodInvoiceCount:4,prodSalesCount:8,prodSales:842,boughtProdPct:2.68,avgProdVal:210.5,prodSvcPct:5.58,prodTotalPct:2.69,memberSales:0,memberCount:0,pkgSales:13644.26,pkgCount:9,gcSales:0,gcCount:0,prepaidSales:1725,prepaidCount:1,campaignRedemptions:0,avgFeedback:4.5,cancelled:6}, December: {appt:103,invoices:112,totalSales:23830.64,avgInvoice:212.77,guests:95,newGuestPct:22.11,rebookedPct:13.59,newGuests:21,svcQty:117,svcSales:16593.64,avgSvcVal:158.03,saleCount:141,svcSalesCount:117,svcInvoiceCount:105,prodInvoiceCount:7,prodSalesCount:18,prodSales:913,boughtProdPct:3.81,avgProdVal:130.43,prodSvcPct:5.5,prodTotalPct:3.83,memberSales:0,memberCount:0,pkgSales:4324,pkgCount:3,gcSales:0,gcCount:0,prepaidSales:2000,prepaidCount:3,campaignRedemptions:3,avgFeedback:5,cancelled:9}, January: {appt:117,invoices:126,totalSales:22852.36,avgInvoice:181.37,guests:107,newGuestPct:30.84,rebookedPct:38.46,newGuests:33,svcQty:131,svcSales:16420.83,avgSvcVal:140.35,saleCount:150,svcSalesCount:131,svcInvoiceCount:117,prodInvoiceCount:11,prodSalesCount:14,prodSales:1129.03,boughtProdPct:5.13,avgProdVal:102.64,prodSvcPct:6.88,prodTotalPct:4.94,memberSales:0,memberCount:0,pkgSales:5302.5,pkgCount:5,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:5,cancelled:19}, February: {appt:93,invoices:100,totalSales:26604.5,avgInvoice:266.04,guests:85,newGuestPct:20,rebookedPct:56.99,newGuests:17,svcQty:106,svcSales:18033.8,avgSvcVal:193.91,saleCount:117,svcSalesCount:106,svcInvoiceCount:93,prodInvoiceCount:4,prodSalesCount:5,prodSales:445.7,boughtProdPct:3.23,avgProdVal:111.42,prodSvcPct:2.47,prodTotalPct:1.68,memberSales:0,memberCount:0,pkgSales:8125,pkgCount:6,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:26}, March: {appt:82,invoices:93,totalSales:24917.22,avgInvoice:267.93,guests:80,newGuestPct:12.5,rebookedPct:51.22,newGuests:10,svcQty:95,svcSales:16346.12,avgSvcVal:199.34,saleCount:115,svcSalesCount:95,svcInvoiceCount:82,prodInvoiceCount:10,prodSalesCount:15,prodSales:844.6,boughtProdPct:3.66,avgProdVal:84.46,prodSvcPct:5.17,prodTotalPct:3.39,memberSales:0,memberCount:0,pkgSales:7676.5,pkgCount:4,gcSales:0,gcCount:0,prepaidSales:50,prepaidCount:1,campaignRedemptions:0,avgFeedback:0,cancelled:34}, April: {appt:20,invoices:23,totalSales:6112.05,avgInvoice:265.74,guests:22,newGuestPct:18.18,rebookedPct:55,newGuests:4,svcQty:21,svcSales:3944.05,avgSvcVal:197.2,saleCount:37,svcSalesCount:21,svcInvoiceCount:20,prodInvoiceCount:5,prodSalesCount:14,prodSales:1008,boughtProdPct:15,avgProdVal:201.6,prodSvcPct:25.56,prodTotalPct:16.49,memberSales:0,memberCount:0,pkgSales:1102.5,pkgCount:1,gcSales:0,gcCount:0,prepaidSales:57.5,prepaidCount:1,campaignRedemptions:1,avgFeedback:0,cancelled:6}, May: {appt:26,invoices:29,totalSales:9834.6,avgInvoice:339.12,guests:26,newGuestPct:11.54,rebookedPct:57.69,newGuests:3,svcQty:31,svcSales:4500,avgSvcVal:173.08,saleCount:31,svcSalesCount:31,svcInvoiceCount:26,prodInvoiceCount:2,prodSalesCount:4,prodSales:249.6,boughtProdPct:3.85,avgProdVal:124.8,prodSvcPct:5.55,prodTotalPct:2.54,memberSales:0,memberCount:0,pkgSales:5085,pkgCount:2,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:9}, }, “Josie Raymond”: { October: {appt:139,invoices:139,totalSales:13534.56,avgInvoice:97.37,guests:104,newGuestPct:18.27,rebookedPct:0,newGuests:19,svcQty:216,svcSales:13534.56,avgSvcVal:97.37,saleCount:216,svcSalesCount:216,svcInvoiceCount:139,prodInvoiceCount:0,prodSalesCount:0,prodSales:0,boughtProdPct:0,avgProdVal:0,prodSvcPct:0,prodTotalPct:0,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:0}, November: {appt:109,invoices:119,totalSales:39576.24,avgInvoice:332.57,guests:90,newGuestPct:12.22,rebookedPct:6.42,newGuests:11,svcQty:160,svcSales:22402.68,avgSvcVal:205.53,saleCount:186,svcSalesCount:164,svcInvoiceCount:109,prodInvoiceCount:7,prodSalesCount:10,prodSales:629.5,boughtProdPct:5.5,avgProdVal:89.93,prodSvcPct:2.81,prodTotalPct:1.59,memberSales:0,memberCount:0,pkgSales:13158.75,pkgCount:10,gcSales:0,gcCount:0,prepaidSales:3385.31,prepaidCount:2,campaignRedemptions:0,avgFeedback:5,cancelled:3}, December: {appt:107,invoices:117,totalSales:35275.42,avgInvoice:301.5,guests:99,newGuestPct:16.16,rebookedPct:17.76,newGuests:16,svcQty:122,svcSales:16891.73,avgSvcVal:156.4,saleCount:150,svcSalesCount:122,svcInvoiceCount:108,prodInvoiceCount:9,prodSalesCount:12,prodSales:993.61,boughtProdPct:5.56,avgProdVal:110.4,prodSvcPct:5.88,prodTotalPct:2.82,memberSales:0,memberCount:0,pkgSales:7355.2,pkgCount:5,gcSales:0,gcCount:0,prepaidSales:10034.88,prepaidCount:11,campaignRedemptions:1,avgFeedback:5,cancelled:11}, January: {appt:111,invoices:120,totalSales:33103.85,avgInvoice:275.87,guests:101,newGuestPct:19.8,rebookedPct:50.45,newGuests:20,svcQty:129,svcSales:22255.6,avgSvcVal:200.5,saleCount:164,svcSalesCount:129,svcInvoiceCount:111,prodInvoiceCount:15,prodSalesCount:29,prodSales:2921,boughtProdPct:9.91,avgProdVal:194.73,prodSvcPct:13.12,prodTotalPct:8.82,memberSales:0,memberCount:0,pkgSales:7875.5,pkgCount:5,gcSales:0,gcCount:0,prepaidSales:51.75,prepaidCount:1,campaignRedemptions:0,avgFeedback:5,cancelled:17}, February: {appt:82,invoices:89,totalSales:27094.62,avgInvoice:304.43,guests:79,newGuestPct:17.72,rebookedPct:58.54,newGuests:14,svcQty:101,svcSales:17189.97,avgSvcVal:207.11,saleCount:159,svcSalesCount:101,svcInvoiceCount:83,prodInvoiceCount:12,prodSalesCount:55,prodSales:1773.15,boughtProdPct:9.64,avgProdVal:147.76,prodSvcPct:10.32,prodTotalPct:6.54,memberSales:426,memberCount:1,pkgSales:7705.5,pkgCount:2,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:5,cancelled:18}, March: {appt:127,invoices:139,totalSales:41487.36,avgInvoice:298.47,guests:117,newGuestPct:17.95,rebookedPct:53.54,newGuests:21,svcQty:158,svcSales:28149.71,avgSvcVal:221.65,saleCount:203,svcSalesCount:158,svcInvoiceCount:127,prodInvoiceCount:19,prodSalesCount:41,prodSales:4704.75,boughtProdPct:8.66,avgProdVal:247.62,prodSvcPct:16.71,prodTotalPct:11.34,memberSales:0,memberCount:0,pkgSales:8632.9,pkgCount:4,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:4,avgFeedback:5,cancelled:32}, April: {appt:45,invoices:48,totalSales:11284.71,avgInvoice:235.1,guests:45,newGuestPct:13.33,rebookedPct:57.78,newGuests:6,svcQty:51,svcSales:9450.71,avgSvcVal:210.02,saleCount:60,svcSalesCount:51,svcInvoiceCount:45,prodInvoiceCount:3,prodSalesCount:8,prodSales:934,boughtProdPct:2.22,avgProdVal:311.33,prodSvcPct:9.88,prodTotalPct:8.28,memberSales:0,memberCount:0,pkgSales:900,pkgCount:1,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:12}, May: {appt:39,invoices:40,totalSales:9102.24,avgInvoice:227.56,guests:40,newGuestPct:17.5,rebookedPct:53.85,newGuests:7,svcQty:47,svcSales:7955.54,avgSvcVal:203.99,saleCount:47,svcSalesCount:47,svcInvoiceCount:39,prodInvoiceCount:4,prodSalesCount:10,prodSales:1146.7,boughtProdPct:7.69,avgProdVal:286.68,prodSvcPct:14.41,prodTotalPct:12.6,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:7}, }, “Kasi Holden”: { October: {appt:36,invoices:36,totalSales:1135,avgInvoice:31.53,guests:32,newGuestPct:6.25,rebookedPct:0,newGuests:2,svcQty:48,svcSales:1135,avgSvcVal:31.53,saleCount:48,svcSalesCount:48,svcInvoiceCount:36,prodInvoiceCount:0,prodSalesCount:0,prodSales:0,boughtProdPct:0,avgProdVal:0,prodSvcPct:0,prodTotalPct:0,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:0}, November: {appt:34,invoices:61,totalSales:22052.26,avgInvoice:361.51,guests:47,newGuestPct:17.02,rebookedPct:8.82,newGuests:8,svcQty:40,svcSales:2499.01,avgSvcVal:71.4,saleCount:85,svcSalesCount:41,svcInvoiceCount:35,prodInvoiceCount:13,prodSalesCount:27,prodSales:2930.3,boughtProdPct:2.86,avgProdVal:225.41,prodSvcPct:117.26,prodTotalPct:13.29,memberSales:349,memberCount:2,pkgSales:11795.5,pkgCount:8,gcSales:230,gcCount:1,prepaidSales:4248.45,prepaidCount:6,campaignRedemptions:7,avgFeedback:0,cancelled:1}, December: {appt:21,invoices:79,totalSales:24460.85,avgInvoice:309.63,guests:69,newGuestPct:15.94,rebookedPct:23.81,newGuests:11,svcQty:22,svcSales:2132.34,avgSvcVal:101.54,saleCount:140,svcSalesCount:22,svcInvoiceCount:21,prodInvoiceCount:35,prodSalesCount:92,prodSales:7323.25,boughtProdPct:19.05,avgProdVal:209.24,prodSvcPct:343.44,prodTotalPct:29.94,memberSales:0,memberCount:0,pkgSales:1032,pkgCount:2,gcSales:2050,gcCount:8,prepaidSales:11923.26,prepaidCount:16,campaignRedemptions:5,avgFeedback:5,cancelled:2}, January: {appt:28,invoices:47,totalSales:16718.65,avgInvoice:355.72,guests:40,newGuestPct:7.5,rebookedPct:46.43,newGuests:3,svcQty:30,svcSales:2541,avgSvcVal:90.75,saleCount:64,svcSalesCount:30,svcInvoiceCount:28,prodInvoiceCount:17,prodSalesCount:27,prodSales:2522.05,boughtProdPct:10.71,avgProdVal:148.36,prodSvcPct:99.25,prodTotalPct:15.09,memberSales:499,memberCount:1,pkgSales:5546.8,pkgCount:3,gcSales:0,gcCount:0,prepaidSales:5609.8,prepaidCount:3,campaignRedemptions:71,avgFeedback:0,cancelled:2}, February: {appt:28,invoices:39,totalSales:6707.26,avgInvoice:171.98,guests:30,newGuestPct:3.33,rebookedPct:64.29,newGuests:1,svcQty:29,svcSales:3680.36,avgSvcVal:131.44,saleCount:44,svcSalesCount:29,svcInvoiceCount:28,prodInvoiceCount:10,prodSalesCount:14,prodSales:1403.5,boughtProdPct:7.14,avgProdVal:140.35,prodSvcPct:38.13,prodTotalPct:20.93,memberSales:0,memberCount:0,pkgSales:1623.4,pkgCount:1,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:57,avgFeedback:0,cancelled:9}, March: {appt:31,invoices:41,totalSales:10364.2,avgInvoice:252.79,guests:34,newGuestPct:8.82,rebookedPct:70.97,newGuests:3,svcQty:33,svcSales:5422.05,avgSvcVal:174.9,saleCount:57,svcSalesCount:33,svcInvoiceCount:31,prodInvoiceCount:14,prodSalesCount:22,prodSales:2942.15,boughtProdPct:19.35,avgProdVal:210.15,prodSvcPct:54.26,prodTotalPct:28.39,memberSales:0,memberCount:0,pkgSales:1000,pkgCount:1,gcSales:0,gcCount:0,prepaidSales:1000,prepaidCount:1,campaignRedemptions:31,avgFeedback:0,cancelled:5}, April: {appt:5,invoices:13,totalSales:1915.25,avgInvoice:147.33,guests:11,newGuestPct:9.09,rebookedPct:40,newGuests:1,svcQty:7,svcSales:550,avgSvcVal:110,saleCount:27,svcSalesCount:7,svcInvoiceCount:5,prodInvoiceCount:7,prodSalesCount:19,prodSales:807.75,boughtProdPct:20,avgProdVal:115.39,prodSvcPct:146.86,prodTotalPct:42.17,memberSales:0,memberCount:0,pkgSales:-500,pkgCount:-1,gcSales:0,gcCount:0,prepaidSales:1057.5,prepaidCount:2,campaignRedemptions:0,avgFeedback:0,cancelled:2}, May: {appt:5,invoices:6,totalSales:2037,avgInvoice:339.5,guests:6,newGuestPct:0,rebookedPct:20,newGuests:0,svcQty:6,svcSales:1908,avgSvcVal:381.6,saleCount:6,svcSalesCount:6,svcInvoiceCount:5,prodInvoiceCount:2,prodSalesCount:2,prodSales:129,boughtProdPct:20,avgProdVal:64.5,prodSvcPct:6.76,prodTotalPct:6.33,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:29,avgFeedback:0,cancelled:1}, }, “Katie Sturgeon”: { October: {appt:89,invoices:89,totalSales:4393.63,avgInvoice:49.37,guests:71,newGuestPct:63.38,rebookedPct:0,newGuests:45,svcQty:92,svcSales:4393.63,avgSvcVal:49.37,saleCount:92,svcSalesCount:92,svcInvoiceCount:89,prodInvoiceCount:0,prodSalesCount:0,prodSales:0,boughtProdPct:0,avgProdVal:0,prodSvcPct:0,prodTotalPct:0,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:0}, November: {appt:88,invoices:89,totalSales:7200.75,avgInvoice:80.91,guests:68,newGuestPct:32.35,rebookedPct:0,newGuests:22,svcQty:94,svcSales:7200.75,avgSvcVal:80.91,saleCount:178,svcSalesCount:178,svcInvoiceCount:89,prodInvoiceCount:0,prodSalesCount:0,prodSales:0,boughtProdPct:0,avgProdVal:0,prodSvcPct:0,prodTotalPct:0,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:1}, December: {appt:21,invoices:25,totalSales:1346.46,avgInvoice:53.86,guests:20,newGuestPct:25,rebookedPct:28.57,newGuests:5,svcQty:21,svcSales:1169.66,avgSvcVal:50.85,saleCount:123,svcSalesCount:121,svcInvoiceCount:23,prodInvoiceCount:2,prodSalesCount:2,prodSales:176.8,boughtProdPct:0,avgProdVal:88.4,prodSvcPct:15.12,prodTotalPct:13.13,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:5,cancelled:7}, January: {appt:48,invoices:55,totalSales:5057.94,avgInvoice:91.96,guests:43,newGuestPct:48.84,rebookedPct:22.92,newGuests:21,svcQty:50,svcSales:4101.5,avgSvcVal:83.7,saleCount:343,svcSalesCount:332,svcInvoiceCount:49,prodInvoiceCount:6,prodSalesCount:11,prodSales:956.44,boughtProdPct:0,avgProdVal:159.41,prodSvcPct:23.32,prodTotalPct:18.91,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:4,avgFeedback:5,cancelled:13}, February: {appt:36,invoices:41,totalSales:6534.67,avgInvoice:159.38,guests:32,newGuestPct:34.38,rebookedPct:52.78,newGuests:11,svcQty:36,svcSales:4148.67,avgSvcVal:115.24,saleCount:291,svcSalesCount:276,svcInvoiceCount:36,prodInvoiceCount:6,prodSalesCount:12,prodSales:1048,boughtProdPct:5.56,avgProdVal:174.67,prodSvcPct:25.26,prodTotalPct:16.04,memberSales:0,memberCount:0,pkgSales:1338,pkgCount:3,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:1,avgFeedback:5,cancelled:13}, March: {appt:39,invoices:46,totalSales:10709.35,avgInvoice:232.81,guests:35,newGuestPct:28.57,rebookedPct:43.59,newGuests:10,svcQty:42,svcSales:4414.15,avgSvcVal:110.35,saleCount:321,svcSalesCount:305,svcInvoiceCount:40,prodInvoiceCount:7,prodSalesCount:14,prodSales:2245.2,boughtProdPct:7.5,avgProdVal:320.74,prodSvcPct:50.86,prodTotalPct:20.96,memberSales:0,memberCount:0,pkgSales:4050,pkgCount:2,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:15}, April: {appt:15,invoices:15,totalSales:2918,avgInvoice:194.53,guests:14,newGuestPct:35.71,rebookedPct:33.33,newGuests:5,svcQty:21,svcSales:2823,avgSvcVal:188.2,saleCount:159,svcSalesCount:158,svcInvoiceCount:15,prodInvoiceCount:1,prodSalesCount:1,prodSales:95,boughtProdPct:6.67,avgProdVal:95,prodSvcPct:3.37,prodTotalPct:3.26,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:3,avgFeedback:0,cancelled:1}, May: {appt:8,invoices:9,totalSales:1305.65,avgInvoice:145.07,guests:9,newGuestPct:0,rebookedPct:62.5,newGuests:0,svcQty:8,svcSales:1010.65,avgSvcVal:126.33,saleCount:77,svcSalesCount:77,svcInvoiceCount:8,prodInvoiceCount:1,prodSalesCount:2,prodSales:295,boughtProdPct:0,avgProdVal:295,prodSvcPct:29.19,prodTotalPct:22.59,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:3}, }, “Taryn McLaughlin”: { October: {appt:90,invoices:90,totalSales:2156.86,avgInvoice:23.97,guests:85,newGuestPct:77.65,rebookedPct:0,newGuests:66,svcQty:118,svcSales:2156.86,avgSvcVal:23.97,saleCount:118,svcSalesCount:118,svcInvoiceCount:90,prodInvoiceCount:0,prodSalesCount:0,prodSales:0,boughtProdPct:0,avgProdVal:0,prodSvcPct:0,prodTotalPct:0,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:0}, November: {appt:110,invoices:123,totalSales:25618.31,avgInvoice:208.28,guests:83,newGuestPct:50.6,rebookedPct:6.36,newGuests:42,svcQty:135,svcSales:11161.36,avgSvcVal:98.77,saleCount:351,svcSalesCount:338,svcInvoiceCount:113,prodInvoiceCount:1,prodSalesCount:1,prodSales:73,boughtProdPct:0,avgProdVal:73,prodSvcPct:0.65,prodTotalPct:0.28,memberSales:349,memberCount:2,pkgSales:10167.5,pkgCount:7,gcSales:0,gcCount:0,prepaidSales:3867.45,prepaidCount:3,campaignRedemptions:1,avgFeedback:5,cancelled:4}, December: {appt:128,invoices:143,totalSales:43089.92,avgInvoice:301.33,guests:102,newGuestPct:35.29,rebookedPct:44.53,newGuests:36,svcQty:163,svcSales:20709.68,avgSvcVal:158.09,saleCount:697,svcSalesCount:671,svcInvoiceCount:131,prodInvoiceCount:9,prodSalesCount:16,prodSales:1367,boughtProdPct:3.05,avgProdVal:151.89,prodSvcPct:6.6,prodTotalPct:3.17,memberSales:0,memberCount:0,pkgSales:12200.74,pkgCount:5,gcSales:0,gcCount:0,prepaidSales:8812.5,prepaidCount:5,campaignRedemptions:1,avgFeedback:5,cancelled:16}, January: {appt:108,invoices:116,totalSales:26900.12,avgInvoice:231.9,guests:87,newGuestPct:45.98,rebookedPct:48.15,newGuests:40,svcQty:129,svcSales:12623.14,avgSvcVal:116.88,saleCount:421,svcSalesCount:340,svcInvoiceCount:108,prodInvoiceCount:7,prodSalesCount:73,prodSales:462.98,boughtProdPct:4.63,avgProdVal:66.14,prodSvcPct:3.67,prodTotalPct:1.72,memberSales:499,memberCount:1,pkgSales:11815,pkgCount:6,gcSales:0,gcCount:0,prepaidSales:1500,prepaidCount:1,campaignRedemptions:0,avgFeedback:5,cancelled:9}, February: {appt:119,invoices:126,totalSales:42042.94,avgInvoice:333.67,guests:89,newGuestPct:40.45,rebookedPct:51.26,newGuests:36,svcQty:142,svcSales:19441.35,avgSvcVal:162.01,saleCount:686,svcSalesCount:660,svcInvoiceCount:120,prodInvoiceCount:6,prodSalesCount:9,prodSales:588.99,boughtProdPct:4.17,avgProdVal:98.16,prodSvcPct:3.03,prodTotalPct:1.4,memberSales:0,memberCount:0,pkgSales:21755,pkgCount:16,gcSales:0,gcCount:0,prepaidSales:257.6,prepaidCount:1,campaignRedemptions:0,avgFeedback:5,cancelled:19}, March: {appt:133,invoices:138,totalSales:40315.06,avgInvoice:292.14,guests:96,newGuestPct:33.33,rebookedPct:54.89,newGuests:32,svcQty:159,svcSales:27250.86,avgSvcVal:204.89,saleCount:1074,svcSalesCount:1047,svcInvoiceCount:133,prodInvoiceCount:10,prodSalesCount:18,prodSales:2142.2,boughtProdPct:6.77,avgProdVal:214.22,prodSvcPct:7.86,prodTotalPct:5.31,memberSales:300,memberCount:1,pkgSales:9622,pkgCount:7,gcSales:0,gcCount:0,prepaidSales:1000,prepaidCount:1,campaignRedemptions:1,avgFeedback:5,cancelled:18}, April: {appt:38,invoices:39,totalSales:11158.35,avgInvoice:286.11,guests:36,newGuestPct:16.67,rebookedPct:68.42,newGuests:6,svcQty:47,svcSales:7451.55,avgSvcVal:196.09,saleCount:171,svcSalesCount:163,svcInvoiceCount:38,prodInvoiceCount:3,prodSalesCount:6,prodSales:596.8,boughtProdPct:7.89,avgProdVal:198.93,prodSvcPct:8.01,prodTotalPct:5.35,memberSales:0,memberCount:0,pkgSales:3110,pkgCount:2,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:16}, May: {appt:34,invoices:36,totalSales:8881.07,avgInvoice:246.7,guests:31,newGuestPct:32.26,rebookedPct:50,newGuests:10,svcQty:39,svcSales:6481.07,avgSvcVal:190.62,saleCount:302,svcSalesCount:302,svcInvoiceCount:34,prodInvoiceCount:0,prodSalesCount:0,prodSales:0,boughtProdPct:0,avgProdVal:0,prodSvcPct:0,prodTotalPct:0,memberSales:0,memberCount:0,pkgSales:2400,pkgCount:2,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:6}, }, “Yannick Mallet Noel”: { October: {appt:228,invoices:228,totalSales:44842.71,avgInvoice:196.68,guests:159,newGuestPct:18.24,rebookedPct:0,newGuests:29,svcQty:246,svcSales:44842.71,avgSvcVal:196.68,saleCount:248,svcSalesCount:248,svcInvoiceCount:228,prodInvoiceCount:0,prodSalesCount:0,prodSales:0,boughtProdPct:0,avgProdVal:0,prodSvcPct:0,prodTotalPct:0,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:0}, November: {appt:165,invoices:170,totalSales:44553.04,avgInvoice:262.08,guests:136,newGuestPct:8.82,rebookedPct:3.64,newGuests:12,svcQty:188,svcSales:40298.15,avgSvcVal:241.31,saleCount:781,svcSalesCount:774,svcInvoiceCount:167,prodInvoiceCount:3,prodSalesCount:3,prodSales:104.89,boughtProdPct:1.2,avgProdVal:34.96,prodSvcPct:0.26,prodTotalPct:0.24,memberSales:0,memberCount:0,pkgSales:3000,pkgCount:3,gcSales:0,gcCount:0,prepaidSales:1150,prepaidCount:1,campaignRedemptions:0,avgFeedback:5,cancelled:5}, December: {appt:168,invoices:184,totalSales:63581.25,avgInvoice:345.55,guests:140,newGuestPct:14.29,rebookedPct:36.31,newGuests:20,svcQty:192,svcSales:44936.85,avgSvcVal:265.9,saleCount:1880,svcSalesCount:1858,svcInvoiceCount:169,prodInvoiceCount:6,prodSalesCount:8,prodSales:622.75,boughtProdPct:1.18,avgProdVal:103.79,prodSvcPct:1.39,prodTotalPct:0.98,memberSales:0,memberCount:0,pkgSales:8116,pkgCount:6,gcSales:1150,gcCount:1,prepaidSales:8755.65,prepaidCount:7,campaignRedemptions:0,avgFeedback:5,cancelled:18}, January: {appt:154,invoices:162,totalSales:47692.43,avgInvoice:294.4,guests:124,newGuestPct:17.74,rebookedPct:33.77,newGuests:22,svcQty:176,svcSales:41070.43,avgSvcVal:264.97,saleCount:1761,svcSalesCount:1729,svcInvoiceCount:155,prodInvoiceCount:15,prodSalesCount:28,prodSales:1639,boughtProdPct:6.45,avgProdVal:109.27,prodSvcPct:3.99,prodTotalPct:3.44,memberSales:0,memberCount:0,pkgSales:4983,pkgCount:4,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:5,cancelled:15}, February: {appt:139,invoices:141,totalSales:47923.33,avgInvoice:339.88,guests:116,newGuestPct:17.24,rebookedPct:36.69,newGuests:20,svcQty:166,svcSales:41274.03,avgSvcVal:296.94,saleCount:2032,svcSalesCount:2009,svcInvoiceCount:139,prodInvoiceCount:7,prodSalesCount:9,prodSales:813.3,boughtProdPct:4.32,avgProdVal:116.19,prodSvcPct:1.97,prodTotalPct:1.7,memberSales:897,memberCount:5,pkgSales:4939,pkgCount:9,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:5,cancelled:16}, March: {appt:162,invoices:170,totalSales:50638.65,avgInvoice:297.87,guests:132,newGuestPct:12.88,rebookedPct:45.06,newGuests:17,svcQty:187,svcSales:39329.26,avgSvcVal:242.77,saleCount:2177,svcSalesCount:2144,svcInvoiceCount:162,prodInvoiceCount:19,prodSalesCount:27,prodSales:2081.49,boughtProdPct:9.26,avgProdVal:109.55,prodSvcPct:5.29,prodTotalPct:4.11,memberSales:0,memberCount:0,pkgSales:3175,pkgCount:3,gcSales:0,gcCount:0,prepaidSales:6052.9,prepaidCount:3,campaignRedemptions:0,avgFeedback:0,cancelled:28}, April: {appt:52,invoices:52,totalSales:13762.97,avgInvoice:264.67,guests:47,newGuestPct:14.89,rebookedPct:36.54,newGuests:7,svcQty:63,svcSales:12472.97,avgSvcVal:239.86,saleCount:810,svcSalesCount:807,svcInvoiceCount:52,prodInvoiceCount:1,prodSalesCount:2,prodSales:290,boughtProdPct:1.92,avgProdVal:290,prodSvcPct:2.32,prodTotalPct:2.11,memberSales:0,memberCount:0,pkgSales:1000,pkgCount:1,gcSales:0,gcCount:0,prepaidSales:0,prepaidCount:0,campaignRedemptions:0,avgFeedback:0,cancelled:11}, May: {appt:38,invoices:40,totalSales:7342.95,avgInvoice:183.57,guests:37,newGuestPct:16.22,rebookedPct:39.47,newGuests:6,svcQty:43,svcSales:6039.95,avgSvcVal:158.95,saleCount:490,svcSalesCount:490,svcInvoiceCount:38,prodInvoiceCount:3,prodSalesCount:4,prodSales:303,boughtProdPct:5.26,avgProdVal:101,prodSvcPct:5.02,prodTotalPct:4.13,memberSales:0,memberCount:0,pkgSales:0,pkgCount:0,gcSales:0,gcCount:0,prepaidSales:1000,prepaidCount:1,campaignRedemptions:0,avgFeedback:0,cancelled:7}, }, }; const MONTHS = [“October”,”November”,”December”,”January”,”February”,”March”,”April”,”May”]; const EMP_KEYS = Object.keys(KPI); // โ”€โ”€ WORKING DAYS CONFIG โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Update elapsed days here as the month progresses const WORK_DAYS = { April: { elapsed: 7, total: 21 }, // Apr 3 = Easter excluded May: { elapsed: 9, total: 21 }, }; const PROJ = {}; Object.entries(WORK_DAYS).forEach(([mo, { elapsed, total }]) => { PROJ[mo] = total / elapsed; }); // โ”€โ”€ CLINIC TOTALS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const CLINIC = {}; MONTHS.forEach(mo => { const s = {}; EMP_KEYS.forEach(e => { const d = KPI[e][mo]; if (d) Object.keys(d).forEach(k => { s[k] = (s[k]||0) + d[k]; }); }); if (Object.keys(s).length) { // Recalculated from totals s.avgInvoice = s.invoices > 0 ? s.totalSales / s.invoices : 0; s.avgSvcVal = s.svcInvoiceCount > 0 ? s.svcSales / s.svcInvoiceCount : 0; s.avgProdVal = s.prodSalesCount > 0 ? s.prodSales / s.prodSalesCount : 0; s.newGuestPct = s.guests > 0 ? (s.newGuests / s.guests) * 100 : 0; s.prodTotalPct = s.totalSales > 0 ? (s.prodSales / s.totalSales) * 100 : 0; s.prodSvcPct = s.svcSales > 0 ? (s.prodSales / s.svcSales) * 100 : 0; // Averaged across team members (not meaningful as sums) const activeEmps = EMP_KEYS.filter(e => (KPI[e][mo]?.invoices || 0) > 0).length || 1; s.rebookedPct = s.rebookedPct / activeEmps; s.avgFeedback = s.avgFeedback / activeEmps; s.boughtProdPct = s.boughtProdPct / activeEmps; } CLINIC[mo] = s; }); const EMP_CFG = { “Clinic Total”: { color:”#A5B4FC”, short:”Clinic” }, “Bri Foster”: { color:”#FCA5A5″, short:”Bri” }, “Josie Raymond”: { color:”#C084FC”, short:”Josie” }, “Kasi Holden”: { color:”#6EE7B7″, short:”Kasi” }, “Katie Sturgeon”: { color:”#FDA4AF”, short:”Katie” }, “Taryn McLaughlin”: { color:”#FDE68A”, short:”Taryn” }, “Yannick Mallet Noel”: { color:”#38BDF8″, short:”Yannick” }, }; const GOALS = { “Clinic Total”: { totalSales:165000, invoices:560, avgInvoice:295, newGuestPct:25, rebookedPct:40, prodTotalPct:12, cancelled:28, avgFeedback:4.8 }, “Bri Foster”: { totalSales:28000, invoices:105, avgInvoice:265, newGuestPct:22, rebookedPct:45, prodTotalPct:8, cancelled:20, avgFeedback:4.8 }, “Josie Raymond”: { totalSales:38000, invoices:125, avgInvoice:300, newGuestPct:18, rebookedPct:50, prodTotalPct:12, cancelled:15, avgFeedback:4.9 }, “Kasi Holden”: { totalSales:13000, invoices:45, avgInvoice:265, newGuestPct:12, rebookedPct:55, prodTotalPct:25, cancelled:5, avgFeedback:4.8 }, “Katie Sturgeon”: { totalSales:10000, invoices:50, avgInvoice:200, newGuestPct:30, rebookedPct:45, prodTotalPct:18, cancelled:10, avgFeedback:4.8 }, “Taryn McLaughlin”: { totalSales:40000, invoices:135, avgInvoice:295, newGuestPct:30, rebookedPct:50, prodTotalPct:8, cancelled:15, avgFeedback:4.9 }, “Yannick Mallet Noel”: { totalSales:52000, invoices:165, avgInvoice:315, newGuestPct:15, rebookedPct:40, prodTotalPct:5, cancelled:18, avgFeedback:4.9 }, }; // โ”€โ”€ HELPERS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const f$ = v => (!v&&v!==0)?”โ€””:(Math.abs(v)>=1000?”$”+(v/1000).toFixed(1)+”K”:”$”+Math.round(v)); const fN = v => (!v&&v!==0)?”โ€””:Math.round(v).toLocaleString(); const fP = v => (!v&&v!==0)?”โ€””:v.toFixed(1)+”%”; const fF = v => (!v||v===0)?”โ€””:v.toFixed(1)+”โ˜…”; function getData(emp, mo) { return emp === “Clinic Total” ? CLINIC[mo] : KPI[emp]?.[mo] || null; } function Mom({ cur, prv, inv=false }) { if (!cur||!prv||prv===0) return null; const pct = ((cur-prv)/prv)*100; const up = pct >= 0; const good = inv ? !up : up; const col = Math.abs(pct)<2?"#475569":good?"#4ADE80":"#F87171"; return {up?”โ–ฒ”:”โ–ผ”}{Math.abs(pct).toFixed(1)}%; } function Card({ lbl, val, prv, goal, fmt=”$”, inv=false, pMo=null }) { const display = fmt===”$”?f$(val):fmt===”%”?fP(val):fmt===”โ˜…”?fF(val):fN(val); const gPct = (goal&&val!=null&&goal>0)?(val/goal)*100:null; const bCol = gPct==null?”#1e3a5f”:inv?(gPct<=85?"#4ADE80":gPct<=100?"#FBBF24":"#F87171"):(gPct>=100?”#4ADE80″:gPct>=70?”#FBBF24″:”#F87171″); const pFactor = pMo ? PROJ[pMo] : null; const projected = pFactor && val != null ? Math.round(val * pFactor * 10)/10 : null; return (
{lbl}
{display}
{projected!=null && (
โ–ถ Proj: {fmt===”$”?f$(projected):fmt===”%”?fP(projected):fN(projected)}
)} {gPct!=null && ( <>
{Math.round(gPct)}% Goal: {fmt===”$”?f$(goal):fmt===”%”?fP(goal):fN(goal)}
)}
); } const SecH = ({t}) =>
{t}
; const Grid = ({ch}) =>
{ch}
; const CTip = ({active,payload,label,money=true}) => { if (!active||!payload?.length) return null; return (
{label}
{payload.filter(p=>p.dataKey!==”projRemaining”&&p.value>0.01).map((p,i)=>(
{p.name}: {money?”$”+Number(p.value).toLocaleString(undefined,{maximumFractionDigits:0}):Number(p.value).toLocaleString(undefined,{maximumFractionDigits:1})}
))}
); }; // โ”€โ”€ MAIN DASHBOARD โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ export default function SparkleDashboard() { const [emp, setEmp] = useState(“Clinic Total”); const [month, setMonth] = useState(“April”); const [trend, setTrend] = useState(“totalSales”); const [goals, setGoals] = useState(GOALS); const [editing, setEditing] = useState(false); const [tmp, setTmp] = useState(null); const prevMo = MONTHS[MONTHS.indexOf(month)-1] || null; const isPartial = !!WORK_DAYS[month]; const accent = EMP_CFG[emp]?.color || “#A5B4FC”; const d = getData(emp, month); const dp = prevMo ? getData(emp, prevMo) : null; const g = goals[emp] || {}; // Metric type detection const isMo = [“totalSales”,”svcSales”,”prodSales”,”pkgSales”,”avgInvoice”,”memberSales”,”prepaidSales”].includes(trend); const isPc = [“newGuestPct”,”rebookedPct”,”prodTotalPct”,”boughtProdPct”].includes(trend); const isFb = trend === “avgFeedback”; const canProj = [“totalSales”,”invoices”,”guests”,”svcSales”,”prodSales”,”pkgSales”,”cancelled”,”newGuests”,”prepaidSales”,”memberSales”].includes(trend); // Format a value for bar labels const fmtBar = (v) => { if (v == null || v === 0) return “”; if (isMo) return Math.abs(v) >= 1000 ? `$${(v/1000).toFixed(0)}K` : `$${Math.round(v)}`; if (isPc) return `${Number(v).toFixed(1)}%`; if (isFb) return `${Number(v).toFixed(1)}โ˜…`; return Math.round(v).toLocaleString(); }; // Helper: projection value for a given raw value + month const projVal = (raw, mo) => { const f = PROJ[mo]; return f ? Math.round(raw * f * 10)/10 : null; }; // โ”€โ”€ REVENUE CHART DATA โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const revData = MONTHS.map(mo => { const r = getData(emp, mo); const partial = !!WORK_DAYS[mo]; const Service = Math.round(r?.svcSales||0); const Products = Math.round(Math.max(0, r?.prodSales||0)); const Packages = Math.round(Math.max(0, r?.pkgSales||0)); const Prepaid = Math.round(r?.prepaidSales||0); const Membership = Math.round(r?.memberSales||0); const GiftCard = Math.round(r?.gcSales||0); const total = Service + Products + Packages + Prepaid + Membership + GiftCard; const pTotal = partial ? projVal(total, mo) : null; const projRemaining = pTotal != null ? Math.max(0.01, pTotal – total) : 0.01; return { month: mo.substring(0,3)+(partial?”โ–ฒ”:””), Service, Products, Packages, Prepaid, Membership, GiftCard, total, pTotal, projRemaining, partial }; }); // โ”€โ”€ PACKAGE SALES CHART DATA โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const pkgData = MONTHS.map(mo => { const raw = Math.max(0, getData(emp, mo)?.pkgSales || 0); const partial = !!WORK_DAYS[mo]; const value = Math.round(raw); const pTotal = partial && value > 0 ? projVal(value, mo) : null; const projRemaining = pTotal != null ? Math.max(0.01, pTotal – value) : 0.01; return { month: mo.substring(0,3)+(partial?”โ–ฒ”:””), value, pTotal, projRemaining, partial }; }); // โ”€โ”€ TREND CHART DATA โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const trendData = MONTHS.map(mo => { const raw = getData(emp, mo)?.[trend] || 0; const partial = !!WORK_DAYS[mo]; const value = Math.round(raw * 100) / 100; const pTotal = partial && canProj ? projVal(raw, mo) : null; const projRemaining = pTotal != null ? Math.max(0.01, pTotal – value) : 0.01; return { month: mo.substring(0,3)+(partial?”โ–ฒ”:””), value, pTotal, projRemaining, partial }; }); const TOPTS = [ {k:”totalSales”,l:”Total Sales”},{k:”invoices”,l:”Invoices”},{k:”guests”,l:”Guests”}, {k:”svcSales”,l:”Svc Sales”},{k:”prodSales”,l:”Prod Sales”}, {k:”newGuestPct”,l:”New Guest %”},{k:”rebookedPct”,l:”Rebooked %”}, {k:”avgFeedback”,l:”Feedback”},{k:”cancelled”,l:”Cancelled”},{k:”avgInvoice”,l:”Avg Invoice”}, ]; const tb = a => ({padding:”6px 12px”,borderRadius:7,background:a?”rgba(99,102,241,0.15)”:”#0f1929″,color:a?”#a5b4fc”:”#334155″,border:`1px solid ${a?”#4F46E5″:”#1a2a3a”}`,cursor:”pointer”,fontWeight:a?700:400,fontSize:11,fontFamily:”inherit”}); // April working day progress const aprWD = WORK_DAYS.April; const aprPct = Math.round((aprWD.elapsed / aprWD.total) * 100); return (
{/* โ”€โ”€ HEADER โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */}
Sparkle Lifestyle & MediSpa ยท Performance Dashboard
Oct 2025 โ€“ May 2026  ยท  Apr: {aprWD.elapsed} of {aprWD.total} working days ({aprPct}% complete ยท Apr 3 Easter excluded)  ยท  โ–ฒ = partial month  ยท  Dashed bar = projected remaining  ยท  โ–ถ = projected full-month total
{Object.keys(EMP_CFG).map(k => { const a=emp===k; const c=EMP_CFG[k].color; return ; })}
{MONTHS.map(mo => { const a=month===mo; const p=!!WORK_DAYS[mo]; return ; })}
{/* โ”€โ”€ TOP STATS BAR โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */}
{[ {lbl:”Total Sales”, val:f$(d?.totalSales), prj:isPartial?f$(projVal(d?.totalSales||0,month)):null}, {lbl:”Invoices”, val:fN(d?.invoices), prj:isPartial?fN(projVal(d?.invoices||0,month)):null}, {lbl:”Avg Invoice”, val:f$(d?.avgInvoice)}, {lbl:”Guests”, val:fN(d?.guests), prj:isPartial?fN(projVal(d?.guests||0,month)):null}, {lbl:”New Guest %”, val:fP(d?.newGuestPct)}, {lbl:”Rebooked %”, val:fP(d?.rebookedPct)}, {lbl:”Avg Feedback”, val:fF(d?.avgFeedback)}, {lbl:”Cancelled”, val:fN(d?.cancelled), prj:isPartial?fN(projVal(d?.cancelled||0,month)):null}, ].map(({lbl,val,prj},i,arr) => (
{lbl}
{val}
{prj &&
โ–ถ {prj}
}
))}
{/* โ”€โ”€ REVENUE BREAKDOWN โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */}
“$”+(v/1000).toFixed(0)+”K”} /> } /> {/* Projected remaining โ€” transparent dashed on top */} { if (!width || !revData[index]) return null; const e = revData[index]; if (!e.total) return null; const lbl = e.total >= 1000 ? `$${(e.total/1000).toFixed(0)}K` : `$${e.total}`; const plbl = e.pTotal ? `โ–ถ$${(e.pTotal/1000).toFixed(0)}K` : null; return ( {lbl} {plbl && {plbl}} ); }} />
{/* โ”€โ”€ PACKAGE SALES REVENUE โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */}
“$”+(v/1000).toFixed(0)+”K”} /> } /> {pkgData.map((pt,i) => )} { if (!value || width < 12) return null; const lbl = value >= 1000 ? `$${(value/1000).toFixed(0)}K` : `$${value}`; return {lbl}; }} /> { if (!value || value <= 0.05 || width < 12) return null; const d = pkgData[index]; if (!d?.pTotal) return null; const lbl = d.pTotal >= 1000 ? `โ–ถ$${(d.pTotal/1000).toFixed(0)}K` : `โ–ถ$${d.pTotal}`; return {lbl}; }} />
{/* โ”€โ”€ METRIC TREND โ€” BAR CHART โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */}
o.k===trend)?.l || “”}`} />
{TOPTS.map(({k,l}) => )}
isMo?”$”+(v/1000).toFixed(0)+”K”:isPc?v.toFixed(1)+”%”:Math.round(v)} /> } /> {/* Actual value bars */} {trendData.map((pt,i) => )} { if (!value || width < 12) return null; const lbl = fmtBar(value); if (!lbl) return null; return {lbl}; }} /> {/* Projected remaining bars */} { if (!value || value <= 0.05 || width < 12) return null; const d = trendData[index]; if (!d?.pTotal) return null; const lbl = fmtBar(d.pTotal); if (!lbl) return null; return โ–ถ{lbl}; }} /> {!canProj && isPc &&
Projection not shown for rate/percentage metrics โ€” they don’t scale linearly with working days.
}
{/* โ”€โ”€ GOALS EDIT โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */}
{!editing ? ( ) : (
Monthly Goals โ€” {emp}
{[{k:”totalSales”,l:”Total Sales ($)”},{k:”invoices”,l:”Invoice Count”},{k:”avgInvoice”,l:”Avg Invoice ($)”},{k:”newGuestPct”,l:”New Guest %”},{k:”rebookedPct”,l:”Rebooked %”},{k:”prodTotalPct”,l:”Product/Total %”},{k:”cancelled”,l:”Max Cancelled”},{k:”avgFeedback”,l:”Avg Feedback”}].map(({k,l}) => (
{l}
setTmp(p=>({…p,[k]:parseFloat(e.target.value)||0}))} style={{width:”100%”,padding:”5px 8px”,background:”#060a12″,border:”1px solid #1a2a3a”,borderRadius:6,color:”#f1f5f9″,fontSize:12,fontFamily:”inherit”,boxSizing:”border-box”}} />
))}
)}
{/* โ”€โ”€ KPI CARDS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */} , , , , , ]} /> , , , , , ]} /> , , , , , , ]} /> , , , , , , , ]} /> , , , , , , , , , ]} />
Notes โ€” Working days: April = {WORK_DAYS.April.elapsed}/{WORK_DAYS.April.total} days elapsed (Apr 3 Easter excluded). May = {WORK_DAYS.May.elapsed}/{WORK_DAYS.May.total} days. Projection factor = total working days รท elapsed. Rate/percentage metrics (New Guest %, Rebooked %, etc.) do not project โ€” they don’t scale with time. October = onboarding period, limited product tracking. Kasi April shows โ€“$500 pkg (reversal). Clinic Total = all 6 members summed.
); }