@burdenoff/microfe-atheletebridge 2026.628.1 → 2026.705.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.js +45 -37
  2. package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
  3. package/dist/atheletebridge/AthleteBridgeRoutes.js +10 -6
  4. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  5. package/dist/atheletebridge/components/AthleteSelect.js +66 -0
  6. package/dist/atheletebridge/components/AthleteSelect.js.map +1 -0
  7. package/dist/atheletebridge/components/DrillVideoLink.js +28 -0
  8. package/dist/atheletebridge/components/DrillVideoLink.js.map +1 -0
  9. package/dist/atheletebridge/components/FixtureCard.js.map +1 -1
  10. package/dist/atheletebridge/components/LoadingState.js.map +1 -1
  11. package/dist/atheletebridge/components/MetricsCard.js +20 -46
  12. package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
  13. package/dist/atheletebridge/components/UserSearchSelect.js +129 -0
  14. package/dist/atheletebridge/components/UserSearchSelect.js.map +1 -0
  15. package/dist/atheletebridge/components/domain.js +10 -1
  16. package/dist/atheletebridge/components/domain.js.map +1 -1
  17. package/dist/atheletebridge/context/AthleteBridgeContext.js.map +1 -1
  18. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +313 -180
  19. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  20. package/dist/atheletebridge/pages/DashboardPage.js +77 -69
  21. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  22. package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
  23. package/dist/atheletebridge/pages/performance/PerformancePage.js +496 -0
  24. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -0
  25. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +175 -141
  26. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  27. package/dist/atheletebridge/pages/programs/ProgramFormPage.js.map +1 -1
  28. package/dist/atheletebridge/pages/sessions/SessionFormPage.js +91 -98
  29. package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -1
  30. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +132 -137
  31. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  32. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
  33. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
  34. package/dist/atheletebridge/utils/formatters.js +2 -25
  35. package/dist/atheletebridge/utils/formatters.js.map +1 -1
  36. package/dist/index.js +4 -4
  37. package/package.json +5 -5
@@ -0,0 +1,129 @@
1
+ import { cn as e } from "../utils/cn.js";
2
+ import { directoryUserName as t, useUserSearch as n } from "../hooks/useAthleteBridgeApi.js";
3
+ import { FormField as r, fieldInputClass as i } from "./form.js";
4
+ import { useState as a } from "react";
5
+ import { Check as o, Loader2 as s, Search as c, User as l, X as u } from "lucide-react";
6
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
7
+ //#region src/atheletebridge/components/UserSearchSelect.tsx
8
+ function p({ userId: p, displayName: m, onSelect: h, required: g = !1 }) {
9
+ let [_, v] = a(""), [y, b] = a(!1), x = n(_), S = x.data ?? [], C = _.trim().length >= 2, w = (e) => {
10
+ h({
11
+ userId: e.id,
12
+ displayName: t(e)
13
+ }), v("");
14
+ }, T = x.isError;
15
+ return y || T ? /* @__PURE__ */ f(r, {
16
+ label: "User ID",
17
+ htmlFor: "member-user-id",
18
+ required: g,
19
+ hint: T ? "User search is unavailable here — paste the auth-svc user id." : "Paste the auth-svc user id.",
20
+ children: [/* @__PURE__ */ d("input", {
21
+ id: "member-user-id",
22
+ className: i,
23
+ value: p,
24
+ onChange: (e) => h({
25
+ userId: e.target.value,
26
+ displayName: m
27
+ }),
28
+ placeholder: "user-uuid"
29
+ }), !T && /* @__PURE__ */ d("button", {
30
+ type: "button",
31
+ onClick: () => b(!1),
32
+ className: "mt-1 self-start text-xs font-medium text-primary hover:underline",
33
+ children: "Search the directory instead"
34
+ })]
35
+ }) : /* @__PURE__ */ d(r, {
36
+ label: "Athlete / user",
37
+ required: g,
38
+ children: p ? /* @__PURE__ */ f("div", {
39
+ className: "flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface px-3 py-2",
40
+ children: [
41
+ /* @__PURE__ */ d("span", {
42
+ className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-text-secondary",
43
+ children: /* @__PURE__ */ d(l, { className: "h-4 w-4" })
44
+ }),
45
+ /* @__PURE__ */ f("div", {
46
+ className: "min-w-0 flex-1",
47
+ children: [/* @__PURE__ */ d("p", {
48
+ className: "truncate text-sm font-medium text-text-primary",
49
+ children: m || "Selected user"
50
+ }), /* @__PURE__ */ d("p", {
51
+ className: "truncate text-xs text-text-secondary",
52
+ children: p
53
+ })]
54
+ }),
55
+ /* @__PURE__ */ d("button", {
56
+ type: "button",
57
+ "aria-label": "Clear selected user",
58
+ onClick: () => h({
59
+ userId: "",
60
+ displayName: ""
61
+ }),
62
+ className: "rounded-md p-1 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary",
63
+ children: /* @__PURE__ */ d(u, { className: "h-4 w-4" })
64
+ })
65
+ ]
66
+ }) : /* @__PURE__ */ f("div", {
67
+ className: "space-y-2",
68
+ children: [
69
+ /* @__PURE__ */ f("div", {
70
+ className: "relative",
71
+ children: [
72
+ /* @__PURE__ */ d(c, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }),
73
+ /* @__PURE__ */ d("input", {
74
+ className: e(i, "pl-9"),
75
+ value: _,
76
+ onChange: (e) => v(e.target.value),
77
+ placeholder: "Search by name or email…",
78
+ "aria-label": "Search users by name or email"
79
+ }),
80
+ x.isFetching && /* @__PURE__ */ d(s, { className: "absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-text-secondary" })
81
+ ]
82
+ }),
83
+ C && !x.isFetching && S.length === 0 && /* @__PURE__ */ f("p", {
84
+ className: "text-xs text-text-secondary",
85
+ children: [
86
+ "No users match “",
87
+ _.trim(),
88
+ "”."
89
+ ]
90
+ }),
91
+ S.length > 0 && /* @__PURE__ */ d("ul", {
92
+ className: "max-h-56 divide-y divide-border-seam overflow-auto rounded-lg border border-border-seam bg-bg-surface",
93
+ children: S.map((e) => /* @__PURE__ */ d("li", { children: /* @__PURE__ */ f("button", {
94
+ type: "button",
95
+ onClick: () => w(e),
96
+ className: "flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-bg-sunken",
97
+ children: [
98
+ /* @__PURE__ */ d("span", {
99
+ className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-text-secondary",
100
+ children: /* @__PURE__ */ d(l, { className: "h-4 w-4" })
101
+ }),
102
+ /* @__PURE__ */ f("span", {
103
+ className: "min-w-0 flex-1",
104
+ children: [/* @__PURE__ */ d("span", {
105
+ className: "block truncate text-sm font-medium text-text-primary",
106
+ children: t(e)
107
+ }), /* @__PURE__ */ d("span", {
108
+ className: "block truncate text-xs text-text-secondary",
109
+ children: e.email
110
+ })]
111
+ }),
112
+ /* @__PURE__ */ d(o, { className: "h-4 w-4 shrink-0 text-text-secondary opacity-0" })
113
+ ]
114
+ }) }, e.id))
115
+ }),
116
+ /* @__PURE__ */ d("button", {
117
+ type: "button",
118
+ onClick: () => b(!0),
119
+ className: "text-xs font-medium text-primary hover:underline",
120
+ children: "Enter a user ID manually"
121
+ })
122
+ ]
123
+ })
124
+ });
125
+ }
126
+ //#endregion
127
+ export { p as UserSearchSelect };
128
+
129
+ //# sourceMappingURL=UserSearchSelect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserSearchSelect.js","names":[],"sources":["../../../src/atheletebridge/components/UserSearchSelect.tsx"],"sourcesContent":["/**\n * User picker\n * @module atheletebridge/components\n *\n * Resolves a real workspace/tenant user by name or email (global user\n * directory) so a coach can add a team member without knowing a raw UUID.\n * Degrades gracefully: if the directory is unavailable the coach can still paste\n * a user id manually. Semantic tokens only.\n */\n\nimport { useState } from 'react';\nimport { Check, Loader2, Search, User as UserIcon, X } from 'lucide-react';\nimport { FormField, fieldInputClass } from './form';\nimport { cn } from '../utils/cn';\nimport { directoryUserName, useUserSearch, type DirectoryUser } from '../hooks/useAthleteBridgeApi';\n\nexport interface UserSelectValue {\n userId: string;\n displayName: string;\n}\n\ninterface UserSearchSelectProps {\n /** Currently selected user id. */\n userId: string;\n /** Display name currently chosen (echoed back so the parent can prefill). */\n displayName: string;\n onSelect: (value: UserSelectValue) => void;\n required?: boolean;\n}\n\nexport function UserSearchSelect({\n userId,\n displayName,\n onSelect,\n required = false,\n}: UserSearchSelectProps) {\n const [term, setTerm] = useState('');\n const [manual, setManual] = useState(false);\n\n const search = useUserSearch(term);\n const results = search.data ?? [];\n const active = term.trim().length >= 2;\n\n const pick = (user: DirectoryUser) => {\n onSelect({ userId: user.id, displayName: directoryUserName(user) });\n setTerm('');\n };\n\n // If the directory query fails (e.g. RBAC), offer manual entry automatically.\n const searchUnavailable = search.isError;\n\n if (manual || searchUnavailable) {\n return (\n <FormField\n label=\"User ID\"\n htmlFor=\"member-user-id\"\n required={required}\n hint={\n searchUnavailable\n ? 'User search is unavailable here — paste the auth-svc user id.'\n : 'Paste the auth-svc user id.'\n }\n >\n <input\n id=\"member-user-id\"\n className={fieldInputClass}\n value={userId}\n onChange={(e) => onSelect({ userId: e.target.value, displayName })}\n placeholder=\"user-uuid\"\n />\n {!searchUnavailable && (\n <button\n type=\"button\"\n onClick={() => setManual(false)}\n className=\"mt-1 self-start text-xs font-medium text-primary hover:underline\"\n >\n Search the directory instead\n </button>\n )}\n </FormField>\n );\n }\n\n return (\n <FormField label=\"Athlete / user\" required={required}>\n {userId ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface px-3 py-2\">\n <span className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-text-secondary\">\n <UserIcon className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {displayName || 'Selected user'}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">{userId}</p>\n </div>\n <button\n type=\"button\"\n aria-label=\"Clear selected user\"\n onClick={() => onSelect({ userId: '', displayName: '' })}\n className=\"rounded-md p-1 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n ) : (\n <div className=\"space-y-2\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n className={cn(fieldInputClass, 'pl-9')}\n value={term}\n onChange={(e) => setTerm(e.target.value)}\n placeholder=\"Search by name or email…\"\n aria-label=\"Search users by name or email\"\n />\n {search.isFetching && (\n <Loader2 className=\"absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-text-secondary\" />\n )}\n </div>\n\n {active && !search.isFetching && results.length === 0 && (\n <p className=\"text-xs text-text-secondary\">No users match “{term.trim()}”.</p>\n )}\n\n {results.length > 0 && (\n <ul className=\"max-h-56 divide-y divide-border-seam overflow-auto rounded-lg border border-border-seam bg-bg-surface\">\n {results.map((user) => (\n <li key={user.id}>\n <button\n type=\"button\"\n onClick={() => pick(user)}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-bg-sunken\"\n >\n <span className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-text-secondary\">\n <UserIcon className=\"h-4 w-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-text-primary\">\n {directoryUserName(user)}\n </span>\n <span className=\"block truncate text-xs text-text-secondary\">\n {user.email}\n </span>\n </span>\n <Check className=\"h-4 w-4 shrink-0 text-text-secondary opacity-0\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n\n <button\n type=\"button\"\n onClick={() => setManual(true)}\n className=\"text-xs font-medium text-primary hover:underline\"\n >\n Enter a user ID manually\n </button>\n </div>\n )}\n </FormField>\n );\n}\n"],"mappings":";;;;;;;AA8BA,SAAgB,EAAiB,EAC/B,WACA,gBACA,aACA,cAAW,MACa;CACxB,IAAM,CAAC,GAAM,KAAW,EAAS,GAAG,EAC9B,CAAC,GAAQ,KAAa,EAAS,GAAM,EAErC,IAAS,EAAc,EAAK,EAC5B,IAAU,EAAO,QAAQ,EAAE,EAC3B,IAAS,EAAK,MAAM,CAAC,UAAU,GAE/B,KAAQ,MAAwB;AAEpC,EADA,EAAS;GAAE,QAAQ,EAAK;GAAI,aAAa,EAAkB,EAAK;GAAE,CAAC,EACnE,EAAQ,GAAG;IAIP,IAAoB,EAAO;AAkCjC,QAhCI,KAAU,IAEV,kBAAC,GAAD;EACE,OAAM;EACN,SAAQ;EACE;EACV,MACE,IACI,kEACA;YAPR,CAUE,kBAAC,SAAD;GACE,IAAG;GACH,WAAW;GACX,OAAO;GACP,WAAW,MAAM,EAAS;IAAE,QAAQ,EAAE,OAAO;IAAO;IAAa,CAAC;GAClE,aAAY;GACZ,CAAA,EACD,CAAC,KACA,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAU,GAAM;GAC/B,WAAU;aACX;GAEQ,CAAA,CAED;MAKd,kBAAC,GAAD;EAAW,OAAM;EAA2B;YACzC,IACC,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,QAAD;KAAM,WAAU;eACd,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;KAC3B,CAAA;IACP,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,KAAe;MACd,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAW,CAAA,CAC5D;;IACN,kBAAC,UAAD;KACE,MAAK;KACL,cAAW;KACX,eAAe,EAAS;MAAE,QAAQ;MAAI,aAAa;MAAI,CAAC;KACxD,WAAU;eAEV,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;KAClB,CAAA;IACL;OAEN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD,EAAQ,WAAU,4FAA6F,CAAA;MAC/G,kBAAC,SAAD;OACE,WAAW,EAAG,GAAiB,OAAO;OACtC,OAAO;OACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;OACxC,aAAY;OACZ,cAAW;OACX,CAAA;MACD,EAAO,cACN,kBAAC,GAAD,EAAS,WAAU,sFAAuF,CAAA;MAExG;;IAEL,KAAU,CAAC,EAAO,cAAc,EAAQ,WAAW,KAClD,kBAAC,KAAD;KAAG,WAAU;eAAb;MAA2C;MAAiB,EAAK,MAAM;MAAC;MAAM;;IAG/E,EAAQ,SAAS,KAChB,kBAAC,MAAD;KAAI,WAAU;eACX,EAAQ,KAAK,MACZ,kBAAC,MAAD,EAAA,UACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAK,EAAK;MACzB,WAAU;gBAHZ;OAKE,kBAAC,QAAD;QAAM,WAAU;kBACd,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;QAC3B,CAAA;OACP,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CACE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAkB,EAAK;SACnB,CAAA,EACP,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAK;SACD,CAAA,CACF;;OACP,kBAAC,GAAD,EAAO,WAAU,kDAAmD,CAAA;OAC7D;SACN,EAnBI,EAAK,GAmBT,CACL;KACC,CAAA;IAGP,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAU,GAAK;KAC9B,WAAU;eACX;KAEQ,CAAA;IACL;;EAEE,CAAA"}
@@ -40,8 +40,17 @@ var s = {
40
40
  IN_PERSON: "In Person",
41
41
  ONLINE: "Online",
42
42
  HYBRID: "Hybrid"
43
+ }, p = {
44
+ SPEED: "Speed",
45
+ ENDURANCE: "Endurance",
46
+ STRENGTH: "Strength",
47
+ AGILITY: "Agility",
48
+ ACCURACY: "Accuracy",
49
+ WEIGHT: "Weight",
50
+ HEART_RATE: "Heart Rate",
51
+ CUSTOM: "Custom"
43
52
  };
44
53
  //#endregion
45
- export { d as FIXTURE_TYPE_LABELS, u as MEMBER_ROLE_LABELS, l as PROGRAM_LEVEL_LABELS, f as SESSION_TYPE_LABELS, s as SPORT_ICONS, c as SPORT_LABELS };
54
+ export { d as FIXTURE_TYPE_LABELS, u as MEMBER_ROLE_LABELS, p as METRIC_TYPE_LABELS, l as PROGRAM_LEVEL_LABELS, f as SESSION_TYPE_LABELS, s as SPORT_ICONS, c as SPORT_LABELS };
46
55
 
47
56
  //# sourceMappingURL=domain.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"domain.js","names":[],"sources":["../../../src/atheletebridge/components/domain.ts"],"sourcesContent":["/**\n * Domain display helpers\n * @module atheletebridge/components\n *\n * Centralized, type-safe labels and icon mappings for the AthleteBridge\n * enums so list/detail/form pages render them consistently.\n */\n\nimport {\n Activity,\n Dumbbell,\n Trophy,\n Volleyball,\n Waves,\n Gamepad2,\n Footprints,\n type LucideIcon,\n} from 'lucide-react';\nimport type {\n AthFixtureType,\n AthMemberRole,\n AthMetricType,\n AthProgramLevel,\n AthSessionType,\n AthSport,\n} from '../types';\n\nexport const SPORT_ICONS: Record<AthSport, LucideIcon> = {\n ATHLETICS: Footprints,\n BASKETBALL: Volleyball,\n CRICKET: Trophy,\n ESPORTS: Gamepad2,\n FOOTBALL: Volleyball,\n OTHER: Activity,\n SWIMMING: Waves,\n TENNIS: Dumbbell,\n};\n\nexport const SPORT_LABELS: Record<AthSport, string> = {\n ATHLETICS: 'Athletics',\n BASKETBALL: 'Basketball',\n CRICKET: 'Cricket',\n ESPORTS: 'Esports',\n FOOTBALL: 'Football',\n OTHER: 'Other',\n SWIMMING: 'Swimming',\n TENNIS: 'Tennis',\n};\n\nexport const PROGRAM_LEVEL_LABELS: Record<AthProgramLevel, string> = {\n BEGINNER: 'Beginner',\n INTERMEDIATE: 'Intermediate',\n ADVANCED: 'Advanced',\n ELITE: 'Elite',\n};\n\nexport const MEMBER_ROLE_LABELS: Record<AthMemberRole, string> = {\n PLAYER: 'Player',\n CAPTAIN: 'Captain',\n COACH: 'Coach',\n ASSISTANT_COACH: 'Assistant Coach',\n PHYSIO: 'Physio',\n MANAGER: 'Manager',\n};\n\nexport const FIXTURE_TYPE_LABELS: Record<AthFixtureType, string> = {\n FRIENDLY: 'Friendly',\n LEAGUE: 'League',\n CUP: 'Cup',\n TOURNAMENT: 'Tournament',\n SCRIMMAGE: 'Scrimmage',\n};\n\nexport const SESSION_TYPE_LABELS: Record<AthSessionType, string> = {\n IN_PERSON: 'In Person',\n ONLINE: 'Online',\n HYBRID: 'Hybrid',\n};\n\nexport const METRIC_TYPE_LABELS: Record<AthMetricType, string> = {\n SPEED: 'Speed',\n ENDURANCE: 'Endurance',\n STRENGTH: 'Strength',\n AGILITY: 'Agility',\n ACCURACY: 'Accuracy',\n WEIGHT: 'Weight',\n HEART_RATE: 'Heart Rate',\n CUSTOM: 'Custom',\n};\n\nexport const SPORT_OPTIONS = Object.keys(SPORT_LABELS) as AthSport[];\nexport const PROGRAM_LEVEL_OPTIONS = Object.keys(PROGRAM_LEVEL_LABELS) as AthProgramLevel[];\nexport const MEMBER_ROLE_OPTIONS = Object.keys(MEMBER_ROLE_LABELS) as AthMemberRole[];\nexport const FIXTURE_TYPE_OPTIONS = Object.keys(FIXTURE_TYPE_LABELS) as AthFixtureType[];\nexport const SESSION_TYPE_OPTIONS = Object.keys(SESSION_TYPE_LABELS) as AthSessionType[];\n\n/** Humanize an enum value for display (fallback when no explicit label exists). */\nexport function humanizeEnum(value: string): string {\n return value\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n"],"mappings":";;AA2BA,IAAa,IAA4C;CACvD,WAAW;CACX,YAAY;CACZ,SAAS;CACT,SAAS;CACT,UAAU;CACV,OAAO;CACP,UAAU;CACV,QAAQ;CACT,EAEY,IAAyC;CACpD,WAAW;CACX,YAAY;CACZ,SAAS;CACT,SAAS;CACT,UAAU;CACV,OAAO;CACP,UAAU;CACV,QAAQ;CACT,EAEY,IAAwD;CACnE,UAAU;CACV,cAAc;CACd,UAAU;CACV,OAAO;CACR,EAEY,IAAoD;CAC/D,QAAQ;CACR,SAAS;CACT,OAAO;CACP,iBAAiB;CACjB,QAAQ;CACR,SAAS;CACV,EAEY,IAAsD;CACjE,UAAU;CACV,QAAQ;CACR,KAAK;CACL,YAAY;CACZ,WAAW;CACZ,EAEY,IAAsD;CACjE,WAAW;CACX,QAAQ;CACR,QAAQ;CACT"}
1
+ {"version":3,"file":"domain.js","names":[],"sources":["../../../src/atheletebridge/components/domain.ts"],"sourcesContent":["/**\n * Domain display helpers\n * @module atheletebridge/components\n *\n * Centralized, type-safe labels and icon mappings for the AthleteBridge\n * enums so list/detail/form pages render them consistently.\n */\n\nimport {\n Activity,\n Dumbbell,\n Trophy,\n Volleyball,\n Waves,\n Gamepad2,\n Footprints,\n type LucideIcon,\n} from 'lucide-react';\nimport type {\n AthFixtureType,\n AthMemberRole,\n AthMetricType,\n AthProgramLevel,\n AthSessionType,\n AthSport,\n} from '../types';\n\nexport const SPORT_ICONS: Record<AthSport, LucideIcon> = {\n ATHLETICS: Footprints,\n BASKETBALL: Volleyball,\n CRICKET: Trophy,\n ESPORTS: Gamepad2,\n FOOTBALL: Volleyball,\n OTHER: Activity,\n SWIMMING: Waves,\n TENNIS: Dumbbell,\n};\n\nexport const SPORT_LABELS: Record<AthSport, string> = {\n ATHLETICS: 'Athletics',\n BASKETBALL: 'Basketball',\n CRICKET: 'Cricket',\n ESPORTS: 'Esports',\n FOOTBALL: 'Football',\n OTHER: 'Other',\n SWIMMING: 'Swimming',\n TENNIS: 'Tennis',\n};\n\nexport const PROGRAM_LEVEL_LABELS: Record<AthProgramLevel, string> = {\n BEGINNER: 'Beginner',\n INTERMEDIATE: 'Intermediate',\n ADVANCED: 'Advanced',\n ELITE: 'Elite',\n};\n\nexport const MEMBER_ROLE_LABELS: Record<AthMemberRole, string> = {\n PLAYER: 'Player',\n CAPTAIN: 'Captain',\n COACH: 'Coach',\n ASSISTANT_COACH: 'Assistant Coach',\n PHYSIO: 'Physio',\n MANAGER: 'Manager',\n};\n\nexport const FIXTURE_TYPE_LABELS: Record<AthFixtureType, string> = {\n FRIENDLY: 'Friendly',\n LEAGUE: 'League',\n CUP: 'Cup',\n TOURNAMENT: 'Tournament',\n SCRIMMAGE: 'Scrimmage',\n};\n\nexport const SESSION_TYPE_LABELS: Record<AthSessionType, string> = {\n IN_PERSON: 'In Person',\n ONLINE: 'Online',\n HYBRID: 'Hybrid',\n};\n\nexport const METRIC_TYPE_LABELS: Record<AthMetricType, string> = {\n SPEED: 'Speed',\n ENDURANCE: 'Endurance',\n STRENGTH: 'Strength',\n AGILITY: 'Agility',\n ACCURACY: 'Accuracy',\n WEIGHT: 'Weight',\n HEART_RATE: 'Heart Rate',\n CUSTOM: 'Custom',\n};\n\nexport const SPORT_OPTIONS = Object.keys(SPORT_LABELS) as AthSport[];\nexport const PROGRAM_LEVEL_OPTIONS = Object.keys(PROGRAM_LEVEL_LABELS) as AthProgramLevel[];\nexport const MEMBER_ROLE_OPTIONS = Object.keys(MEMBER_ROLE_LABELS) as AthMemberRole[];\nexport const FIXTURE_TYPE_OPTIONS = Object.keys(FIXTURE_TYPE_LABELS) as AthFixtureType[];\nexport const SESSION_TYPE_OPTIONS = Object.keys(SESSION_TYPE_LABELS) as AthSessionType[];\n\n/** Humanize an enum value for display (fallback when no explicit label exists). */\nexport function humanizeEnum(value: string): string {\n return value\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n"],"mappings":";;AA2BA,IAAa,IAA4C;CACvD,WAAW;CACX,YAAY;CACZ,SAAS;CACT,SAAS;CACT,UAAU;CACV,OAAO;CACP,UAAU;CACV,QAAQ;CACT,EAEY,IAAyC;CACpD,WAAW;CACX,YAAY;CACZ,SAAS;CACT,SAAS;CACT,UAAU;CACV,OAAO;CACP,UAAU;CACV,QAAQ;CACT,EAEY,IAAwD;CACnE,UAAU;CACV,cAAc;CACd,UAAU;CACV,OAAO;CACR,EAEY,IAAoD;CAC/D,QAAQ;CACR,SAAS;CACT,OAAO;CACP,iBAAiB;CACjB,QAAQ;CACR,SAAS;CACV,EAEY,IAAsD;CACjE,UAAU;CACV,QAAQ;CACR,KAAK;CACL,YAAY;CACZ,WAAW;CACZ,EAEY,IAAsD;CACjE,WAAW;CACX,QAAQ;CACR,QAAQ;CACT,EAEY,IAAoD;CAC/D,OAAO;CACP,WAAW;CACX,UAAU;CACV,SAAS;CACT,UAAU;CACV,QAAQ;CACR,YAAY;CACZ,QAAQ;CACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"AthleteBridgeContext.js","names":[],"sources":["../../../src/atheletebridge/context/AthleteBridgeContext.tsx"],"sourcesContent":["/**\n * AthleteBridge Context Provider\n * @module atheletebridge/context\n *\n * The provider exposes the host-supplied props (basePath, workspaceId,\n * tenantId, apiGatewayUrl, authToken, currentUser, entity-select callbacks) plus\n * path/navigation helpers. The Root mounts this with the exact props the shell\n * passes; the export name/signature is part of the host contract.\n */\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createContext, useContext, useMemo, useCallback } from 'react';\nimport { MemoryRouter, useNavigate as useRouterNavigate } from 'react-router-dom';\nimport type { AthleteBridgeRootProps } from '../types';\nimport { joinPath } from '../utils/navigation';\n\n// ============================================================================\n// Context\n// ============================================================================\n\ninterface AthleteBridgeContextValue\n extends Omit<AthleteBridgeRootProps, 'registerNavItems' | 'registerFooterItems' | 'navigate'> {\n isStandalone: boolean;\n /** Shell's navigate function (only available in integrated mode) */\n navigate?: (path: string) => void;\n /** Navigate to a path relative to basePath */\n navigateTo: (relativePath: string) => void;\n /** Get the full path for a relative path */\n getPath: (relativePath: string) => string;\n}\n\nconst AthleteBridgeContext = createContext<AthleteBridgeContextValue | null>(null);\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useAthleteBridge(): AthleteBridgeContextValue {\n const context = useContext(AthleteBridgeContext);\n if (!context) {\n throw new Error('useAthleteBridge must be used within a AthleteBridgeProvider');\n }\n return context;\n}\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\ntype ProviderProps = Omit<AthleteBridgeRootProps, 'registerNavItems' | 'registerFooterItems'> & {\n isStandalone: boolean;\n};\n\n/** Provider for standalone mode (has access to MemoryRouter) */\nconst StandaloneProviderInner: FC<PropsWithChildren<ProviderProps>> = ({\n children,\n basePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n}) => {\n const routerNavigate = useRouterNavigate();\n const effectiveBasePath = basePath || '/';\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n const fullPath = joinPath(effectiveBasePath, relativePath);\n routerNavigate(fullPath);\n },\n [effectiveBasePath, routerNavigate]\n );\n\n const contextValue = useMemo<AthleteBridgeContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate: undefined,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n isStandalone: true,\n navigateTo,\n getPath,\n }),\n [\n effectiveBasePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n navigateTo,\n getPath,\n ]\n );\n\n return (\n <AthleteBridgeContext.Provider value={contextValue}>{children}</AthleteBridgeContext.Provider>\n );\n};\n\n/** Provider for integrated mode (shell provides navigate) */\nconst IntegratedProviderInner: FC<\n PropsWithChildren<ProviderProps & { navigate: (path: string) => void }>\n> = ({\n children,\n basePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n}) => {\n const effectiveBasePath = basePath || '/';\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n const fullPath = joinPath(effectiveBasePath, relativePath);\n navigate(fullPath);\n },\n [effectiveBasePath, navigate]\n );\n\n const contextValue = useMemo<AthleteBridgeContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n isStandalone: false,\n navigateTo,\n getPath,\n }),\n [\n effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n navigateTo,\n getPath,\n ]\n );\n\n return (\n <AthleteBridgeContext.Provider value={contextValue}>{children}</AthleteBridgeContext.Provider>\n );\n};\n\nexport const AthleteBridgeProvider: FC<PropsWithChildren<AthleteBridgeRootProps>> = (props) => {\n const { children, navigate } = props;\n // Standalone mode: no navigate function provided (MFE manages its own router)\n // Integrated mode: navigate function provided by shell (shell provides router)\n const isStandalone = !navigate;\n\n // Standalone mode: wrap in MemoryRouter\n if (isStandalone) {\n return (\n <MemoryRouter>\n <StandaloneProviderInner {...props} isStandalone={true}>\n {children}\n </StandaloneProviderInner>\n </MemoryRouter>\n );\n }\n\n // Integrated mode: shell provides router\n return (\n <IntegratedProviderInner {...props} navigate={navigate} isStandalone={false}>\n {children}\n </IntegratedProviderInner>\n );\n};\n"],"mappings":";;;;;AA+BA,IAAM,IAAuB,EAAgD,KAAK;AAMlF,SAAgB,IAA8C;CAC5D,IAAM,IAAU,EAAW,EAAqB;AAChD,KAAI,CAAC,EACH,OAAU,MAAM,+DAA+D;AAEjF,QAAO;;AAYT,IAAM,KAAiE,EACrE,aACA,aACA,gBACA,aACA,gBACA,kBACA,cACA,iBACA,yBACI;CACJ,IAAM,IAAiB,GAAmB,EACpC,IAAoB,KAAY,KAEhC,IAAU,GACb,MAAyB,EAAS,GAAmB,EAAa,EACnE,CAAC,EAAkB,CACpB,EAEK,IAAa,GAChB,MAAyB;AAExB,IADiB,EAAS,GAAmB,EAAa,CAClC;IAE1B,CAAC,GAAmB,EAAe,CACpC,EAEK,IAAe,SACZ;EACL,UAAU;EACV,UAAU,KAAA;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QACE,kBAAC,EAAqB,UAAtB;EAA+B,OAAO;EAAe;EAAyC,CAAA;GAK5F,KAED,EACH,aACA,aACA,aACA,gBACA,aACA,gBACA,kBACA,cACA,iBACA,yBACI;CACJ,IAAM,IAAoB,KAAY,KAEhC,IAAU,GACb,MAAyB,EAAS,GAAmB,EAAa,EACnE,CAAC,EAAkB,CACpB,EAEK,IAAa,GAChB,MAAyB;AAExB,IADiB,EAAS,GAAmB,EAAa,CACxC;IAEpB,CAAC,GAAmB,EAAS,CAC9B,EAEK,IAAe,SACZ;EACL,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QACE,kBAAC,EAAqB,UAAtB;EAA+B,OAAO;EAAe;EAAyC,CAAA;GAIrF,KAAwE,MAAU;CAC7F,IAAM,EAAE,aAAU,gBAAa;AAiB/B,QAdsB,IAepB,kBAAC,GAAD;EAAyB,GAAI;EAAiB;EAAU,cAAc;EACnE;EACuB,CAAA,GAZxB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAyB,GAAI;EAAO,cAAc;EAC/C;EACuB,CAAA,EACb,CAAA"}
1
+ {"version":3,"file":"AthleteBridgeContext.js","names":[],"sources":["../../../src/atheletebridge/context/AthleteBridgeContext.tsx"],"sourcesContent":["/**\n * AthleteBridge Context Provider\n * @module atheletebridge/context\n *\n * The provider exposes the host-supplied props (basePath, workspaceId,\n * tenantId, apiGatewayUrl, authToken, currentUser, entity-select callbacks) plus\n * path/navigation helpers. The Root mounts this with the exact props the shell\n * passes; the export name/signature is part of the host contract.\n */\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createContext, useContext, useMemo, useCallback } from 'react';\nimport { MemoryRouter, useNavigate as useRouterNavigate } from 'react-router-dom';\nimport type { AthleteBridgeRootProps } from '../types';\nimport { joinPath } from '../utils/navigation';\n\n// ============================================================================\n// Context\n// ============================================================================\n\ninterface AthleteBridgeContextValue extends Omit<\n AthleteBridgeRootProps,\n 'registerNavItems' | 'registerFooterItems' | 'navigate'\n> {\n isStandalone: boolean;\n /** Shell's navigate function (only available in integrated mode) */\n navigate?: (path: string) => void;\n /** Navigate to a path relative to basePath */\n navigateTo: (relativePath: string) => void;\n /** Get the full path for a relative path */\n getPath: (relativePath: string) => string;\n}\n\nconst AthleteBridgeContext = createContext<AthleteBridgeContextValue | null>(null);\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useAthleteBridge(): AthleteBridgeContextValue {\n const context = useContext(AthleteBridgeContext);\n if (!context) {\n throw new Error('useAthleteBridge must be used within a AthleteBridgeProvider');\n }\n return context;\n}\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\ntype ProviderProps = Omit<AthleteBridgeRootProps, 'registerNavItems' | 'registerFooterItems'> & {\n isStandalone: boolean;\n};\n\n/** Provider for standalone mode (has access to MemoryRouter) */\nconst StandaloneProviderInner: FC<PropsWithChildren<ProviderProps>> = ({\n children,\n basePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n}) => {\n const routerNavigate = useRouterNavigate();\n const effectiveBasePath = basePath || '/';\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n const fullPath = joinPath(effectiveBasePath, relativePath);\n routerNavigate(fullPath);\n },\n [effectiveBasePath, routerNavigate]\n );\n\n const contextValue = useMemo<AthleteBridgeContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate: undefined,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n isStandalone: true,\n navigateTo,\n getPath,\n }),\n [\n effectiveBasePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n navigateTo,\n getPath,\n ]\n );\n\n return (\n <AthleteBridgeContext.Provider value={contextValue}>{children}</AthleteBridgeContext.Provider>\n );\n};\n\n/** Provider for integrated mode (shell provides navigate) */\nconst IntegratedProviderInner: FC<\n PropsWithChildren<ProviderProps & { navigate: (path: string) => void }>\n> = ({\n children,\n basePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n}) => {\n const effectiveBasePath = basePath || '/';\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n const fullPath = joinPath(effectiveBasePath, relativePath);\n navigate(fullPath);\n },\n [effectiveBasePath, navigate]\n );\n\n const contextValue = useMemo<AthleteBridgeContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n isStandalone: false,\n navigateTo,\n getPath,\n }),\n [\n effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n onTeamSelect,\n onFixtureSelect,\n navigateTo,\n getPath,\n ]\n );\n\n return (\n <AthleteBridgeContext.Provider value={contextValue}>{children}</AthleteBridgeContext.Provider>\n );\n};\n\nexport const AthleteBridgeProvider: FC<PropsWithChildren<AthleteBridgeRootProps>> = (props) => {\n const { children, navigate } = props;\n // Standalone mode: no navigate function provided (MFE manages its own router)\n // Integrated mode: navigate function provided by shell (shell provides router)\n const isStandalone = !navigate;\n\n // Standalone mode: wrap in MemoryRouter\n if (isStandalone) {\n return (\n <MemoryRouter>\n <StandaloneProviderInner {...props} isStandalone={true}>\n {children}\n </StandaloneProviderInner>\n </MemoryRouter>\n );\n }\n\n // Integrated mode: shell provides router\n return (\n <IntegratedProviderInner {...props} navigate={navigate} isStandalone={false}>\n {children}\n </IntegratedProviderInner>\n );\n};\n"],"mappings":";;;;;AAiCA,IAAM,IAAuB,EAAgD,KAAK;AAMlF,SAAgB,IAA8C;CAC5D,IAAM,IAAU,EAAW,EAAqB;AAChD,KAAI,CAAC,EACH,OAAU,MAAM,+DAA+D;AAEjF,QAAO;;AAYT,IAAM,KAAiE,EACrE,aACA,aACA,gBACA,aACA,gBACA,kBACA,cACA,iBACA,yBACI;CACJ,IAAM,IAAiB,GAAmB,EACpC,IAAoB,KAAY,KAEhC,IAAU,GACb,MAAyB,EAAS,GAAmB,EAAa,EACnE,CAAC,EAAkB,CACpB,EAEK,IAAa,GAChB,MAAyB;AAExB,IADiB,EAAS,GAAmB,EAAa,CAClC;IAE1B,CAAC,GAAmB,EAAe,CACpC,EAEK,IAAe,SACZ;EACL,UAAU;EACV,UAAU,KAAA;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QACE,kBAAC,EAAqB,UAAtB;EAA+B,OAAO;EAAe;EAAyC,CAAA;GAK5F,KAED,EACH,aACA,aACA,aACA,gBACA,aACA,gBACA,kBACA,cACA,iBACA,yBACI;CACJ,IAAM,IAAoB,KAAY,KAEhC,IAAU,GACb,MAAyB,EAAS,GAAmB,EAAa,EACnE,CAAC,EAAkB,CACpB,EAEK,IAAa,GAChB,MAAyB;AAExB,IADiB,EAAS,GAAmB,EAAa,CACxC;IAEpB,CAAC,GAAmB,EAAS,CAC9B,EAEK,IAAe,SACZ;EACL,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QACE,kBAAC,EAAqB,UAAtB;EAA+B,OAAO;EAAe;EAAyC,CAAA;GAIrF,KAAwE,MAAU;CAC7F,IAAM,EAAE,aAAU,gBAAa;AAiB/B,QAdsB,IAepB,kBAAC,GAAD;EAAyB,GAAI;EAAiB;EAAU,cAAc;EACnE;EACuB,CAAA,GAZxB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAyB,GAAI;EAAO,cAAc;EAC/C;EACuB,CAAA,EACb,CAAA"}