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
window.print()} style={{
padding:”7px 16px”,borderRadius:7,background:”#1e293b”,color:”#94a3b8″,
border:”1px solid #334155″,cursor:”pointer”,fontSize:12,fontFamily:”inherit”,
display:”flex”,alignItems:”center”,gap:6,flexShrink:0,
}}>
๐จ Print / Save PDF
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 setEmp(k)} style={{padding:”6px 14px”,borderRadius:7,background:a?`${c}18`:”#111827″,color:a?c:”#334155″,border:`1px solid ${a?c:”#1e293b”}`,cursor:”pointer”,fontWeight:a?700:400,fontSize:12,fontFamily:”inherit”}}>{EMP_CFG[k].short} ;
})}
{MONTHS.map(mo => {
const a=month===mo; const p=!!WORK_DAYS[mo];
return setMonth(mo)} style={{padding:”4px 11px”,borderRadius:6,fontFamily:”inherit”,background:a?”#1e293b”:”transparent”,color:a?”#f1f5f9″:p?”#4ADE80″:”#1e3a5f”,border:`1px solid ${a?”#334155″:”transparent”}`,cursor:”pointer”,fontSize:11,fontWeight:a?600:400}}>
{mo.substring(0,3)}{p?”โฒ”:””}
;
})}
{/* โโ 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}) => setTrend(k)} style={tb(trend===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 ? (
{setTmp({…g});setEditing(true);}} style={tb(false)}>โ Edit Monthly Goals โ {emp}
) : (
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}) => (
))}
{setGoals(p=>({…p,[emp]:{…tmp}}));setEditing(false);}} style={{padding:”5px 14px”,borderRadius:7,background:”#4F46E5″,color:”#fff”,border:”none”,cursor:”pointer”,fontSize:11,fontFamily:”inherit”,fontWeight:600}}>Save
setEditing(false)} style={{padding:”5px 14px”,borderRadius:7,background:”#0f1929″,color:”#475569″,border:”1px solid #1a2a3a”,cursor:”pointer”,fontSize:11,fontFamily:”inherit”}}>Cancel
)}
{/* โโ 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.
);
}