@burdenoff/microfe-atheletebridge 2026.625.2 → 2026.628.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 (162) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.js +49 -129
  2. package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
  3. package/dist/atheletebridge/AthleteBridgeRoutes.js +65 -184
  4. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  5. package/dist/atheletebridge/components/CursorPager.js +34 -0
  6. package/dist/atheletebridge/components/CursorPager.js.map +1 -0
  7. package/dist/atheletebridge/components/FilterSelect.js +22 -0
  8. package/dist/atheletebridge/components/FilterSelect.js.map +1 -0
  9. package/dist/atheletebridge/components/FixtureCard.js +76 -0
  10. package/dist/atheletebridge/components/FixtureCard.js.map +1 -0
  11. package/dist/atheletebridge/components/LoadingState.js +36 -0
  12. package/dist/atheletebridge/components/LoadingState.js.map +1 -0
  13. package/dist/atheletebridge/components/ProgramCard.js +69 -0
  14. package/dist/atheletebridge/components/ProgramCard.js.map +1 -0
  15. package/dist/atheletebridge/components/SessionCard.js +76 -0
  16. package/dist/atheletebridge/components/SessionCard.js.map +1 -0
  17. package/dist/atheletebridge/components/StatusBadge.js +44 -35
  18. package/dist/atheletebridge/components/StatusBadge.js.map +1 -1
  19. package/dist/atheletebridge/components/TeamCard.js +81 -0
  20. package/dist/atheletebridge/components/TeamCard.js.map +1 -0
  21. package/dist/atheletebridge/components/domain.js +47 -0
  22. package/dist/atheletebridge/components/domain.js.map +1 -0
  23. package/dist/atheletebridge/components/form.js +29 -0
  24. package/dist/atheletebridge/components/form.js.map +1 -0
  25. package/dist/atheletebridge/context/AthleteBridgeContext.js +6 -6
  26. package/dist/atheletebridge/context/AthleteBridgeContext.js.map +1 -1
  27. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +342 -165
  28. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  29. package/dist/atheletebridge/index.js +1 -1
  30. package/dist/atheletebridge/pages/DashboardPage.js +169 -0
  31. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -0
  32. package/dist/atheletebridge/pages/StandingsPage.js +166 -0
  33. package/dist/atheletebridge/pages/StandingsPage.js.map +1 -0
  34. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +201 -0
  35. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -0
  36. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js +205 -0
  37. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js.map +1 -0
  38. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js +92 -0
  39. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -0
  40. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +374 -0
  41. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -0
  42. package/dist/atheletebridge/pages/programs/ProgramFormPage.js +207 -0
  43. package/dist/atheletebridge/pages/programs/ProgramFormPage.js.map +1 -0
  44. package/dist/atheletebridge/pages/programs/ProgramsListPage.js +113 -0
  45. package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -0
  46. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +224 -0
  47. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -0
  48. package/dist/atheletebridge/pages/sessions/SessionFormPage.js +206 -0
  49. package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -0
  50. package/dist/atheletebridge/pages/sessions/SessionsListPage.js +92 -0
  51. package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -0
  52. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +350 -0
  53. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -0
  54. package/dist/atheletebridge/pages/teams/TeamFormPage.js +222 -0
  55. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -0
  56. package/dist/atheletebridge/pages/teams/TeamsListPage.js +101 -0
  57. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -0
  58. package/dist/atheletebridge/store/atheletebridgeStore.js +2 -13
  59. package/dist/atheletebridge/store/atheletebridgeStore.js.map +1 -1
  60. package/dist/atheletebridge/utils/datetime.js +10 -0
  61. package/dist/atheletebridge/utils/datetime.js.map +1 -0
  62. package/dist/atheletebridge/utils/formatters.js +1 -4
  63. package/dist/atheletebridge/utils/formatters.js.map +1 -1
  64. package/package.json +1 -1
  65. package/dist/atheletebridge/components/InvestmentCard.js +0 -96
  66. package/dist/atheletebridge/components/InvestmentCard.js.map +0 -1
  67. package/dist/atheletebridge/components/RatingDisplay.js +0 -35
  68. package/dist/atheletebridge/components/RatingDisplay.js.map +0 -1
  69. package/dist/atheletebridge/mocks/data.js +0 -1517
  70. package/dist/atheletebridge/mocks/data.js.map +0 -1
  71. package/dist/atheletebridge/mocks/users.js +0 -34
  72. package/dist/atheletebridge/mocks/users.js.map +0 -1
  73. package/dist/atheletebridge/pages/HomePage.js +0 -936
  74. package/dist/atheletebridge/pages/HomePage.js.map +0 -1
  75. package/dist/atheletebridge/pages/admin/AdminAnalyticsPage.js +0 -653
  76. package/dist/atheletebridge/pages/admin/AdminAnalyticsPage.js.map +0 -1
  77. package/dist/atheletebridge/pages/admin/AdminDashboard.js +0 -671
  78. package/dist/atheletebridge/pages/admin/AdminDashboard.js.map +0 -1
  79. package/dist/atheletebridge/pages/admin/AdminFinancialPage.js +0 -429
  80. package/dist/atheletebridge/pages/admin/AdminFinancialPage.js.map +0 -1
  81. package/dist/atheletebridge/pages/admin/AdminOrdersPage.js +0 -667
  82. package/dist/atheletebridge/pages/admin/AdminOrdersPage.js.map +0 -1
  83. package/dist/atheletebridge/pages/admin/AdminProfilePage.js +0 -261
  84. package/dist/atheletebridge/pages/admin/AdminProfilePage.js.map +0 -1
  85. package/dist/atheletebridge/pages/admin/AdminSettingsPage.js +0 -653
  86. package/dist/atheletebridge/pages/admin/AdminSettingsPage.js.map +0 -1
  87. package/dist/atheletebridge/pages/admin/CartManagementPage.js +0 -876
  88. package/dist/atheletebridge/pages/admin/CartManagementPage.js.map +0 -1
  89. package/dist/atheletebridge/pages/admin/UserManagementPage.js +0 -900
  90. package/dist/atheletebridge/pages/admin/UserManagementPage.js.map +0 -1
  91. package/dist/atheletebridge/pages/cart-owner/AnalyticsDashboard.js +0 -839
  92. package/dist/atheletebridge/pages/cart-owner/AnalyticsDashboard.js.map +0 -1
  93. package/dist/atheletebridge/pages/cart-owner/BusinessSettingsPage.js +0 -704
  94. package/dist/atheletebridge/pages/cart-owner/BusinessSettingsPage.js.map +0 -1
  95. package/dist/atheletebridge/pages/cart-owner/CartOwnerDashboard.js +0 -792
  96. package/dist/atheletebridge/pages/cart-owner/CartOwnerDashboard.js.map +0 -1
  97. package/dist/atheletebridge/pages/cart-owner/CartOwnerProfilePage.js +0 -891
  98. package/dist/atheletebridge/pages/cart-owner/CartOwnerProfilePage.js.map +0 -1
  99. package/dist/atheletebridge/pages/cart-owner/CartServiceConfigPage.js +0 -633
  100. package/dist/atheletebridge/pages/cart-owner/CartServiceConfigPage.js.map +0 -1
  101. package/dist/atheletebridge/pages/cart-owner/InventoryManagementPage.js +0 -913
  102. package/dist/atheletebridge/pages/cart-owner/InventoryManagementPage.js.map +0 -1
  103. package/dist/atheletebridge/pages/cart-owner/OrderManagementPage.js +0 -881
  104. package/dist/atheletebridge/pages/cart-owner/OrderManagementPage.js.map +0 -1
  105. package/dist/atheletebridge/pages/cart-owner/StaffManagementPage.js +0 -841
  106. package/dist/atheletebridge/pages/cart-owner/StaffManagementPage.js.map +0 -1
  107. package/dist/atheletebridge/pages/common/HelpSupportPage.js +0 -1319
  108. package/dist/atheletebridge/pages/common/HelpSupportPage.js.map +0 -1
  109. package/dist/atheletebridge/pages/common/NotificationCenterPage.js +0 -674
  110. package/dist/atheletebridge/pages/common/NotificationCenterPage.js.map +0 -1
  111. package/dist/atheletebridge/pages/common/SettingsPage.js +0 -972
  112. package/dist/atheletebridge/pages/common/SettingsPage.js.map +0 -1
  113. package/dist/atheletebridge/pages/customer/BookingDetailsPage.js +0 -602
  114. package/dist/atheletebridge/pages/customer/BookingDetailsPage.js.map +0 -1
  115. package/dist/atheletebridge/pages/customer/CartDetailPage.js +0 -656
  116. package/dist/atheletebridge/pages/customer/CartDetailPage.js.map +0 -1
  117. package/dist/atheletebridge/pages/customer/CartDiscoveryPage.js +0 -558
  118. package/dist/atheletebridge/pages/customer/CartDiscoveryPage.js.map +0 -1
  119. package/dist/atheletebridge/pages/customer/CheckoutPage.js +0 -536
  120. package/dist/atheletebridge/pages/customer/CheckoutPage.js.map +0 -1
  121. package/dist/atheletebridge/pages/customer/CustomerDashboard.js +0 -539
  122. package/dist/atheletebridge/pages/customer/CustomerDashboard.js.map +0 -1
  123. package/dist/atheletebridge/pages/customer/CustomerProfilePage.js +0 -657
  124. package/dist/atheletebridge/pages/customer/CustomerProfilePage.js.map +0 -1
  125. package/dist/atheletebridge/pages/customer/DirectServiceBookingPage.js +0 -635
  126. package/dist/atheletebridge/pages/customer/DirectServiceBookingPage.js.map +0 -1
  127. package/dist/atheletebridge/pages/customer/FavoritesPage.js +0 -486
  128. package/dist/atheletebridge/pages/customer/FavoritesPage.js.map +0 -1
  129. package/dist/atheletebridge/pages/customer/OrderHistoryPage.js +0 -447
  130. package/dist/atheletebridge/pages/customer/OrderHistoryPage.js.map +0 -1
  131. package/dist/atheletebridge/pages/customer/OrderTrackingPage.js +0 -393
  132. package/dist/atheletebridge/pages/customer/OrderTrackingPage.js.map +0 -1
  133. package/dist/atheletebridge/pages/customer/PaymentMethodsPage.js +0 -494
  134. package/dist/atheletebridge/pages/customer/PaymentMethodsPage.js.map +0 -1
  135. package/dist/atheletebridge/pages/customer/ReviewsPage.js +0 -615
  136. package/dist/atheletebridge/pages/customer/ReviewsPage.js.map +0 -1
  137. package/dist/atheletebridge/pages/customer/SavedAddressesPage.js +0 -451
  138. package/dist/atheletebridge/pages/customer/SavedAddressesPage.js.map +0 -1
  139. package/dist/atheletebridge/pages/investor/InvestmentDetailsPage.js +0 -881
  140. package/dist/atheletebridge/pages/investor/InvestmentDetailsPage.js.map +0 -1
  141. package/dist/atheletebridge/pages/investor/InvestmentOpportunitiesPage.js +0 -945
  142. package/dist/atheletebridge/pages/investor/InvestmentOpportunitiesPage.js.map +0 -1
  143. package/dist/atheletebridge/pages/investor/InvestorAnalyticsPage.js +0 -686
  144. package/dist/atheletebridge/pages/investor/InvestorAnalyticsPage.js.map +0 -1
  145. package/dist/atheletebridge/pages/investor/InvestorDashboard.js +0 -453
  146. package/dist/atheletebridge/pages/investor/InvestorDashboard.js.map +0 -1
  147. package/dist/atheletebridge/pages/investor/InvestorInvestmentsPage.js +0 -405
  148. package/dist/atheletebridge/pages/investor/InvestorInvestmentsPage.js.map +0 -1
  149. package/dist/atheletebridge/pages/investor/InvestorPortfolioPage.js +0 -577
  150. package/dist/atheletebridge/pages/investor/InvestorPortfolioPage.js.map +0 -1
  151. package/dist/atheletebridge/pages/investor/InvestorProfilePage.js +0 -1069
  152. package/dist/atheletebridge/pages/investor/InvestorProfilePage.js.map +0 -1
  153. package/dist/atheletebridge/pages/worker/TaskDetailsPage.js +0 -530
  154. package/dist/atheletebridge/pages/worker/TaskDetailsPage.js.map +0 -1
  155. package/dist/atheletebridge/pages/worker/WorkerDashboard.js +0 -669
  156. package/dist/atheletebridge/pages/worker/WorkerDashboard.js.map +0 -1
  157. package/dist/atheletebridge/pages/worker/WorkerOrdersPage.js +0 -681
  158. package/dist/atheletebridge/pages/worker/WorkerOrdersPage.js.map +0 -1
  159. package/dist/atheletebridge/pages/worker/WorkerProfilePage.js +0 -691
  160. package/dist/atheletebridge/pages/worker/WorkerProfilePage.js.map +0 -1
  161. package/dist/atheletebridge/pages/worker/WorkerSchedulePage.js +0 -588
  162. package/dist/atheletebridge/pages/worker/WorkerSchedulePage.js.map +0 -1
@@ -0,0 +1,222 @@
1
+ import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
2
+ import { PageLayout as t } from "../../components/PageLayout.js";
3
+ import { SPORT_LABELS as n } from "../../components/domain.js";
4
+ import { ErrorState as r, LoadingState as i } from "../../components/LoadingState.js";
5
+ import { useCreateTeam as a, useTeam as o, useUpdateTeam as s } from "../../hooks/useAthleteBridgeApi.js";
6
+ import { FormField as c, fieldInputClass as l } from "../../components/form.js";
7
+ import { useEffect as u, useState as d } from "react";
8
+ import { ArrowLeft as f, Loader2 as p, Save as m } from "lucide-react";
9
+ import { useParams as h } from "react-router-dom";
10
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
11
+ //#region src/atheletebridge/pages/teams/TeamFormPage.tsx
12
+ var v = Object.keys(n), y = [
13
+ "FORMING",
14
+ "ACTIVE",
15
+ "INACTIVE",
16
+ "ARCHIVED"
17
+ ], b = {
18
+ name: "",
19
+ sport: "OTHER",
20
+ status: "FORMING",
21
+ description: "",
22
+ ageGroup: "",
23
+ season: "",
24
+ homeVenue: "",
25
+ tagsText: ""
26
+ };
27
+ function x() {
28
+ let { id: x } = h(), S = !!x, { navigateTo: C } = e(), w = o(x), T = a(), E = s(), [D, O] = d(b), [k, A] = d(null);
29
+ u(() => {
30
+ let e = w.data;
31
+ S && e && O({
32
+ name: e.name,
33
+ sport: e.sport,
34
+ status: e.status,
35
+ description: e.description ?? "",
36
+ ageGroup: e.ageGroup ?? "",
37
+ season: e.season ?? "",
38
+ homeVenue: e.homeVenue ?? "",
39
+ tagsText: e.tags.join(", ")
40
+ });
41
+ }, [S, w.data]);
42
+ let j = (e, t) => O((n) => ({
43
+ ...n,
44
+ [e]: t
45
+ })), M = (e) => e.split(",").map((e) => e.trim()).filter(Boolean), N = async (e) => {
46
+ if (e.preventDefault(), A(null), !D.name.trim()) {
47
+ A("Team name is required.");
48
+ return;
49
+ }
50
+ let t = M(D.tagsText);
51
+ try {
52
+ S && x ? (await E.mutateAsync({
53
+ id: x,
54
+ input: {
55
+ name: D.name.trim(),
56
+ sport: D.sport,
57
+ status: D.status,
58
+ description: D.description.trim() || void 0,
59
+ ageGroup: D.ageGroup.trim() || void 0,
60
+ season: D.season.trim() || void 0,
61
+ homeVenue: D.homeVenue.trim() || void 0,
62
+ tags: t
63
+ }
64
+ }), C(`/teams/${x}`)) : C(`/teams/${(await T.mutateAsync({
65
+ name: D.name.trim(),
66
+ sport: D.sport,
67
+ status: D.status,
68
+ description: D.description.trim() || void 0,
69
+ ageGroup: D.ageGroup.trim() || void 0,
70
+ season: D.season.trim() || void 0,
71
+ homeVenue: D.homeVenue.trim() || void 0,
72
+ tags: t
73
+ })).id}`);
74
+ } catch (e) {
75
+ A(e instanceof Error ? e.message : "Failed to save team.");
76
+ }
77
+ }, P = T.isPending || E.isPending;
78
+ return S && w.isLoading ? /* @__PURE__ */ g(t, {
79
+ title: "Edit team",
80
+ children: /* @__PURE__ */ g(i, { label: "Loading team…" })
81
+ }) : S && (w.isError || !w.isLoading && !w.data) ? /* @__PURE__ */ g(t, {
82
+ title: "Edit team",
83
+ children: /* @__PURE__ */ g(r, {
84
+ title: "Team not found",
85
+ message: "This team does not exist or you do not have access to it.",
86
+ onRetry: () => C("/teams")
87
+ })
88
+ }) : /* @__PURE__ */ g(t, {
89
+ title: S ? "Edit team" : "New team",
90
+ description: S ? "Update the squad details." : "Create a new squad to build a roster.",
91
+ actions: /* @__PURE__ */ _("button", {
92
+ type: "button",
93
+ onClick: () => C(S && x ? `/teams/${x}` : "/teams"),
94
+ className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
95
+ children: [/* @__PURE__ */ g(f, { className: "h-4 w-4" }), " Cancel"]
96
+ }),
97
+ children: /* @__PURE__ */ _("form", {
98
+ onSubmit: N,
99
+ className: "max-w-2xl space-y-5",
100
+ children: [
101
+ /* @__PURE__ */ g(c, {
102
+ label: "Team name",
103
+ htmlFor: "name",
104
+ required: !0,
105
+ children: /* @__PURE__ */ g("input", {
106
+ id: "name",
107
+ className: l,
108
+ value: D.name,
109
+ onChange: (e) => j("name", e.target.value),
110
+ placeholder: "e.g. Riverside United U18"
111
+ })
112
+ }),
113
+ /* @__PURE__ */ _("div", {
114
+ className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
115
+ children: [/* @__PURE__ */ g(c, {
116
+ label: "Sport",
117
+ htmlFor: "sport",
118
+ children: /* @__PURE__ */ g("select", {
119
+ id: "sport",
120
+ className: l,
121
+ value: D.sport,
122
+ onChange: (e) => j("sport", e.target.value),
123
+ children: v.map((e) => /* @__PURE__ */ g("option", {
124
+ value: e,
125
+ children: n[e]
126
+ }, e))
127
+ })
128
+ }), /* @__PURE__ */ g(c, {
129
+ label: "Status",
130
+ htmlFor: "status",
131
+ children: /* @__PURE__ */ g("select", {
132
+ id: "status",
133
+ className: l,
134
+ value: D.status,
135
+ onChange: (e) => j("status", e.target.value),
136
+ children: y.map((e) => /* @__PURE__ */ g("option", {
137
+ value: e,
138
+ children: e.charAt(0) + e.slice(1).toLowerCase()
139
+ }, e))
140
+ })
141
+ })]
142
+ }),
143
+ /* @__PURE__ */ _("div", {
144
+ className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
145
+ children: [/* @__PURE__ */ g(c, {
146
+ label: "Age group",
147
+ htmlFor: "ageGroup",
148
+ children: /* @__PURE__ */ g("input", {
149
+ id: "ageGroup",
150
+ className: l,
151
+ value: D.ageGroup,
152
+ onChange: (e) => j("ageGroup", e.target.value),
153
+ placeholder: "e.g. U18"
154
+ })
155
+ }), /* @__PURE__ */ g(c, {
156
+ label: "Season",
157
+ htmlFor: "season",
158
+ children: /* @__PURE__ */ g("input", {
159
+ id: "season",
160
+ className: l,
161
+ value: D.season,
162
+ onChange: (e) => j("season", e.target.value),
163
+ placeholder: "e.g. 2025/26"
164
+ })
165
+ })]
166
+ }),
167
+ /* @__PURE__ */ g(c, {
168
+ label: "Home venue",
169
+ htmlFor: "homeVenue",
170
+ children: /* @__PURE__ */ g("input", {
171
+ id: "homeVenue",
172
+ className: l,
173
+ value: D.homeVenue,
174
+ onChange: (e) => j("homeVenue", e.target.value),
175
+ placeholder: "e.g. Riverside Stadium"
176
+ })
177
+ }),
178
+ /* @__PURE__ */ g(c, {
179
+ label: "Description",
180
+ htmlFor: "description",
181
+ children: /* @__PURE__ */ g("textarea", {
182
+ id: "description",
183
+ className: l,
184
+ rows: 3,
185
+ value: D.description,
186
+ onChange: (e) => j("description", e.target.value),
187
+ placeholder: "A short description of the team."
188
+ })
189
+ }),
190
+ /* @__PURE__ */ g(c, {
191
+ label: "Tags",
192
+ htmlFor: "tags",
193
+ hint: "Comma-separated, e.g. youth, development, first-team.",
194
+ children: /* @__PURE__ */ g("input", {
195
+ id: "tags",
196
+ className: l,
197
+ value: D.tagsText,
198
+ onChange: (e) => j("tagsText", e.target.value),
199
+ placeholder: "youth, development"
200
+ })
201
+ }),
202
+ k && /* @__PURE__ */ g("p", {
203
+ className: "text-sm text-status-error-text",
204
+ children: k
205
+ }),
206
+ /* @__PURE__ */ g("div", {
207
+ className: "flex items-center gap-3 pt-2",
208
+ children: /* @__PURE__ */ _("button", {
209
+ type: "submit",
210
+ disabled: P,
211
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60",
212
+ children: [P ? /* @__PURE__ */ g(p, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ g(m, { className: "h-4 w-4" }), S ? "Save changes" : "Create team"]
213
+ })
214
+ })
215
+ ]
216
+ })
217
+ });
218
+ }
219
+ //#endregion
220
+ export { x as TeamFormPage };
221
+
222
+ //# sourceMappingURL=TeamFormPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamFormPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/teams/TeamFormPage.tsx"],"sourcesContent":["/**\n * Team Create / Edit Form\n * @module atheletebridge/pages/teams\n */\n\nimport { useEffect, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Loader2, Save } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { SPORT_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport {\n useTeam,\n useCreateTeam,\n useUpdateTeam,\n} from '../../hooks/useAthleteBridgeApi';\nimport type { AthSport, AthTeamStatus } from '../../types';\n\nconst SPORTS = Object.keys(SPORT_LABELS) as AthSport[];\nconst STATUSES: AthTeamStatus[] = ['FORMING', 'ACTIVE', 'INACTIVE', 'ARCHIVED'];\n\ninterface TeamFormState {\n name: string;\n sport: AthSport;\n status: AthTeamStatus;\n description: string;\n ageGroup: string;\n season: string;\n homeVenue: string;\n tagsText: string;\n}\n\nconst EMPTY_FORM: TeamFormState = {\n name: '',\n sport: 'OTHER',\n status: 'FORMING',\n description: '',\n ageGroup: '',\n season: '',\n homeVenue: '',\n tagsText: '',\n};\n\nexport function TeamFormPage() {\n const { id } = useParams<{ id: string }>();\n const isEdit = Boolean(id);\n const { navigateTo } = useAthleteBridge();\n\n const existing = useTeam(id);\n const createTeam = useCreateTeam();\n const updateTeam = useUpdateTeam();\n\n const [form, setForm] = useState<TeamFormState>(EMPTY_FORM);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const team = existing.data;\n if (isEdit && team) {\n setForm({\n name: team.name,\n sport: team.sport,\n status: team.status,\n description: team.description ?? '',\n ageGroup: team.ageGroup ?? '',\n season: team.season ?? '',\n homeVenue: team.homeVenue ?? '',\n tagsText: team.tags.join(', '),\n });\n }\n }, [isEdit, existing.data]);\n\n const set = <K extends keyof TeamFormState>(key: K, value: TeamFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n const parseTags = (text: string): string[] =>\n text\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (!form.name.trim()) {\n setError('Team name is required.');\n return;\n }\n\n const tags = parseTags(form.tagsText);\n\n try {\n if (isEdit && id) {\n await updateTeam.mutateAsync({\n id,\n input: {\n name: form.name.trim(),\n sport: form.sport,\n status: form.status,\n description: form.description.trim() || undefined,\n ageGroup: form.ageGroup.trim() || undefined,\n season: form.season.trim() || undefined,\n homeVenue: form.homeVenue.trim() || undefined,\n tags,\n },\n });\n navigateTo(`/teams/${id}`);\n } else {\n const created = await createTeam.mutateAsync({\n name: form.name.trim(),\n sport: form.sport,\n status: form.status,\n description: form.description.trim() || undefined,\n ageGroup: form.ageGroup.trim() || undefined,\n season: form.season.trim() || undefined,\n homeVenue: form.homeVenue.trim() || undefined,\n tags,\n });\n navigateTo(`/teams/${created.id}`);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to save team.');\n }\n };\n\n const saving = createTeam.isPending || updateTeam.isPending;\n\n if (isEdit && existing.isLoading) {\n return (\n <PageLayout title=\"Edit team\">\n <LoadingState label=\"Loading team…\" />\n </PageLayout>\n );\n }\n\n if (isEdit && (existing.isError || (!existing.isLoading && !existing.data))) {\n return (\n <PageLayout title=\"Edit team\">\n <ErrorState\n title=\"Team not found\"\n message=\"This team does not exist or you do not have access to it.\"\n onRetry={() => navigateTo('/teams')}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={isEdit ? 'Edit team' : 'New team'}\n description={isEdit ? 'Update the squad details.' : 'Create a new squad to build a roster.'}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo(isEdit && id ? `/teams/${id}` : '/teams')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Cancel\n </button>\n }\n >\n <form onSubmit={handleSubmit} className=\"max-w-2xl space-y-5\">\n <FormField label=\"Team name\" htmlFor=\"name\" required>\n <input\n id=\"name\"\n className={fieldInputClass}\n value={form.name}\n onChange={(e) => set('name', e.target.value)}\n placeholder=\"e.g. Riverside United U18\"\n />\n </FormField>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Sport\" htmlFor=\"sport\">\n <select\n id=\"sport\"\n className={fieldInputClass}\n value={form.sport}\n onChange={(e) => set('sport', e.target.value as AthSport)}\n >\n {SPORTS.map((s) => (\n <option key={s} value={s}>\n {SPORT_LABELS[s]}\n </option>\n ))}\n </select>\n </FormField>\n\n <FormField label=\"Status\" htmlFor=\"status\">\n <select\n id=\"status\"\n className={fieldInputClass}\n value={form.status}\n onChange={(e) => set('status', e.target.value as AthTeamStatus)}\n >\n {STATUSES.map((s) => (\n <option key={s} value={s}>\n {s.charAt(0) + s.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </FormField>\n </div>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Age group\" htmlFor=\"ageGroup\">\n <input\n id=\"ageGroup\"\n className={fieldInputClass}\n value={form.ageGroup}\n onChange={(e) => set('ageGroup', e.target.value)}\n placeholder=\"e.g. U18\"\n />\n </FormField>\n\n <FormField label=\"Season\" htmlFor=\"season\">\n <input\n id=\"season\"\n className={fieldInputClass}\n value={form.season}\n onChange={(e) => set('season', e.target.value)}\n placeholder=\"e.g. 2025/26\"\n />\n </FormField>\n </div>\n\n <FormField label=\"Home venue\" htmlFor=\"homeVenue\">\n <input\n id=\"homeVenue\"\n className={fieldInputClass}\n value={form.homeVenue}\n onChange={(e) => set('homeVenue', e.target.value)}\n placeholder=\"e.g. Riverside Stadium\"\n />\n </FormField>\n\n <FormField label=\"Description\" htmlFor=\"description\">\n <textarea\n id=\"description\"\n className={fieldInputClass}\n rows={3}\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"A short description of the team.\"\n />\n </FormField>\n\n <FormField\n label=\"Tags\"\n htmlFor=\"tags\"\n hint=\"Comma-separated, e.g. youth, development, first-team.\"\n >\n <input\n id=\"tags\"\n className={fieldInputClass}\n value={form.tagsText}\n onChange={(e) => set('tagsText', e.target.value)}\n placeholder=\"youth, development\"\n />\n </FormField>\n\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n\n <div className=\"flex items-center gap-3 pt-2\">\n <button\n type=\"submit\"\n disabled={saving}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60\"\n >\n {saving ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {isEdit ? 'Save changes' : 'Create team'}\n </button>\n </div>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
2
+ import { PageLayout as t } from "../../components/PageLayout.js";
3
+ import { SPORT_LABELS as n } from "../../components/domain.js";
4
+ import { TeamCard as r } from "../../components/TeamCard.js";
5
+ import { EmptyState as i } from "../../components/EmptyState.js";
6
+ import { ErrorState as a, LoadingState as o } from "../../components/LoadingState.js";
7
+ import { useTeams as s } from "../../hooks/useAthleteBridgeApi.js";
8
+ import { FilterSelect as c } from "../../components/FilterSelect.js";
9
+ import { CursorPager as l } from "../../components/CursorPager.js";
10
+ import { useState as u } from "react";
11
+ import { Plus as d, Users as f } from "lucide-react";
12
+ import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
13
+ //#region src/atheletebridge/pages/teams/TeamsListPage.tsx
14
+ var g = 12, _ = Object.keys(n).map((e) => ({
15
+ value: e,
16
+ label: n[e]
17
+ })), v = [
18
+ {
19
+ value: "FORMING",
20
+ label: "Forming"
21
+ },
22
+ {
23
+ value: "ACTIVE",
24
+ label: "Active"
25
+ },
26
+ {
27
+ value: "INACTIVE",
28
+ label: "Inactive"
29
+ },
30
+ {
31
+ value: "ARCHIVED",
32
+ label: "Archived"
33
+ }
34
+ ];
35
+ function y() {
36
+ let { navigateTo: n } = e(), [y, b] = u(""), [x, S] = u(""), [C, w] = u(0), T = s({
37
+ sport: y || void 0,
38
+ status: x || void 0,
39
+ pagination: {
40
+ limit: g,
41
+ offset: C * g
42
+ }
43
+ }), E = T.data?.items ?? [], D = T.data?.pageInfo.hasMore ?? !1;
44
+ return /* @__PURE__ */ h(t, {
45
+ title: "Teams",
46
+ description: "Squads, club sides, academy groups and esports rosters.",
47
+ actions: /* @__PURE__ */ h("button", {
48
+ type: "button",
49
+ onClick: () => n("/teams/new"),
50
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
51
+ children: [/* @__PURE__ */ m(d, { className: "h-4 w-4" }), " New team"]
52
+ }),
53
+ children: [/* @__PURE__ */ h("div", {
54
+ className: "mb-6 flex flex-wrap items-center gap-3",
55
+ children: [/* @__PURE__ */ m(c, {
56
+ ariaLabel: "Filter by sport",
57
+ allLabel: "All sports",
58
+ value: y,
59
+ onChange: (e) => {
60
+ b(e), w(0);
61
+ },
62
+ options: _
63
+ }), /* @__PURE__ */ m(c, {
64
+ ariaLabel: "Filter by status",
65
+ allLabel: "All statuses",
66
+ value: x,
67
+ onChange: (e) => {
68
+ S(e), w(0);
69
+ },
70
+ options: v
71
+ })]
72
+ }), T.isLoading ? /* @__PURE__ */ m(o, { label: "Loading teams…" }) : T.isError ? /* @__PURE__ */ m(a, { onRetry: () => void T.refetch() }) : E.length === 0 ? /* @__PURE__ */ m(i, {
73
+ illustration: "empty-data",
74
+ icon: /* @__PURE__ */ m(f, { className: "h-10 w-10" }),
75
+ title: "No teams found",
76
+ description: y || x ? "Try clearing your filters to see all teams." : "Create your first team to build a roster and start scheduling fixtures.",
77
+ action: /* @__PURE__ */ m("button", {
78
+ type: "button",
79
+ onClick: () => n("/teams/new"),
80
+ className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
81
+ children: "Create team"
82
+ })
83
+ }) : /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m("div", {
84
+ className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",
85
+ children: E.map((e) => /* @__PURE__ */ m(r, {
86
+ team: e,
87
+ onClick: () => n(`/teams/${e.id}`)
88
+ }, e.id))
89
+ }), /* @__PURE__ */ m(l, {
90
+ className: "mt-6",
91
+ page: C,
92
+ hasMore: D,
93
+ onPrev: () => w((e) => Math.max(0, e - 1)),
94
+ onNext: () => w((e) => e + 1)
95
+ })] })]
96
+ });
97
+ }
98
+ //#endregion
99
+ export { y as TeamsListPage };
100
+
101
+ //# sourceMappingURL=TeamsListPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamsListPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/teams/TeamsListPage.tsx"],"sourcesContent":["/**\n * Teams List\n * @module atheletebridge/pages/teams\n */\n\nimport { useState } from 'react';\nimport { Plus, Users } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { TeamCard } from '../../components/TeamCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FilterSelect } from '../../components/FilterSelect';\nimport { CursorPager } from '../../components/CursorPager';\nimport { SPORT_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useTeams } from '../../hooks/useAthleteBridgeApi';\nimport type { AthSport, AthTeamStatus } from '../../types';\n\nconst PAGE_SIZE = 12;\n\nconst SPORT_OPTS = (Object.keys(SPORT_LABELS) as AthSport[]).map((value) => ({\n value,\n label: SPORT_LABELS[value],\n}));\n\nconst STATUS_OPTS: ReadonlyArray<{ value: AthTeamStatus; label: string }> = [\n { value: 'FORMING', label: 'Forming' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'INACTIVE', label: 'Inactive' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nexport function TeamsListPage() {\n const { navigateTo } = useAthleteBridge();\n const [sport, setSport] = useState<AthSport | ''>('');\n const [status, setStatus] = useState<AthTeamStatus | ''>('');\n const [page, setPage] = useState(0);\n\n const teams = useTeams({\n sport: sport || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset: page * PAGE_SIZE },\n });\n\n const items = teams.data?.items ?? [];\n const hasMore = teams.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Teams\"\n description=\"Squads, club sides, academy groups and esports rosters.\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/teams/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Plus className=\"h-4 w-4\" /> New team\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <FilterSelect\n ariaLabel=\"Filter by sport\"\n allLabel=\"All sports\"\n value={sport}\n onChange={(v) => {\n setSport(v);\n setPage(0);\n }}\n options={SPORT_OPTS}\n />\n <FilterSelect\n ariaLabel=\"Filter by status\"\n allLabel=\"All statuses\"\n value={status}\n onChange={(v) => {\n setStatus(v);\n setPage(0);\n }}\n options={STATUS_OPTS}\n />\n </div>\n\n {teams.isLoading ? (\n <LoadingState label=\"Loading teams…\" />\n ) : teams.isError ? (\n <ErrorState onRetry={() => void teams.refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Users className=\"h-10 w-10\" />}\n title=\"No teams found\"\n description={\n sport || status\n ? 'Try clearing your filters to see all teams.'\n : 'Create your first team to build a roster and start scheduling fixtures.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/teams/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n Create team\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {items.map((team) => (\n <TeamCard\n key={team.id}\n team={team}\n onClick={() => navigateTo(`/teams/${team.id}`)}\n />\n ))}\n </div>\n <CursorPager\n className=\"mt-6\"\n page={page}\n hasMore={hasMore}\n onPrev={() => setPage((p) => Math.max(0, p - 1))}\n onNext={() => setPage((p) => p + 1)}\n />\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAkBA,IAAM,IAAY,IAEZ,IAAc,OAAO,KAAK,EAAa,CAAgB,KAAK,OAAW;CAC3E;CACA,OAAO,EAAa;CACrB,EAAE,EAEG,IAAsE;CAC1E;EAAE,OAAO;EAAW,OAAO;EAAW;CACtC;EAAE,OAAO;EAAU,OAAO;EAAU;CACpC;EAAE,OAAO;EAAY,OAAO;EAAY;CACxC;EAAE,OAAO;EAAY,OAAO;EAAY;CACzC;AAED,SAAgB,IAAgB;CAC9B,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAO,KAAY,EAAwB,GAAG,EAC/C,CAAC,GAAQ,KAAa,EAA6B,GAAG,EACtD,CAAC,GAAM,KAAW,EAAS,EAAE,EAE7B,IAAQ,EAAS;EACrB,OAAO,KAAS,KAAA;EAChB,QAAQ,KAAU,KAAA;EAClB,YAAY;GAAE,OAAO;GAAW,QAAQ,IAAO;GAAW;EAC3D,CAAC,EAEI,IAAQ,EAAM,MAAM,SAAS,EAAE,EAC/B,IAAU,EAAM,MAAM,SAAS,WAAW;AAEhD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,aAAa;GACvC,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,YACrB;;YAVb,CAaE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IACE,WAAU;IACV,UAAS;IACT,OAAO;IACP,WAAW,MAAM;AAEf,KADA,EAAS,EAAE,EACX,EAAQ,EAAE;;IAEZ,SAAS;IACT,CAAA,EACF,kBAAC,GAAD;IACE,WAAU;IACV,UAAS;IACT,OAAO;IACP,WAAW,MAAM;AAEf,KADA,EAAU,EAAE,EACZ,EAAQ,EAAE;;IAEZ,SAAS;IACT,CAAA,CACE;MAEL,EAAM,YACL,kBAAC,GAAD,EAAc,OAAM,kBAAmB,CAAA,GACrC,EAAM,UACR,kBAAC,GAAD,EAAY,eAAe,KAAK,EAAM,SAAS,EAAI,CAAA,GACjD,EAAM,WAAW,IACnB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAO,WAAU,aAAc,CAAA;GACrC,OAAM;GACN,aACE,KAAS,IACL,gDACA;GAEN,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,aAAa;IACvC,WAAU;cACX;IAEQ,CAAA;GAEX,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,GAAD;IAEQ;IACN,eAAe,EAAW,UAAU,EAAK,KAAK;IAC9C,EAHK,EAAK,GAGV,CACF;GACE,CAAA,EACN,kBAAC,GAAD;GACE,WAAU;GACJ;GACG;GACT,cAAc,GAAS,MAAM,KAAK,IAAI,GAAG,IAAI,EAAE,CAAC;GAChD,cAAc,GAAS,MAAM,IAAI,EAAE;GACnC,CAAA,CACD,EAAA,CAAA,CAEM"}
@@ -4,29 +4,18 @@ import { createProfileScopedStorage as r } from "@burdenoff/fe-libs/shared/utils
4
4
  //#region src/atheletebridge/store/atheletebridgeStore.ts
5
5
  var i = {
6
6
  viewMode: "grid",
7
- activeSection: "dashboard",
8
- sidebarCollapsed: !1,
9
- searchQuery: "",
10
- categoryFilter: "",
11
- selectedCartId: null,
12
- selectedOrderId: null
7
+ sidebarCollapsed: !1
13
8
  }, a = e()(t(n((e) => ({
14
9
  ...i,
15
10
  setViewMode: (t) => e({ viewMode: t }),
16
- setActiveSection: (t) => e({ activeSection: t }),
17
11
  toggleSidebar: () => e((e) => ({ sidebarCollapsed: !e.sidebarCollapsed })),
18
- setSearchQuery: (t) => e({ searchQuery: t }),
19
- setCategoryFilter: (t) => e({ categoryFilter: t }),
20
- setSelectedCartId: (t) => e({ selectedCartId: t }),
21
- setSelectedOrderId: (t) => e({ selectedOrderId: t }),
22
12
  reset: () => e(i)
23
13
  }), {
24
14
  name: "burdenoff-atheletebridge-storage",
25
15
  storage: r(),
26
16
  partialize: (e) => ({
27
17
  viewMode: e.viewMode,
28
- sidebarCollapsed: e.sidebarCollapsed,
29
- activeSection: e.activeSection
18
+ sidebarCollapsed: e.sidebarCollapsed
30
19
  })
31
20
  }), {
32
21
  name: "AthleteBridge Store",
@@ -1 +1 @@
1
- {"version":3,"file":"atheletebridgeStore.js","names":[],"sources":["../../../src/atheletebridge/store/atheletebridgeStore.ts"],"sourcesContent":["/**\n * AthleteBridge Zustand Store\n * @module atheletebridge/store\n */\n\nimport { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\nimport { createProfileScopedStorage } from '@burdenoff/fe-libs/shared/utils';\nimport type { ViewMode } from '../types';\n\n// ============================================================================\n// State Interface\n// ============================================================================\n\ninterface AthleteBridgeState {\n // View state\n viewMode: ViewMode;\n activeSection: string;\n sidebarCollapsed: boolean;\n\n // Search & filters\n searchQuery: string;\n categoryFilter: string;\n\n // Selected entities\n selectedCartId: string | null;\n selectedOrderId: string | null;\n\n // Actions\n setViewMode: (mode: ViewMode) => void;\n setActiveSection: (section: string) => void;\n setSearchQuery: (query: string) => void;\n setCategoryFilter: (category: string) => void;\n setSelectedCartId: (cartId: string | null) => void;\n setSelectedOrderId: (orderId: string | null) => void;\n toggleSidebar: () => void;\n reset: () => void;\n}\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst initialState = {\n viewMode: 'grid' as ViewMode,\n activeSection: 'dashboard',\n sidebarCollapsed: false,\n\n searchQuery: '',\n categoryFilter: '',\n\n selectedCartId: null,\n selectedOrderId: null,\n};\n\n// ============================================================================\n// Store\n// ============================================================================\n\nexport const useAthleteBridgeStore = create<AthleteBridgeState>()(\n devtools(\n persist(\n (set) => ({\n ...initialState,\n\n // View actions\n setViewMode: (mode) => set({ viewMode: mode }),\n setActiveSection: (section) => set({ activeSection: section }),\n toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),\n\n // Search & filter actions\n setSearchQuery: (query) => set({ searchQuery: query }),\n setCategoryFilter: (category) => set({ categoryFilter: category }),\n\n // Selection actions\n setSelectedCartId: (cartId) => set({ selectedCartId: cartId }),\n setSelectedOrderId: (orderId) => set({ selectedOrderId: orderId }),\n\n // Reset\n reset: () => set(initialState),\n }),\n {\n name: 'burdenoff-atheletebridge-storage',\n storage: createProfileScopedStorage(),\n partialize: (state) => ({\n viewMode: state.viewMode,\n sidebarCollapsed: state.sidebarCollapsed,\n activeSection: state.activeSection,\n }),\n }\n ),\n { name: 'AthleteBridge Store', enabled: import.meta.env.DEV }\n )\n);\n"],"mappings":";;;;AA2CA,IAAM,IAAe;CACnB,UAAU;CACV,eAAe;CACf,kBAAkB;CAElB,aAAa;CACb,gBAAgB;CAEhB,gBAAgB;CAChB,iBAAiB;CAClB,EAMY,IAAwB,GAA4B,CAC/D,EACE,GACG,OAAS;CACR,GAAG;CAGH,cAAc,MAAS,EAAI,EAAE,UAAU,GAAM,CAAC;CAC9C,mBAAmB,MAAY,EAAI,EAAE,eAAe,GAAS,CAAC;CAC9D,qBAAqB,GAAK,OAAW,EAAE,kBAAkB,CAAC,EAAM,kBAAkB,EAAE;CAGpF,iBAAiB,MAAU,EAAI,EAAE,aAAa,GAAO,CAAC;CACtD,oBAAoB,MAAa,EAAI,EAAE,gBAAgB,GAAU,CAAC;CAGlE,oBAAoB,MAAW,EAAI,EAAE,gBAAgB,GAAQ,CAAC;CAC9D,qBAAqB,MAAY,EAAI,EAAE,iBAAiB,GAAS,CAAC;CAGlE,aAAa,EAAI,EAAa;CAC/B,GACD;CACE,MAAM;CACN,SAAS,GAA4B;CACrC,aAAa,OAAW;EACtB,UAAU,EAAM;EAChB,kBAAkB,EAAM;EACxB,eAAe,EAAM;EACtB;CACF,CACF,EACD;CAAE,MAAM;CAAuB,SAAA;CAA8B,CAC9D,CACF"}
1
+ {"version":3,"file":"atheletebridgeStore.js","names":[],"sources":["../../../src/atheletebridge/store/atheletebridgeStore.ts"],"sourcesContent":["/**\n * AthleteBridge Zustand Store\n * @module atheletebridge/store\n *\n * Local UI state only (view mode, sidebar). Server state lives in React Query.\n */\n\nimport { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\nimport { createProfileScopedStorage } from '@burdenoff/fe-libs/shared/utils';\nimport type { ViewMode } from '../types';\n\n// ============================================================================\n// State Interface\n// ============================================================================\n\ninterface AthleteBridgeState {\n viewMode: ViewMode;\n sidebarCollapsed: boolean;\n\n setViewMode: (mode: ViewMode) => void;\n toggleSidebar: () => void;\n reset: () => void;\n}\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst initialState = {\n viewMode: 'grid' as ViewMode,\n sidebarCollapsed: false,\n};\n\n// ============================================================================\n// Store\n// ============================================================================\n\nexport const useAthleteBridgeStore = create<AthleteBridgeState>()(\n devtools(\n persist(\n (set) => ({\n ...initialState,\n\n setViewMode: (mode) => set({ viewMode: mode }),\n toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),\n\n reset: () => set(initialState),\n }),\n {\n name: 'burdenoff-atheletebridge-storage',\n storage: createProfileScopedStorage(),\n partialize: (state) => ({\n viewMode: state.viewMode,\n sidebarCollapsed: state.sidebarCollapsed,\n }),\n }\n ),\n { name: 'AthleteBridge Store', enabled: import.meta.env.DEV }\n )\n);\n"],"mappings":";;;;AA6BA,IAAM,IAAe;CACnB,UAAU;CACV,kBAAkB;CACnB,EAMY,IAAwB,GAA4B,CAC/D,EACE,GACG,OAAS;CACR,GAAG;CAEH,cAAc,MAAS,EAAI,EAAE,UAAU,GAAM,CAAC;CAC9C,qBAAqB,GAAK,OAAW,EAAE,kBAAkB,CAAC,EAAM,kBAAkB,EAAE;CAEpF,aAAa,EAAI,EAAa;CAC/B,GACD;CACE,MAAM;CACN,SAAS,GAA4B;CACrC,aAAa,OAAW;EACtB,UAAU,EAAM;EAChB,kBAAkB,EAAM;EACzB;CACF,CACF,EACD;CAAE,MAAM;CAAuB,SAAA;CAA8B,CAC9D,CACF"}
@@ -0,0 +1,10 @@
1
+ //#region src/atheletebridge/utils/datetime.ts
2
+ function e(e) {
3
+ if (!e) return;
4
+ let t = new Date(e);
5
+ return Number.isNaN(t.getTime()) ? void 0 : t.toISOString();
6
+ }
7
+ //#endregion
8
+ export { e as toIsoOrUndefined };
9
+
10
+ //# sourceMappingURL=datetime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datetime.js","names":[],"sources":["../../../src/atheletebridge/utils/datetime.ts"],"sourcesContent":["/**\n * Datetime helpers for form inputs\n * @module atheletebridge/utils/datetime\n */\n\n/**\n * Convert a `datetime-local` input value to an ISO string, or undefined when\n * the value is empty. Returns undefined for unparseable values so callers never\n * send \"Invalid Date\" to the API.\n */\nexport function toIsoOrUndefined(value: string): string | undefined {\n if (!value) return undefined;\n const d = new Date(value);\n return Number.isNaN(d.getTime()) ? undefined : d.toISOString();\n}\n\n/**\n * Convert an ISO datetime string into the `datetime-local` input format\n * (`YYYY-MM-DDTHH:mm`) in the browser's local timezone.\n */\nexport function isoToLocalInput(iso: string | null | undefined): string {\n if (!iso) return '';\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return '';\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(\n d.getHours()\n )}:${pad(d.getMinutes())}`;\n}\n"],"mappings":";AAUA,SAAgB,EAAiB,GAAmC;AAClE,KAAI,CAAC,EAAO;CACZ,IAAM,IAAI,IAAI,KAAK,EAAM;AACzB,QAAO,OAAO,MAAM,EAAE,SAAS,CAAC,GAAG,KAAA,IAAY,EAAE,aAAa"}
@@ -35,9 +35,6 @@ function r(e, t) {
35
35
  return new Intl.NumberFormat("en-IN", t).format(e);
36
36
  }
37
37
  function i(e) {
38
- return e < 1 ? `${Math.round(e * 1e3)} m` : e < 10 ? `${e.toFixed(1)} km` : `${Math.round(e)} km`;
39
- }
40
- function a(e) {
41
38
  if (e < 1) return "instant";
42
39
  if (e < 60) return `${e} min`;
43
40
  let t = Math.floor(e / 60), n = e % 60;
@@ -46,6 +43,6 @@ function a(e) {
46
43
  return i === 0 ? `${r} day${r === 1 ? "" : "s"}` : `${r} day${r === 1 ? "" : "s"} ${i}h`;
47
44
  }
48
45
  //#endregion
49
- export { e as formatCurrency, t as formatDate, i as formatDistance, a as formatDuration, r as formatNumber, n as formatRelativeTime };
46
+ export { e as formatCurrency, t as formatDate, i as formatDuration, r as formatNumber, n as formatRelativeTime };
50
47
 
51
48
  //# sourceMappingURL=formatters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatters.js","names":[],"sources":["../../../src/atheletebridge/utils/formatters.ts"],"sourcesContent":["/**\n * Formatting utilities for the AthleteBridge microfrontend\n * @module atheletebridge/utils/formatters\n */\n\n/**\n * Format a number as Indian Rupees (INR) currency\n *\n * @param amount - The numeric amount to format\n * @param options - Optional Intl.NumberFormat options to override defaults\n * @returns Formatted currency string (e.g., \"₹1,200.00\")\n *\n * @example\n * formatCurrency(1200) // => \"₹1,200.00\"\n * formatCurrency(0) // => \"₹0.00\"\n * formatCurrency(1200, { minimumFractionDigits: 0 }) // => \"₹1,200\"\n */\nexport function formatCurrency(\n amount: number,\n options?: Partial<Intl.NumberFormatOptions>\n): string {\n return new Intl.NumberFormat('en-IN', {\n style: 'currency',\n currency: 'INR',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n ...options,\n }).format(amount);\n}\n\n/**\n * Format a date string or Date object into a human-readable format\n *\n * @param date - ISO date string or Date object\n * @param options - Optional Intl.DateTimeFormat options\n * @returns Formatted date string (e.g., \"15 Jan 2024, 4:00 PM\")\n *\n * @example\n * formatDate('2024-01-15T10:30:00Z')\n * // => \"15 Jan 2024, 4:00 PM\" (in IST)\n */\nexport function formatDate(\n date: string | Date,\n options?: Partial<Intl.DateTimeFormatOptions>\n): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n return new Intl.DateTimeFormat('en-IN', {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n ...options,\n }).format(d);\n}\n\n/**\n * Format a date into a relative time string (e.g., \"2 hours ago\")\n *\n * @param date - ISO date string or Date object\n * @returns Human-readable relative time string\n *\n * @example\n * formatRelativeTime('2024-01-15T10:30:00Z') // => \"3 days ago\"\n * formatRelativeTime(new Date()) // => \"just now\"\n */\nexport function formatRelativeTime(date: string | Date): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n const now = new Date();\n const diffMs = now.getTime() - d.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n const diffWeeks = Math.floor(diffDays / 7);\n const diffMonths = Math.floor(diffDays / 30);\n\n if (diffSeconds < 60) return 'just now';\n if (diffMinutes < 60) return `${diffMinutes} min${diffMinutes !== 1 ? 's' : ''} ago`;\n if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;\n if (diffDays < 7) return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`;\n if (diffWeeks < 4) return `${diffWeeks} week${diffWeeks !== 1 ? 's' : ''} ago`;\n if (diffMonths < 12) return `${diffMonths} month${diffMonths !== 1 ? 's' : ''} ago`;\n\n const diffYears = Math.floor(diffDays / 365);\n return `${diffYears} year${diffYears !== 1 ? 's' : ''} ago`;\n}\n\n/**\n * Format a number with Indian locale grouping (lakhs, crores)\n *\n * @param value - The number to format\n * @param options - Optional Intl.NumberFormat options\n * @returns Formatted number string (e.g., \"12,345\" or \"1,24,500\")\n *\n * @example\n * formatNumber(1245) // => \"1,245\"\n * formatNumber(124500) // => \"1,24,500\"\n */\nexport function formatNumber(value: number, options?: Partial<Intl.NumberFormatOptions>): string {\n return new Intl.NumberFormat('en-IN', options).format(value);\n}\n\n/**\n * Format a distance value in kilometers\n *\n * @param km - Distance in kilometers\n * @returns Formatted distance string\n *\n * @example\n * formatDistance(0.5) // => \"500 m\"\n * formatDistance(1.2) // => \"1.2 km\"\n * formatDistance(15) // => \"15 km\"\n */\nexport function formatDistance(km: number): string {\n if (km < 1) {\n return `${Math.round(km * 1000)} m`;\n }\n if (km < 10) {\n return `${km.toFixed(1)} km`;\n }\n return `${Math.round(km)} km`;\n}\n\n/**\n * Format a duration in minutes into a human-readable string\n *\n * @param minutes - Duration in minutes\n * @returns Formatted duration string\n *\n * @example\n * formatDuration(5) // => \"5 min\"\n * formatDuration(90) // => \"1h 30min\"\n * formatDuration(1440) // => \"1 day\"\n * formatDuration(4320) // => \"3 days\"\n */\nexport function formatDuration(minutes: number): string {\n if (minutes < 1) return 'instant';\n if (minutes < 60) return `${minutes} min`;\n\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n\n if (hours < 24) {\n if (remainingMinutes === 0) {\n return `${hours}h`;\n }\n return `${hours}h ${remainingMinutes}min`;\n }\n\n const days = Math.floor(hours / 24);\n const remainingHours = hours % 24;\n\n if (remainingHours === 0) {\n return `${days} day${days !== 1 ? 's' : ''}`;\n }\n return `${days} day${days !== 1 ? 's' : ''} ${remainingHours}h`;\n}\n"],"mappings":";AAiBA,SAAgB,EACd,GACA,GACQ;AACR,QAAO,IAAI,KAAK,aAAa,SAAS;EACpC,OAAO;EACP,UAAU;EACV,uBAAuB;EACvB,uBAAuB;EACvB,GAAG;EACJ,CAAC,CAAC,OAAO,EAAO;;AAcnB,SAAgB,EACd,GACA,GACQ;CACR,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,EAAK,GAAG;AACtD,QAAO,IAAI,KAAK,eAAe,SAAS;EACtC,KAAK;EACL,OAAO;EACP,MAAM;EACN,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,GAAG;EACJ,CAAC,CAAC,OAAO,EAAE;;AAad,SAAgB,EAAmB,GAA6B;CAC9D,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,EAAK,GAAG,GAEhD,qBADM,IAAI,MAAM,EACH,SAAS,GAAG,EAAE,SAAS,EACpC,IAAc,KAAK,MAAM,IAAS,IAAK,EACvC,IAAc,KAAK,MAAM,IAAc,GAAG,EAC1C,IAAY,KAAK,MAAM,IAAc,GAAG,EACxC,IAAW,KAAK,MAAM,IAAY,GAAG,EACrC,IAAY,KAAK,MAAM,IAAW,EAAE,EACpC,IAAa,KAAK,MAAM,IAAW,GAAG;AAE5C,KAAI,IAAc,GAAI,QAAO;AAC7B,KAAI,IAAc,GAAI,QAAO,GAAG,EAAY,MAAM,MAAgB,IAAU,KAAN,IAAS;AAC/E,KAAI,IAAY,GAAI,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;AAC1E,KAAI,IAAW,EAAG,QAAO,GAAG,EAAS,MAAM,MAAa,IAAU,KAAN,IAAS;AACrE,KAAI,IAAY,EAAG,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;AACzE,KAAI,IAAa,GAAI,QAAO,GAAG,EAAW,QAAQ,MAAe,IAAU,KAAN,IAAS;CAE9E,IAAM,IAAY,KAAK,MAAM,IAAW,IAAI;AAC5C,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;;AAcxD,SAAgB,EAAa,GAAe,GAAqD;AAC/F,QAAO,IAAI,KAAK,aAAa,SAAS,EAAQ,CAAC,OAAO,EAAM;;AAc9D,SAAgB,EAAe,GAAoB;AAOjD,QANI,IAAK,IACA,GAAG,KAAK,MAAM,IAAK,IAAK,CAAC,MAE9B,IAAK,KACA,GAAG,EAAG,QAAQ,EAAE,CAAC,OAEnB,GAAG,KAAK,MAAM,EAAG,CAAC;;AAe3B,SAAgB,EAAe,GAAyB;AACtD,KAAI,IAAU,EAAG,QAAO;AACxB,KAAI,IAAU,GAAI,QAAO,GAAG,EAAQ;CAEpC,IAAM,IAAQ,KAAK,MAAM,IAAU,GAAG,EAChC,IAAmB,IAAU;AAEnC,KAAI,IAAQ,GAIV,QAHI,MAAqB,IAChB,GAAG,EAAM,KAEX,GAAG,EAAM,IAAI,EAAiB;CAGvC,IAAM,IAAO,KAAK,MAAM,IAAQ,GAAG,EAC7B,IAAiB,IAAQ;AAK/B,QAHI,MAAmB,IACd,GAAG,EAAK,MAAM,MAAS,IAAU,KAAN,QAE7B,GAAG,EAAK,MAAM,MAAS,IAAU,KAAN,IAAS,GAAG,EAAe"}
1
+ {"version":3,"file":"formatters.js","names":[],"sources":["../../../src/atheletebridge/utils/formatters.ts"],"sourcesContent":["/**\n * Formatting utilities for the AthleteBridge microfrontend\n * @module atheletebridge/utils/formatters\n */\n\n/**\n * Format a number as Indian Rupees (INR) currency\n *\n * @param amount - The numeric amount to format\n * @param options - Optional Intl.NumberFormat options to override defaults\n * @returns Formatted currency string (e.g., \"₹1,200.00\")\n *\n * @example\n * formatCurrency(1200) // => \"₹1,200.00\"\n * formatCurrency(0) // => \"₹0.00\"\n * formatCurrency(1200, { minimumFractionDigits: 0 }) // => \"₹1,200\"\n */\nexport function formatCurrency(\n amount: number,\n options?: Partial<Intl.NumberFormatOptions>\n): string {\n return new Intl.NumberFormat('en-IN', {\n style: 'currency',\n currency: 'INR',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n ...options,\n }).format(amount);\n}\n\n/**\n * Format a date string or Date object into a human-readable format\n *\n * @param date - ISO date string or Date object\n * @param options - Optional Intl.DateTimeFormat options\n * @returns Formatted date string (e.g., \"15 Jan 2024, 4:00 PM\")\n *\n * @example\n * formatDate('2024-01-15T10:30:00Z')\n * // => \"15 Jan 2024, 4:00 PM\" (in IST)\n */\nexport function formatDate(\n date: string | Date,\n options?: Partial<Intl.DateTimeFormatOptions>\n): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n return new Intl.DateTimeFormat('en-IN', {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n ...options,\n }).format(d);\n}\n\n/**\n * Format a date into a relative time string (e.g., \"2 hours ago\")\n *\n * @param date - ISO date string or Date object\n * @returns Human-readable relative time string\n *\n * @example\n * formatRelativeTime('2024-01-15T10:30:00Z') // => \"3 days ago\"\n * formatRelativeTime(new Date()) // => \"just now\"\n */\nexport function formatRelativeTime(date: string | Date): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n const now = new Date();\n const diffMs = now.getTime() - d.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n const diffWeeks = Math.floor(diffDays / 7);\n const diffMonths = Math.floor(diffDays / 30);\n\n if (diffSeconds < 60) return 'just now';\n if (diffMinutes < 60) return `${diffMinutes} min${diffMinutes !== 1 ? 's' : ''} ago`;\n if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;\n if (diffDays < 7) return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`;\n if (diffWeeks < 4) return `${diffWeeks} week${diffWeeks !== 1 ? 's' : ''} ago`;\n if (diffMonths < 12) return `${diffMonths} month${diffMonths !== 1 ? 's' : ''} ago`;\n\n const diffYears = Math.floor(diffDays / 365);\n return `${diffYears} year${diffYears !== 1 ? 's' : ''} ago`;\n}\n\n/**\n * Format a number with Indian locale grouping (lakhs, crores)\n *\n * @param value - The number to format\n * @param options - Optional Intl.NumberFormat options\n * @returns Formatted number string (e.g., \"12,345\" or \"1,24,500\")\n *\n * @example\n * formatNumber(1245) // => \"1,245\"\n * formatNumber(124500) // => \"1,24,500\"\n */\nexport function formatNumber(value: number, options?: Partial<Intl.NumberFormatOptions>): string {\n return new Intl.NumberFormat('en-IN', options).format(value);\n}\n\n/**\n * Format a distance value in kilometers\n *\n * @param km - Distance in kilometers\n * @returns Formatted distance string\n *\n * @example\n * formatDistance(0.5) // => \"500 m\"\n * formatDistance(1.2) // => \"1.2 km\"\n * formatDistance(15) // => \"15 km\"\n */\nexport function formatDistance(km: number): string {\n if (km < 1) {\n return `${Math.round(km * 1000)} m`;\n }\n if (km < 10) {\n return `${km.toFixed(1)} km`;\n }\n return `${Math.round(km)} km`;\n}\n\n/**\n * Format a duration in minutes into a human-readable string\n *\n * @param minutes - Duration in minutes\n * @returns Formatted duration string\n *\n * @example\n * formatDuration(5) // => \"5 min\"\n * formatDuration(90) // => \"1h 30min\"\n * formatDuration(1440) // => \"1 day\"\n * formatDuration(4320) // => \"3 days\"\n */\nexport function formatDuration(minutes: number): string {\n if (minutes < 1) return 'instant';\n if (minutes < 60) return `${minutes} min`;\n\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n\n if (hours < 24) {\n if (remainingMinutes === 0) {\n return `${hours}h`;\n }\n return `${hours}h ${remainingMinutes}min`;\n }\n\n const days = Math.floor(hours / 24);\n const remainingHours = hours % 24;\n\n if (remainingHours === 0) {\n return `${days} day${days !== 1 ? 's' : ''}`;\n }\n return `${days} day${days !== 1 ? 's' : ''} ${remainingHours}h`;\n}\n"],"mappings":";AAiBA,SAAgB,EACd,GACA,GACQ;AACR,QAAO,IAAI,KAAK,aAAa,SAAS;EACpC,OAAO;EACP,UAAU;EACV,uBAAuB;EACvB,uBAAuB;EACvB,GAAG;EACJ,CAAC,CAAC,OAAO,EAAO;;AAcnB,SAAgB,EACd,GACA,GACQ;CACR,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,EAAK,GAAG;AACtD,QAAO,IAAI,KAAK,eAAe,SAAS;EACtC,KAAK;EACL,OAAO;EACP,MAAM;EACN,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,GAAG;EACJ,CAAC,CAAC,OAAO,EAAE;;AAad,SAAgB,EAAmB,GAA6B;CAC9D,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,EAAK,GAAG,GAEhD,qBADM,IAAI,MAAM,EACH,SAAS,GAAG,EAAE,SAAS,EACpC,IAAc,KAAK,MAAM,IAAS,IAAK,EACvC,IAAc,KAAK,MAAM,IAAc,GAAG,EAC1C,IAAY,KAAK,MAAM,IAAc,GAAG,EACxC,IAAW,KAAK,MAAM,IAAY,GAAG,EACrC,IAAY,KAAK,MAAM,IAAW,EAAE,EACpC,IAAa,KAAK,MAAM,IAAW,GAAG;AAE5C,KAAI,IAAc,GAAI,QAAO;AAC7B,KAAI,IAAc,GAAI,QAAO,GAAG,EAAY,MAAM,MAAgB,IAAU,KAAN,IAAS;AAC/E,KAAI,IAAY,GAAI,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;AAC1E,KAAI,IAAW,EAAG,QAAO,GAAG,EAAS,MAAM,MAAa,IAAU,KAAN,IAAS;AACrE,KAAI,IAAY,EAAG,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;AACzE,KAAI,IAAa,GAAI,QAAO,GAAG,EAAW,QAAQ,MAAe,IAAU,KAAN,IAAS;CAE9E,IAAM,IAAY,KAAK,MAAM,IAAW,IAAI;AAC5C,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;;AAcxD,SAAgB,EAAa,GAAe,GAAqD;AAC/F,QAAO,IAAI,KAAK,aAAa,SAAS,EAAQ,CAAC,OAAO,EAAM;;AAoC9D,SAAgB,EAAe,GAAyB;AACtD,KAAI,IAAU,EAAG,QAAO;AACxB,KAAI,IAAU,GAAI,QAAO,GAAG,EAAQ;CAEpC,IAAM,IAAQ,KAAK,MAAM,IAAU,GAAG,EAChC,IAAmB,IAAU;AAEnC,KAAI,IAAQ,GAIV,QAHI,MAAqB,IAChB,GAAG,EAAM,KAEX,GAAG,EAAM,IAAI,EAAiB;CAGvC,IAAM,IAAO,KAAK,MAAM,IAAQ,GAAG,EAC7B,IAAiB,IAAQ;AAK/B,QAHI,MAAmB,IACd,GAAG,EAAK,MAAM,MAAS,IAAU,KAAN,QAE7B,GAAG,EAAK,MAAM,MAAS,IAAU,KAAN,IAAS,GAAG,EAAe"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-atheletebridge",
3
- "version": "2026.625.2",
3
+ "version": "2026.628.1",
4
4
  "description": "Burdenoff Kadaikodi Microfrontend - Mobile services marketplace platform for connecting service providers with customers",
5
5
  "type": "module",
6
6
  "files": [
@@ -1,96 +0,0 @@
1
- import { cn as e } from "../utils/cn.js";
2
- import { StatusBadge as t } from "./StatusBadge.js";
3
- import { AlertTriangle as n, Shield as r, TrendingUp as i } from "lucide-react";
4
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
5
- //#region src/atheletebridge/components/InvestmentCard.tsx
6
- var s = {
7
- low: {
8
- label: "Low Risk",
9
- icon: r,
10
- color: "text-status-success-text"
11
- },
12
- medium: {
13
- label: "Medium Risk",
14
- icon: n,
15
- color: "text-status-warning-text"
16
- },
17
- high: {
18
- label: "High Risk",
19
- icon: n,
20
- color: "text-status-error-text"
21
- }
22
- }, c = ({ id: n, cartName: r, targetAmount: c, raisedAmount: l, currency: u = "INR", expectedReturns: d, riskLevel: f, status: p, onClick: m, className: h }) => {
23
- let g = c > 0 ? Math.min(l / c * 100, 100) : 0, _ = s[f], v = _.icon, y = (e) => new Intl.NumberFormat(void 0, {
24
- style: "currency",
25
- currency: u,
26
- maximumFractionDigits: 0
27
- }).format(e);
28
- return /* @__PURE__ */ o("div", {
29
- role: "button",
30
- tabIndex: 0,
31
- onClick: () => m?.(n),
32
- onKeyDown: (e) => {
33
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), m?.(n));
34
- },
35
- className: e("rounded-card border border-border-seam bg-bg-surface p-4 shadow-elevation-1", "transition-[box-shadow,border-color] duration-200", "hover:border-border-strong hover:shadow-pop cursor-pointer", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-canvas", h),
36
- children: [
37
- /* @__PURE__ */ o("div", {
38
- className: "flex items-start justify-between",
39
- children: [/* @__PURE__ */ a("h3", {
40
- className: "text-base font-semibold text-text-primary truncate",
41
- children: r
42
- }), /* @__PURE__ */ a(t, { status: p })]
43
- }),
44
- /* @__PURE__ */ o("div", {
45
- className: "mt-4",
46
- children: [
47
- /* @__PURE__ */ o("div", {
48
- className: "flex items-center justify-between text-sm",
49
- children: [/* @__PURE__ */ a("span", {
50
- className: "text-text-secondary",
51
- children: "Raised"
52
- }), /* @__PURE__ */ o("span", {
53
- className: "font-medium tabular-nums text-text-primary",
54
- children: [Math.round(g), "%"]
55
- })]
56
- }),
57
- /* @__PURE__ */ a("div", {
58
- className: "mt-1.5 h-2 w-full rounded-full bg-bg-sunken overflow-hidden",
59
- children: /* @__PURE__ */ a("div", {
60
- className: "h-full rounded-full bg-action-primary-bg transition-all duration-300",
61
- style: { width: `${g}%` }
62
- })
63
- }),
64
- /* @__PURE__ */ o("div", {
65
- className: "mt-1.5 flex items-center justify-between text-xs tabular-nums text-text-secondary",
66
- children: [/* @__PURE__ */ a("span", { children: y(l) }), /* @__PURE__ */ a("span", { children: y(c) })]
67
- })
68
- ]
69
- }),
70
- /* @__PURE__ */ o("div", {
71
- className: "mt-4 flex items-center justify-between",
72
- children: [/* @__PURE__ */ o("div", {
73
- className: "flex items-center gap-1.5 text-sm",
74
- children: [
75
- /* @__PURE__ */ a(i, { className: "h-3.5 w-3.5 text-status-success-text" }),
76
- /* @__PURE__ */ a("span", {
77
- className: "font-medium text-text-primary",
78
- children: d
79
- }),
80
- /* @__PURE__ */ a("span", {
81
- className: "text-text-secondary",
82
- children: "returns"
83
- })
84
- ]
85
- }), /* @__PURE__ */ o("div", {
86
- className: e("flex items-center gap-1 text-xs font-medium", _.color),
87
- children: [/* @__PURE__ */ a(v, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ a("span", { children: _.label })]
88
- })]
89
- })
90
- ]
91
- });
92
- };
93
- //#endregion
94
- export { c as InvestmentCard };
95
-
96
- //# sourceMappingURL=InvestmentCard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"InvestmentCard.js","names":[],"sources":["../../../src/atheletebridge/components/InvestmentCard.tsx"],"sourcesContent":["/**\n * Investment Card Component\n * @module atheletebridge/components\n *\n * Displays an investment opportunity with cart name, target/raised amounts,\n * progress bar, expected returns, risk level, and status.\n */\n\nimport type { FC } from 'react';\nimport { TrendingUp, AlertTriangle, Shield } from 'lucide-react';\nimport { cn } from '../utils/cn';\nimport { StatusBadge } from './StatusBadge';\nimport type { InvestmentStatus, RiskLevel } from '../types';\n\ninterface InvestmentCardProps {\n id: string;\n cartName: string;\n targetAmount: number;\n raisedAmount: number;\n currency?: string;\n expectedReturns: string;\n riskLevel: RiskLevel;\n status: InvestmentStatus;\n onClick?: (id: string) => void;\n className?: string;\n}\n\nconst riskConfig: Record<RiskLevel, { label: string; icon: typeof Shield; color: string }> = {\n low: {\n label: 'Low Risk',\n icon: Shield,\n color: 'text-status-success-text',\n },\n medium: {\n label: 'Medium Risk',\n icon: AlertTriangle,\n color: 'text-status-warning-text',\n },\n high: {\n label: 'High Risk',\n icon: AlertTriangle,\n color: 'text-status-error-text',\n },\n};\n\nexport const InvestmentCard: FC<InvestmentCardProps> = ({\n id,\n cartName,\n targetAmount,\n raisedAmount,\n currency = 'INR',\n expectedReturns,\n riskLevel,\n status,\n onClick,\n className,\n}) => {\n const progress = targetAmount > 0 ? Math.min((raisedAmount / targetAmount) * 100, 100) : 0;\n const risk = riskConfig[riskLevel];\n const RiskIcon = risk.icon;\n\n const formatAmount = (amount: number) =>\n new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency,\n maximumFractionDigits: 0,\n }).format(amount);\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => onClick?.(id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.(id);\n }\n }}\n className={cn(\n 'rounded-card border border-border-seam bg-bg-surface p-4 shadow-elevation-1',\n 'transition-[box-shadow,border-color] duration-200',\n 'hover:border-border-strong hover:shadow-pop cursor-pointer',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-canvas',\n className\n )}\n >\n {/* Header */}\n <div className=\"flex items-start justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary truncate\">{cartName}</h3>\n <StatusBadge status={status} />\n </div>\n\n {/* Progress Bar */}\n <div className=\"mt-4\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Raised</span>\n <span className=\"font-medium tabular-nums text-text-primary\">\n {Math.round(progress)}%\n </span>\n </div>\n <div className=\"mt-1.5 h-2 w-full rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-all duration-300\"\n style={{ width: `${progress}%` }}\n />\n </div>\n <div className=\"mt-1.5 flex items-center justify-between text-xs tabular-nums text-text-secondary\">\n <span>{formatAmount(raisedAmount)}</span>\n <span>{formatAmount(targetAmount)}</span>\n </div>\n </div>\n\n {/* Details */}\n <div className=\"mt-4 flex items-center justify-between\">\n <div className=\"flex items-center gap-1.5 text-sm\">\n <TrendingUp className=\"h-3.5 w-3.5 text-status-success-text\" />\n <span className=\"font-medium text-text-primary\">{expectedReturns}</span>\n <span className=\"text-text-secondary\">returns</span>\n </div>\n <div className={cn('flex items-center gap-1 text-xs font-medium', risk.color)}>\n <RiskIcon className=\"h-3.5 w-3.5\" />\n <span>{risk.label}</span>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;AA2BA,IAAM,IAAuF;CAC3F,KAAK;EACH,OAAO;EACP,MAAM;EACN,OAAO;EACR;CACD,QAAQ;EACN,OAAO;EACP,MAAM;EACN,OAAO;EACR;CACD,MAAM;EACJ,OAAO;EACP,MAAM;EACN,OAAO;EACR;CACF,EAEY,KAA2C,EACtD,OACA,aACA,iBACA,iBACA,cAAW,OACX,oBACA,cACA,WACA,YACA,mBACI;CACJ,IAAM,IAAW,IAAe,IAAI,KAAK,IAAK,IAAe,IAAgB,KAAK,IAAI,GAAG,GACnF,IAAO,EAAW,IAClB,IAAW,EAAK,MAEhB,KAAgB,MACpB,IAAI,KAAK,aAAa,KAAA,GAAW;EAC/B,OAAO;EACP;EACA,uBAAuB;EACxB,CAAC,CAAC,OAAO,EAAO;AAEnB,QACE,kBAAC,OAAD;EACE,MAAK;EACL,UAAU;EACV,eAAe,IAAU,EAAG;EAC5B,YAAY,MAAM;AAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,IAAU,EAAG;;EAGjB,WAAW,EACT,+EACA,qDACA,8DACA,mJACA,EACD;YAhBH;GAmBE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAAsD;KAAc,CAAA,EAClF,kBAAC,GAAD,EAAqB,WAAU,CAAA,CAC3B;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBAAsB;OAAa,CAAA,EACnD,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACG,KAAK,MAAM,EAAS,EAAC,IACjB;SACH;;KACN,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,OAAO,GAAG,EAAS,IAAI;OAChC,CAAA;MACE,CAAA;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAa,EAAa,EAAQ,CAAA,EACzC,kBAAC,QAAD,EAAA,UAAO,EAAa,EAAa,EAAQ,CAAA,CACrC;;KACF;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD,EAAY,WAAU,wCAAyC,CAAA;MAC/D,kBAAC,QAAD;OAAM,WAAU;iBAAiC;OAAuB,CAAA;MACxE,kBAAC,QAAD;OAAM,WAAU;iBAAsB;OAAc,CAAA;MAChD;QACN,kBAAC,OAAD;KAAK,WAAW,EAAG,+CAA+C,EAAK,MAAM;eAA7E,CACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,EACpC,kBAAC,QAAD,EAAA,UAAO,EAAK,OAAa,CAAA,CACrB;OACF;;GACF"}