@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.
- package/dist/atheletebridge/AthleteBridgeRoot.js +49 -129
- package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
- package/dist/atheletebridge/AthleteBridgeRoutes.js +65 -184
- package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
- package/dist/atheletebridge/components/CursorPager.js +34 -0
- package/dist/atheletebridge/components/CursorPager.js.map +1 -0
- package/dist/atheletebridge/components/FilterSelect.js +22 -0
- package/dist/atheletebridge/components/FilterSelect.js.map +1 -0
- package/dist/atheletebridge/components/FixtureCard.js +76 -0
- package/dist/atheletebridge/components/FixtureCard.js.map +1 -0
- package/dist/atheletebridge/components/LoadingState.js +36 -0
- package/dist/atheletebridge/components/LoadingState.js.map +1 -0
- package/dist/atheletebridge/components/ProgramCard.js +69 -0
- package/dist/atheletebridge/components/ProgramCard.js.map +1 -0
- package/dist/atheletebridge/components/SessionCard.js +76 -0
- package/dist/atheletebridge/components/SessionCard.js.map +1 -0
- package/dist/atheletebridge/components/StatusBadge.js +44 -35
- package/dist/atheletebridge/components/StatusBadge.js.map +1 -1
- package/dist/atheletebridge/components/TeamCard.js +81 -0
- package/dist/atheletebridge/components/TeamCard.js.map +1 -0
- package/dist/atheletebridge/components/domain.js +47 -0
- package/dist/atheletebridge/components/domain.js.map +1 -0
- package/dist/atheletebridge/components/form.js +29 -0
- package/dist/atheletebridge/components/form.js.map +1 -0
- package/dist/atheletebridge/context/AthleteBridgeContext.js +6 -6
- package/dist/atheletebridge/context/AthleteBridgeContext.js.map +1 -1
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +342 -165
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
- package/dist/atheletebridge/index.js +1 -1
- package/dist/atheletebridge/pages/DashboardPage.js +169 -0
- package/dist/atheletebridge/pages/DashboardPage.js.map +1 -0
- package/dist/atheletebridge/pages/StandingsPage.js +166 -0
- package/dist/atheletebridge/pages/StandingsPage.js.map +1 -0
- package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +201 -0
- package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -0
- package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js +205 -0
- package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js.map +1 -0
- package/dist/atheletebridge/pages/fixtures/FixturesListPage.js +92 -0
- package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -0
- package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +374 -0
- package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -0
- package/dist/atheletebridge/pages/programs/ProgramFormPage.js +207 -0
- package/dist/atheletebridge/pages/programs/ProgramFormPage.js.map +1 -0
- package/dist/atheletebridge/pages/programs/ProgramsListPage.js +113 -0
- package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -0
- package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +224 -0
- package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -0
- package/dist/atheletebridge/pages/sessions/SessionFormPage.js +206 -0
- package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -0
- package/dist/atheletebridge/pages/sessions/SessionsListPage.js +92 -0
- package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -0
- package/dist/atheletebridge/pages/teams/TeamDetailPage.js +350 -0
- package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -0
- package/dist/atheletebridge/pages/teams/TeamFormPage.js +222 -0
- package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -0
- package/dist/atheletebridge/pages/teams/TeamsListPage.js +101 -0
- package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -0
- package/dist/atheletebridge/store/atheletebridgeStore.js +2 -13
- package/dist/atheletebridge/store/atheletebridgeStore.js.map +1 -1
- package/dist/atheletebridge/utils/datetime.js +10 -0
- package/dist/atheletebridge/utils/datetime.js.map +1 -0
- package/dist/atheletebridge/utils/formatters.js +1 -4
- package/dist/atheletebridge/utils/formatters.js.map +1 -1
- package/package.json +1 -1
- package/dist/atheletebridge/components/InvestmentCard.js +0 -96
- package/dist/atheletebridge/components/InvestmentCard.js.map +0 -1
- package/dist/atheletebridge/components/RatingDisplay.js +0 -35
- package/dist/atheletebridge/components/RatingDisplay.js.map +0 -1
- package/dist/atheletebridge/mocks/data.js +0 -1517
- package/dist/atheletebridge/mocks/data.js.map +0 -1
- package/dist/atheletebridge/mocks/users.js +0 -34
- package/dist/atheletebridge/mocks/users.js.map +0 -1
- package/dist/atheletebridge/pages/HomePage.js +0 -936
- package/dist/atheletebridge/pages/HomePage.js.map +0 -1
- package/dist/atheletebridge/pages/admin/AdminAnalyticsPage.js +0 -653
- package/dist/atheletebridge/pages/admin/AdminAnalyticsPage.js.map +0 -1
- package/dist/atheletebridge/pages/admin/AdminDashboard.js +0 -671
- package/dist/atheletebridge/pages/admin/AdminDashboard.js.map +0 -1
- package/dist/atheletebridge/pages/admin/AdminFinancialPage.js +0 -429
- package/dist/atheletebridge/pages/admin/AdminFinancialPage.js.map +0 -1
- package/dist/atheletebridge/pages/admin/AdminOrdersPage.js +0 -667
- package/dist/atheletebridge/pages/admin/AdminOrdersPage.js.map +0 -1
- package/dist/atheletebridge/pages/admin/AdminProfilePage.js +0 -261
- package/dist/atheletebridge/pages/admin/AdminProfilePage.js.map +0 -1
- package/dist/atheletebridge/pages/admin/AdminSettingsPage.js +0 -653
- package/dist/atheletebridge/pages/admin/AdminSettingsPage.js.map +0 -1
- package/dist/atheletebridge/pages/admin/CartManagementPage.js +0 -876
- package/dist/atheletebridge/pages/admin/CartManagementPage.js.map +0 -1
- package/dist/atheletebridge/pages/admin/UserManagementPage.js +0 -900
- package/dist/atheletebridge/pages/admin/UserManagementPage.js.map +0 -1
- package/dist/atheletebridge/pages/cart-owner/AnalyticsDashboard.js +0 -839
- package/dist/atheletebridge/pages/cart-owner/AnalyticsDashboard.js.map +0 -1
- package/dist/atheletebridge/pages/cart-owner/BusinessSettingsPage.js +0 -704
- package/dist/atheletebridge/pages/cart-owner/BusinessSettingsPage.js.map +0 -1
- package/dist/atheletebridge/pages/cart-owner/CartOwnerDashboard.js +0 -792
- package/dist/atheletebridge/pages/cart-owner/CartOwnerDashboard.js.map +0 -1
- package/dist/atheletebridge/pages/cart-owner/CartOwnerProfilePage.js +0 -891
- package/dist/atheletebridge/pages/cart-owner/CartOwnerProfilePage.js.map +0 -1
- package/dist/atheletebridge/pages/cart-owner/CartServiceConfigPage.js +0 -633
- package/dist/atheletebridge/pages/cart-owner/CartServiceConfigPage.js.map +0 -1
- package/dist/atheletebridge/pages/cart-owner/InventoryManagementPage.js +0 -913
- package/dist/atheletebridge/pages/cart-owner/InventoryManagementPage.js.map +0 -1
- package/dist/atheletebridge/pages/cart-owner/OrderManagementPage.js +0 -881
- package/dist/atheletebridge/pages/cart-owner/OrderManagementPage.js.map +0 -1
- package/dist/atheletebridge/pages/cart-owner/StaffManagementPage.js +0 -841
- package/dist/atheletebridge/pages/cart-owner/StaffManagementPage.js.map +0 -1
- package/dist/atheletebridge/pages/common/HelpSupportPage.js +0 -1319
- package/dist/atheletebridge/pages/common/HelpSupportPage.js.map +0 -1
- package/dist/atheletebridge/pages/common/NotificationCenterPage.js +0 -674
- package/dist/atheletebridge/pages/common/NotificationCenterPage.js.map +0 -1
- package/dist/atheletebridge/pages/common/SettingsPage.js +0 -972
- package/dist/atheletebridge/pages/common/SettingsPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/BookingDetailsPage.js +0 -602
- package/dist/atheletebridge/pages/customer/BookingDetailsPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/CartDetailPage.js +0 -656
- package/dist/atheletebridge/pages/customer/CartDetailPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/CartDiscoveryPage.js +0 -558
- package/dist/atheletebridge/pages/customer/CartDiscoveryPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/CheckoutPage.js +0 -536
- package/dist/atheletebridge/pages/customer/CheckoutPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/CustomerDashboard.js +0 -539
- package/dist/atheletebridge/pages/customer/CustomerDashboard.js.map +0 -1
- package/dist/atheletebridge/pages/customer/CustomerProfilePage.js +0 -657
- package/dist/atheletebridge/pages/customer/CustomerProfilePage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/DirectServiceBookingPage.js +0 -635
- package/dist/atheletebridge/pages/customer/DirectServiceBookingPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/FavoritesPage.js +0 -486
- package/dist/atheletebridge/pages/customer/FavoritesPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/OrderHistoryPage.js +0 -447
- package/dist/atheletebridge/pages/customer/OrderHistoryPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/OrderTrackingPage.js +0 -393
- package/dist/atheletebridge/pages/customer/OrderTrackingPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/PaymentMethodsPage.js +0 -494
- package/dist/atheletebridge/pages/customer/PaymentMethodsPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/ReviewsPage.js +0 -615
- package/dist/atheletebridge/pages/customer/ReviewsPage.js.map +0 -1
- package/dist/atheletebridge/pages/customer/SavedAddressesPage.js +0 -451
- package/dist/atheletebridge/pages/customer/SavedAddressesPage.js.map +0 -1
- package/dist/atheletebridge/pages/investor/InvestmentDetailsPage.js +0 -881
- package/dist/atheletebridge/pages/investor/InvestmentDetailsPage.js.map +0 -1
- package/dist/atheletebridge/pages/investor/InvestmentOpportunitiesPage.js +0 -945
- package/dist/atheletebridge/pages/investor/InvestmentOpportunitiesPage.js.map +0 -1
- package/dist/atheletebridge/pages/investor/InvestorAnalyticsPage.js +0 -686
- package/dist/atheletebridge/pages/investor/InvestorAnalyticsPage.js.map +0 -1
- package/dist/atheletebridge/pages/investor/InvestorDashboard.js +0 -453
- package/dist/atheletebridge/pages/investor/InvestorDashboard.js.map +0 -1
- package/dist/atheletebridge/pages/investor/InvestorInvestmentsPage.js +0 -405
- package/dist/atheletebridge/pages/investor/InvestorInvestmentsPage.js.map +0 -1
- package/dist/atheletebridge/pages/investor/InvestorPortfolioPage.js +0 -577
- package/dist/atheletebridge/pages/investor/InvestorPortfolioPage.js.map +0 -1
- package/dist/atheletebridge/pages/investor/InvestorProfilePage.js +0 -1069
- package/dist/atheletebridge/pages/investor/InvestorProfilePage.js.map +0 -1
- package/dist/atheletebridge/pages/worker/TaskDetailsPage.js +0 -530
- package/dist/atheletebridge/pages/worker/TaskDetailsPage.js.map +0 -1
- package/dist/atheletebridge/pages/worker/WorkerDashboard.js +0 -669
- package/dist/atheletebridge/pages/worker/WorkerDashboard.js.map +0 -1
- package/dist/atheletebridge/pages/worker/WorkerOrdersPage.js +0 -681
- package/dist/atheletebridge/pages/worker/WorkerOrdersPage.js.map +0 -1
- package/dist/atheletebridge/pages/worker/WorkerProfilePage.js +0 -691
- package/dist/atheletebridge/pages/worker/WorkerProfilePage.js.map +0 -1
- package/dist/atheletebridge/pages/worker/WorkerSchedulePage.js +0 -588
- package/dist/atheletebridge/pages/worker/WorkerSchedulePage.js.map +0 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
|
|
2
|
+
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
|
+
import { StatusBadge as n } from "../../components/StatusBadge.js";
|
|
4
|
+
import { FIXTURE_TYPE_LABELS as r } from "../../components/domain.js";
|
|
5
|
+
import { formatDate as i } from "../../utils/formatters.js";
|
|
6
|
+
import { ErrorState as a, LoadingState as o } from "../../components/LoadingState.js";
|
|
7
|
+
import { useFixture as s, useRecordFixtureResult as c } from "../../hooks/useAthleteBridgeApi.js";
|
|
8
|
+
import { FormField as l, fieldInputClass as u } from "../../components/form.js";
|
|
9
|
+
import { useState as d } from "react";
|
|
10
|
+
import { ArrowLeft as f, CalendarClock as p, Flag as m, Loader2 as h, MapPin as g, Trophy as _ } from "lucide-react";
|
|
11
|
+
import { useParams as v } from "react-router-dom";
|
|
12
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
13
|
+
import { EmphasisPanel as x, GlassCard as S } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
//#region src/atheletebridge/pages/fixtures/FixtureDetailPage.tsx
|
|
15
|
+
function C() {
|
|
16
|
+
let { id: C } = v(), { navigateTo: w } = e(), T = s(C), E = c(), [D, O] = d(""), [k, A] = d(""), [j, M] = d(null);
|
|
17
|
+
if (T.isLoading) return /* @__PURE__ */ y(t, {
|
|
18
|
+
title: "Fixture",
|
|
19
|
+
children: /* @__PURE__ */ y(o, { label: "Loading fixture…" })
|
|
20
|
+
});
|
|
21
|
+
if (T.isError || !T.data) return /* @__PURE__ */ y(t, {
|
|
22
|
+
title: "Fixture",
|
|
23
|
+
children: /* @__PURE__ */ y(a, {
|
|
24
|
+
title: "Fixture not found",
|
|
25
|
+
message: "This fixture does not exist or you do not have access to it.",
|
|
26
|
+
onRetry: () => w("/fixtures")
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
let N = T.data, P = N.homeScore !== null && N.awayScore !== null, F = N.homeTeam?.name ?? "Home", I = N.awayTeam?.name ?? (N.awayTeamId ? "Away" : "TBD"), L = !!N.awayTeamId && (N.status === "SCHEDULED" || N.status === "LIVE");
|
|
30
|
+
return /* @__PURE__ */ b(t, {
|
|
31
|
+
title: `${F} vs ${I}`,
|
|
32
|
+
description: `${r[N.type]}${N.competition ? ` · ${N.competition}` : ""}`,
|
|
33
|
+
actions: /* @__PURE__ */ b("button", {
|
|
34
|
+
type: "button",
|
|
35
|
+
onClick: () => w("/fixtures"),
|
|
36
|
+
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",
|
|
37
|
+
children: [/* @__PURE__ */ y(f, { className: "h-4 w-4" }), " Back"]
|
|
38
|
+
}),
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ b(S, {
|
|
41
|
+
treatment: "glass",
|
|
42
|
+
glow: !0,
|
|
43
|
+
className: "mb-8 p-8",
|
|
44
|
+
children: [
|
|
45
|
+
/* @__PURE__ */ y("div", {
|
|
46
|
+
className: "mb-4 flex items-center justify-center",
|
|
47
|
+
children: /* @__PURE__ */ y(n, { status: N.status })
|
|
48
|
+
}),
|
|
49
|
+
/* @__PURE__ */ b("div", {
|
|
50
|
+
className: "flex items-center justify-center gap-6",
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ y("span", {
|
|
53
|
+
className: "flex-1 text-right text-lg font-semibold text-text-primary",
|
|
54
|
+
children: F
|
|
55
|
+
}),
|
|
56
|
+
/* @__PURE__ */ y("span", {
|
|
57
|
+
className: "rounded-xl bg-bg-sunken px-5 py-2 text-3xl font-bold tabular-nums text-text-primary",
|
|
58
|
+
children: P ? `${N.homeScore} : ${N.awayScore}` : "vs"
|
|
59
|
+
}),
|
|
60
|
+
/* @__PURE__ */ y("span", {
|
|
61
|
+
className: "flex-1 text-left text-lg font-semibold text-text-primary",
|
|
62
|
+
children: I
|
|
63
|
+
})
|
|
64
|
+
]
|
|
65
|
+
}),
|
|
66
|
+
/* @__PURE__ */ b("div", {
|
|
67
|
+
className: "mt-6 flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-sm text-text-secondary",
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ b("span", {
|
|
70
|
+
className: "flex items-center gap-1.5",
|
|
71
|
+
children: [
|
|
72
|
+
/* @__PURE__ */ y(p, { className: "h-4 w-4" }),
|
|
73
|
+
" ",
|
|
74
|
+
i(N.scheduledAt)
|
|
75
|
+
]
|
|
76
|
+
}),
|
|
77
|
+
N.venue && /* @__PURE__ */ b("span", {
|
|
78
|
+
className: "flex items-center gap-1.5",
|
|
79
|
+
children: [
|
|
80
|
+
/* @__PURE__ */ y(g, { className: "h-4 w-4" }),
|
|
81
|
+
" ",
|
|
82
|
+
N.venue
|
|
83
|
+
]
|
|
84
|
+
}),
|
|
85
|
+
N.round && /* @__PURE__ */ y("span", { children: N.round })
|
|
86
|
+
]
|
|
87
|
+
})
|
|
88
|
+
]
|
|
89
|
+
}),
|
|
90
|
+
N.notes && /* @__PURE__ */ b(x, {
|
|
91
|
+
className: "mb-8",
|
|
92
|
+
children: [/* @__PURE__ */ y("h2", {
|
|
93
|
+
className: "mb-2 text-sm font-semibold text-text-primary",
|
|
94
|
+
children: "Notes"
|
|
95
|
+
}), /* @__PURE__ */ y("p", {
|
|
96
|
+
className: "text-sm text-text-secondary",
|
|
97
|
+
children: N.notes
|
|
98
|
+
})]
|
|
99
|
+
}),
|
|
100
|
+
L && /* @__PURE__ */ b("section", {
|
|
101
|
+
className: "mb-8",
|
|
102
|
+
children: [/* @__PURE__ */ b("h2", {
|
|
103
|
+
className: "mb-4 flex items-center gap-2 text-lg font-semibold text-text-primary",
|
|
104
|
+
children: [/* @__PURE__ */ y(m, { className: "h-5 w-5" }), " Record result"]
|
|
105
|
+
}), /* @__PURE__ */ b(S, {
|
|
106
|
+
treatment: "insight",
|
|
107
|
+
className: "p-6",
|
|
108
|
+
children: [
|
|
109
|
+
/* @__PURE__ */ b("p", {
|
|
110
|
+
className: "mb-4 text-sm text-text-secondary",
|
|
111
|
+
children: [
|
|
112
|
+
"Recording a final score marks this fixture ",
|
|
113
|
+
/* @__PURE__ */ y("strong", { children: "Completed" }),
|
|
114
|
+
" and recomputes the competition standings for both teams."
|
|
115
|
+
]
|
|
116
|
+
}),
|
|
117
|
+
/* @__PURE__ */ b("form", {
|
|
118
|
+
onSubmit: async (e) => {
|
|
119
|
+
if (e.preventDefault(), M(null), !C) return;
|
|
120
|
+
let t = Number.parseInt(D, 10), n = Number.parseInt(k, 10);
|
|
121
|
+
if (Number.isNaN(t) || Number.isNaN(n)) {
|
|
122
|
+
M("Both scores are required and must be numbers.");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (t < 0 || n < 0) {
|
|
126
|
+
M("Scores cannot be negative.");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
await E.mutateAsync({
|
|
131
|
+
id: C,
|
|
132
|
+
input: {
|
|
133
|
+
homeScore: t,
|
|
134
|
+
awayScore: n
|
|
135
|
+
}
|
|
136
|
+
}), O(""), A("");
|
|
137
|
+
} catch (e) {
|
|
138
|
+
M(e instanceof Error ? e.message : "Failed to record result.");
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
className: "flex flex-wrap items-end gap-4",
|
|
142
|
+
children: [
|
|
143
|
+
/* @__PURE__ */ y(l, {
|
|
144
|
+
label: `${F} score`,
|
|
145
|
+
htmlFor: "homeScore",
|
|
146
|
+
className: "w-32",
|
|
147
|
+
children: /* @__PURE__ */ y("input", {
|
|
148
|
+
id: "homeScore",
|
|
149
|
+
inputMode: "numeric",
|
|
150
|
+
className: u,
|
|
151
|
+
value: D,
|
|
152
|
+
onChange: (e) => O(e.target.value),
|
|
153
|
+
placeholder: "0"
|
|
154
|
+
})
|
|
155
|
+
}),
|
|
156
|
+
/* @__PURE__ */ y(l, {
|
|
157
|
+
label: `${I} score`,
|
|
158
|
+
htmlFor: "awayScore",
|
|
159
|
+
className: "w-32",
|
|
160
|
+
children: /* @__PURE__ */ y("input", {
|
|
161
|
+
id: "awayScore",
|
|
162
|
+
inputMode: "numeric",
|
|
163
|
+
className: u,
|
|
164
|
+
value: k,
|
|
165
|
+
onChange: (e) => A(e.target.value),
|
|
166
|
+
placeholder: "0"
|
|
167
|
+
})
|
|
168
|
+
}),
|
|
169
|
+
/* @__PURE__ */ b("button", {
|
|
170
|
+
type: "submit",
|
|
171
|
+
disabled: E.isPending,
|
|
172
|
+
className: "inline-flex h-[38px] items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60",
|
|
173
|
+
children: [E.isPending ? /* @__PURE__ */ y(h, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ y(_, { className: "h-4 w-4" }), "Record"]
|
|
174
|
+
})
|
|
175
|
+
]
|
|
176
|
+
}),
|
|
177
|
+
j && /* @__PURE__ */ y("p", {
|
|
178
|
+
className: "mt-3 text-sm text-status-error-text",
|
|
179
|
+
children: j
|
|
180
|
+
})
|
|
181
|
+
]
|
|
182
|
+
})]
|
|
183
|
+
}),
|
|
184
|
+
N.competition && /* @__PURE__ */ b("button", {
|
|
185
|
+
type: "button",
|
|
186
|
+
onClick: () => w(`/standings?competition=${encodeURIComponent(N.competition ?? "")}`),
|
|
187
|
+
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",
|
|
188
|
+
children: [
|
|
189
|
+
/* @__PURE__ */ y(_, { className: "h-4 w-4" }),
|
|
190
|
+
" View ",
|
|
191
|
+
N.competition,
|
|
192
|
+
" standings"
|
|
193
|
+
]
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
//#endregion
|
|
199
|
+
export { C as FixtureDetailPage };
|
|
200
|
+
|
|
201
|
+
//# sourceMappingURL=FixtureDetailPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixtureDetailPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/fixtures/FixtureDetailPage.tsx"],"sourcesContent":["/**\n * Fixture Detail\n * @module atheletebridge/pages/fixtures\n *\n * Reads a single fixture (athFixture) and lets the user record a final result\n * (athRecordFixtureResult) which marks it COMPLETED and recomputes standings.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, CalendarClock, MapPin, Trophy, Loader2, Flag } from 'lucide-react';\nimport { GlassCard, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { FIXTURE_TYPE_LABELS } from '../../components/domain';\nimport { formatDate } from '../../utils/formatters';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useFixture, useRecordFixtureResult } from '../../hooks/useAthleteBridgeApi';\n\nexport function FixtureDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useAthleteBridge();\n\n const fixture = useFixture(id);\n const recordResult = useRecordFixtureResult();\n\n const [homeScore, setHomeScore] = useState('');\n const [awayScore, setAwayScore] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n if (fixture.isLoading) {\n return (\n <PageLayout title=\"Fixture\">\n <LoadingState label=\"Loading fixture…\" />\n </PageLayout>\n );\n }\n\n if (fixture.isError || !fixture.data) {\n return (\n <PageLayout title=\"Fixture\">\n <ErrorState\n title=\"Fixture not found\"\n message=\"This fixture does not exist or you do not have access to it.\"\n onRetry={() => navigateTo('/fixtures')}\n />\n </PageLayout>\n );\n }\n\n const f = fixture.data;\n const hasScore = f.homeScore !== null && f.awayScore !== null;\n const homeName = f.homeTeam?.name ?? 'Home';\n const awayName = f.awayTeam?.name ?? (f.awayTeamId ? 'Away' : 'TBD');\n const canRecordResult =\n Boolean(f.awayTeamId) && (f.status === 'SCHEDULED' || f.status === 'LIVE');\n\n const handleRecord = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!id) return;\n const home = Number.parseInt(homeScore, 10);\n const away = Number.parseInt(awayScore, 10);\n if (Number.isNaN(home) || Number.isNaN(away)) {\n setError('Both scores are required and must be numbers.');\n return;\n }\n if (home < 0 || away < 0) {\n setError('Scores cannot be negative.');\n return;\n }\n try {\n await recordResult.mutateAsync({ id, input: { homeScore: home, awayScore: away } });\n setHomeScore('');\n setAwayScore('');\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to record result.');\n }\n };\n\n return (\n <PageLayout\n title={`${homeName} vs ${awayName}`}\n description={`${FIXTURE_TYPE_LABELS[f.type]}${f.competition ? ` · ${f.competition}` : ''}`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures')}\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\" /> Back\n </button>\n }\n >\n {/* Scoreboard */}\n <GlassCard treatment=\"glass\" glow className=\"mb-8 p-8\">\n <div className=\"mb-4 flex items-center justify-center\">\n <StatusBadge status={f.status} />\n </div>\n <div className=\"flex items-center justify-center gap-6\">\n <span className=\"flex-1 text-right text-lg font-semibold text-text-primary\">\n {homeName}\n </span>\n <span className=\"rounded-xl bg-bg-sunken px-5 py-2 text-3xl font-bold tabular-nums text-text-primary\">\n {hasScore ? `${f.homeScore} : ${f.awayScore}` : 'vs'}\n </span>\n <span className=\"flex-1 text-left text-lg font-semibold text-text-primary\">\n {awayName}\n </span>\n </div>\n <div className=\"mt-6 flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1.5\">\n <CalendarClock className=\"h-4 w-4\" /> {formatDate(f.scheduledAt)}\n </span>\n {f.venue && (\n <span className=\"flex items-center gap-1.5\">\n <MapPin className=\"h-4 w-4\" /> {f.venue}\n </span>\n )}\n {f.round && <span>{f.round}</span>}\n </div>\n </GlassCard>\n\n {f.notes && (\n <EmphasisPanel className=\"mb-8\">\n <h2 className=\"mb-2 text-sm font-semibold text-text-primary\">Notes</h2>\n <p className=\"text-sm text-text-secondary\">{f.notes}</p>\n </EmphasisPanel>\n )}\n\n {/* Record result */}\n {canRecordResult && (\n <section className=\"mb-8\">\n <h2 className=\"mb-4 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Flag className=\"h-5 w-5\" /> Record result\n </h2>\n <GlassCard treatment=\"insight\" className=\"p-6\">\n <p className=\"mb-4 text-sm text-text-secondary\">\n Recording a final score marks this fixture <strong>Completed</strong> and recomputes\n the competition standings for both teams.\n </p>\n <form onSubmit={handleRecord} className=\"flex flex-wrap items-end gap-4\">\n <FormField label={`${homeName} score`} htmlFor=\"homeScore\" className=\"w-32\">\n <input\n id=\"homeScore\"\n inputMode=\"numeric\"\n className={fieldInputClass}\n value={homeScore}\n onChange={(e) => setHomeScore(e.target.value)}\n placeholder=\"0\"\n />\n </FormField>\n <FormField label={`${awayName} score`} htmlFor=\"awayScore\" className=\"w-32\">\n <input\n id=\"awayScore\"\n inputMode=\"numeric\"\n className={fieldInputClass}\n value={awayScore}\n onChange={(e) => setAwayScore(e.target.value)}\n placeholder=\"0\"\n />\n </FormField>\n <button\n type=\"submit\"\n disabled={recordResult.isPending}\n className=\"inline-flex h-[38px] items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60\"\n >\n {recordResult.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trophy className=\"h-4 w-4\" />\n )}\n Record\n </button>\n </form>\n {error && <p className=\"mt-3 text-sm text-status-error-text\">{error}</p>}\n </GlassCard>\n </section>\n )}\n\n {f.competition && (\n <button\n type=\"button\"\n onClick={() =>\n navigateTo(`/standings?competition=${encodeURIComponent(f.competition ?? '')}`)\n }\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 <Trophy className=\"h-4 w-4\" /> View {f.competition} standings\n </button>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
|
|
2
|
+
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
|
+
import { FIXTURE_TYPE_LABELS as n } from "../../components/domain.js";
|
|
4
|
+
import { LoadingState as r } from "../../components/LoadingState.js";
|
|
5
|
+
import { useScheduleFixture as i, useTeams as a } from "../../hooks/useAthleteBridgeApi.js";
|
|
6
|
+
import { FormField as o, fieldInputClass as s } from "../../components/form.js";
|
|
7
|
+
import { toIsoOrUndefined as c } from "../../utils/datetime.js";
|
|
8
|
+
import { useState as l } from "react";
|
|
9
|
+
import { ArrowLeft as u, Loader2 as d, Save as f } from "lucide-react";
|
|
10
|
+
import { useSearchParams as p } from "react-router-dom";
|
|
11
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
12
|
+
//#region src/atheletebridge/pages/fixtures/FixtureFormPage.tsx
|
|
13
|
+
var g = Object.keys(n);
|
|
14
|
+
function _() {
|
|
15
|
+
let [_] = p(), { navigateTo: v } = e(), y = a({ pagination: { limit: 100 } }), b = i(), [x, S] = l(_.get("homeTeamId") ?? ""), [C, w] = l(""), [T, E] = l("FRIENDLY"), [D, O] = l(""), [k, A] = l(""), [j, M] = l(""), [N, P] = l(""), [F, I] = l(""), [L, R] = l(""), [z, B] = l(null), V = y.data?.items ?? [];
|
|
16
|
+
return y.isLoading ? /* @__PURE__ */ m(t, {
|
|
17
|
+
title: "Schedule fixture",
|
|
18
|
+
children: /* @__PURE__ */ m(r, { label: "Loading teams…" })
|
|
19
|
+
}) : /* @__PURE__ */ m(t, {
|
|
20
|
+
title: "Schedule fixture",
|
|
21
|
+
description: "Set up a match between a home team and an optional away team.",
|
|
22
|
+
actions: /* @__PURE__ */ h("button", {
|
|
23
|
+
type: "button",
|
|
24
|
+
onClick: () => v("/fixtures"),
|
|
25
|
+
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",
|
|
26
|
+
children: [/* @__PURE__ */ m(u, { className: "h-4 w-4" }), " Cancel"]
|
|
27
|
+
}),
|
|
28
|
+
children: /* @__PURE__ */ h("form", {
|
|
29
|
+
onSubmit: async (e) => {
|
|
30
|
+
if (e.preventDefault(), B(null), !x) {
|
|
31
|
+
B("A home team is required.");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!N) {
|
|
35
|
+
B("A scheduled date and time is required.");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (C && C === x) {
|
|
39
|
+
B("Home and away teams must be different.");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
v(`/fixtures/${(await b.mutateAsync({
|
|
44
|
+
homeTeamId: x,
|
|
45
|
+
awayTeamId: C || void 0,
|
|
46
|
+
type: T,
|
|
47
|
+
competition: D.trim() || void 0,
|
|
48
|
+
round: k.trim() || void 0,
|
|
49
|
+
venue: j.trim() || void 0,
|
|
50
|
+
scheduledAt: new Date(N).toISOString(),
|
|
51
|
+
kickoffAt: c(F),
|
|
52
|
+
notes: L.trim() || void 0
|
|
53
|
+
})).id}`);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
B(e instanceof Error ? e.message : "Failed to schedule fixture.");
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
className: "max-w-2xl space-y-5",
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ h("div", {
|
|
61
|
+
className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
|
|
62
|
+
children: [/* @__PURE__ */ m(o, {
|
|
63
|
+
label: "Home team",
|
|
64
|
+
htmlFor: "homeTeam",
|
|
65
|
+
required: !0,
|
|
66
|
+
children: /* @__PURE__ */ h("select", {
|
|
67
|
+
id: "homeTeam",
|
|
68
|
+
className: s,
|
|
69
|
+
value: x,
|
|
70
|
+
onChange: (e) => S(e.target.value),
|
|
71
|
+
children: [/* @__PURE__ */ m("option", {
|
|
72
|
+
value: "",
|
|
73
|
+
children: "Select a team"
|
|
74
|
+
}), V.map((e) => /* @__PURE__ */ m("option", {
|
|
75
|
+
value: e.id,
|
|
76
|
+
children: e.name
|
|
77
|
+
}, e.id))]
|
|
78
|
+
})
|
|
79
|
+
}), /* @__PURE__ */ m(o, {
|
|
80
|
+
label: "Away team",
|
|
81
|
+
htmlFor: "awayTeam",
|
|
82
|
+
hint: "Optional for trials / open events.",
|
|
83
|
+
children: /* @__PURE__ */ h("select", {
|
|
84
|
+
id: "awayTeam",
|
|
85
|
+
className: s,
|
|
86
|
+
value: C,
|
|
87
|
+
onChange: (e) => w(e.target.value),
|
|
88
|
+
children: [/* @__PURE__ */ m("option", {
|
|
89
|
+
value: "",
|
|
90
|
+
children: "No away team"
|
|
91
|
+
}), V.map((e) => /* @__PURE__ */ m("option", {
|
|
92
|
+
value: e.id,
|
|
93
|
+
children: e.name
|
|
94
|
+
}, e.id))]
|
|
95
|
+
})
|
|
96
|
+
})]
|
|
97
|
+
}),
|
|
98
|
+
/* @__PURE__ */ m(o, {
|
|
99
|
+
label: "Type",
|
|
100
|
+
htmlFor: "type",
|
|
101
|
+
children: /* @__PURE__ */ m("select", {
|
|
102
|
+
id: "type",
|
|
103
|
+
className: s,
|
|
104
|
+
value: T,
|
|
105
|
+
onChange: (e) => E(e.target.value),
|
|
106
|
+
children: g.map((e) => /* @__PURE__ */ m("option", {
|
|
107
|
+
value: e,
|
|
108
|
+
children: n[e]
|
|
109
|
+
}, e))
|
|
110
|
+
})
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ h("div", {
|
|
113
|
+
className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
|
|
114
|
+
children: [/* @__PURE__ */ m(o, {
|
|
115
|
+
label: "Competition",
|
|
116
|
+
htmlFor: "competition",
|
|
117
|
+
hint: "Used to group standings.",
|
|
118
|
+
children: /* @__PURE__ */ m("input", {
|
|
119
|
+
id: "competition",
|
|
120
|
+
className: s,
|
|
121
|
+
value: D,
|
|
122
|
+
onChange: (e) => O(e.target.value),
|
|
123
|
+
placeholder: "e.g. Spring League 2026"
|
|
124
|
+
})
|
|
125
|
+
}), /* @__PURE__ */ m(o, {
|
|
126
|
+
label: "Round",
|
|
127
|
+
htmlFor: "round",
|
|
128
|
+
children: /* @__PURE__ */ m("input", {
|
|
129
|
+
id: "round",
|
|
130
|
+
className: s,
|
|
131
|
+
value: k,
|
|
132
|
+
onChange: (e) => A(e.target.value),
|
|
133
|
+
placeholder: "e.g. Round 4"
|
|
134
|
+
})
|
|
135
|
+
})]
|
|
136
|
+
}),
|
|
137
|
+
/* @__PURE__ */ m(o, {
|
|
138
|
+
label: "Venue",
|
|
139
|
+
htmlFor: "venue",
|
|
140
|
+
children: /* @__PURE__ */ m("input", {
|
|
141
|
+
id: "venue",
|
|
142
|
+
className: s,
|
|
143
|
+
value: j,
|
|
144
|
+
onChange: (e) => M(e.target.value),
|
|
145
|
+
placeholder: "e.g. Riverside Stadium"
|
|
146
|
+
})
|
|
147
|
+
}),
|
|
148
|
+
/* @__PURE__ */ h("div", {
|
|
149
|
+
className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
|
|
150
|
+
children: [/* @__PURE__ */ m(o, {
|
|
151
|
+
label: "Scheduled at",
|
|
152
|
+
htmlFor: "scheduledAt",
|
|
153
|
+
required: !0,
|
|
154
|
+
children: /* @__PURE__ */ m("input", {
|
|
155
|
+
id: "scheduledAt",
|
|
156
|
+
type: "datetime-local",
|
|
157
|
+
className: s,
|
|
158
|
+
value: N,
|
|
159
|
+
onChange: (e) => P(e.target.value)
|
|
160
|
+
})
|
|
161
|
+
}), /* @__PURE__ */ m(o, {
|
|
162
|
+
label: "Kick-off at",
|
|
163
|
+
htmlFor: "kickoffAt",
|
|
164
|
+
children: /* @__PURE__ */ m("input", {
|
|
165
|
+
id: "kickoffAt",
|
|
166
|
+
type: "datetime-local",
|
|
167
|
+
className: s,
|
|
168
|
+
value: F,
|
|
169
|
+
onChange: (e) => I(e.target.value)
|
|
170
|
+
})
|
|
171
|
+
})]
|
|
172
|
+
}),
|
|
173
|
+
/* @__PURE__ */ m(o, {
|
|
174
|
+
label: "Notes",
|
|
175
|
+
htmlFor: "notes",
|
|
176
|
+
children: /* @__PURE__ */ m("textarea", {
|
|
177
|
+
id: "notes",
|
|
178
|
+
className: s,
|
|
179
|
+
rows: 3,
|
|
180
|
+
value: L,
|
|
181
|
+
onChange: (e) => R(e.target.value),
|
|
182
|
+
placeholder: "Any extra context for this fixture."
|
|
183
|
+
})
|
|
184
|
+
}),
|
|
185
|
+
z && /* @__PURE__ */ m("p", {
|
|
186
|
+
className: "text-sm text-status-error-text",
|
|
187
|
+
children: z
|
|
188
|
+
}),
|
|
189
|
+
/* @__PURE__ */ m("div", {
|
|
190
|
+
className: "pt-2",
|
|
191
|
+
children: /* @__PURE__ */ h("button", {
|
|
192
|
+
type: "submit",
|
|
193
|
+
disabled: b.isPending,
|
|
194
|
+
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",
|
|
195
|
+
children: [b.isPending ? /* @__PURE__ */ m(d, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ m(f, { className: "h-4 w-4" }), "Schedule fixture"]
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
]
|
|
199
|
+
})
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
export { _ as FixtureFormPage };
|
|
204
|
+
|
|
205
|
+
//# sourceMappingURL=FixtureFormPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixtureFormPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/fixtures/FixtureFormPage.tsx"],"sourcesContent":["/**\n * Fixture Schedule Form\n * @module atheletebridge/pages/fixtures\n */\n\nimport { useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { ArrowLeft, Loader2, Save } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { LoadingState } from '../../components/LoadingState';\nimport { FIXTURE_TYPE_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useScheduleFixture, useTeams } from '../../hooks/useAthleteBridgeApi';\nimport { toIsoOrUndefined } from '../../utils/datetime';\nimport type { AthFixtureType } from '../../types';\n\nconst TYPES = Object.keys(FIXTURE_TYPE_LABELS) as AthFixtureType[];\n\nexport function FixtureFormPage() {\n const [searchParams] = useSearchParams();\n const { navigateTo } = useAthleteBridge();\n\n const teams = useTeams({ pagination: { limit: 100 } });\n const scheduleFixture = useScheduleFixture();\n\n const [homeTeamId, setHomeTeamId] = useState(searchParams.get('homeTeamId') ?? '');\n const [awayTeamId, setAwayTeamId] = useState('');\n const [type, setType] = useState<AthFixtureType>('FRIENDLY');\n const [competition, setCompetition] = useState('');\n const [round, setRound] = useState('');\n const [venue, setVenue] = useState('');\n const [scheduledAt, setScheduledAt] = useState('');\n const [kickoffAt, setKickoffAt] = useState('');\n const [notes, setNotes] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n const teamOptions = teams.data?.items ?? [];\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (!homeTeamId) {\n setError('A home team is required.');\n return;\n }\n if (!scheduledAt) {\n setError('A scheduled date and time is required.');\n return;\n }\n if (awayTeamId && awayTeamId === homeTeamId) {\n setError('Home and away teams must be different.');\n return;\n }\n\n try {\n const created = await scheduleFixture.mutateAsync({\n homeTeamId,\n awayTeamId: awayTeamId || undefined,\n type,\n competition: competition.trim() || undefined,\n round: round.trim() || undefined,\n venue: venue.trim() || undefined,\n scheduledAt: new Date(scheduledAt).toISOString(),\n kickoffAt: toIsoOrUndefined(kickoffAt),\n notes: notes.trim() || undefined,\n });\n navigateTo(`/fixtures/${created.id}`);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to schedule fixture.');\n }\n };\n\n if (teams.isLoading) {\n return (\n <PageLayout title=\"Schedule fixture\">\n <LoadingState label=\"Loading teams…\" />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Schedule fixture\"\n description=\"Set up a match between a home team and an optional away team.\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures')}\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 <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Home team\" htmlFor=\"homeTeam\" required>\n <select\n id=\"homeTeam\"\n className={fieldInputClass}\n value={homeTeamId}\n onChange={(e) => setHomeTeamId(e.target.value)}\n >\n <option value=\"\">Select a team</option>\n {teamOptions.map((tm) => (\n <option key={tm.id} value={tm.id}>\n {tm.name}\n </option>\n ))}\n </select>\n </FormField>\n\n <FormField label=\"Away team\" htmlFor=\"awayTeam\" hint=\"Optional for trials / open events.\">\n <select\n id=\"awayTeam\"\n className={fieldInputClass}\n value={awayTeamId}\n onChange={(e) => setAwayTeamId(e.target.value)}\n >\n <option value=\"\">No away team</option>\n {teamOptions.map((tm) => (\n <option key={tm.id} value={tm.id}>\n {tm.name}\n </option>\n ))}\n </select>\n </FormField>\n </div>\n\n <FormField label=\"Type\" htmlFor=\"type\">\n <select\n id=\"type\"\n className={fieldInputClass}\n value={type}\n onChange={(e) => setType(e.target.value as AthFixtureType)}\n >\n {TYPES.map((tp) => (\n <option key={tp} value={tp}>\n {FIXTURE_TYPE_LABELS[tp]}\n </option>\n ))}\n </select>\n </FormField>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Competition\" htmlFor=\"competition\" hint=\"Used to group standings.\">\n <input\n id=\"competition\"\n className={fieldInputClass}\n value={competition}\n onChange={(e) => setCompetition(e.target.value)}\n placeholder=\"e.g. Spring League 2026\"\n />\n </FormField>\n\n <FormField label=\"Round\" htmlFor=\"round\">\n <input\n id=\"round\"\n className={fieldInputClass}\n value={round}\n onChange={(e) => setRound(e.target.value)}\n placeholder=\"e.g. Round 4\"\n />\n </FormField>\n </div>\n\n <FormField label=\"Venue\" htmlFor=\"venue\">\n <input\n id=\"venue\"\n className={fieldInputClass}\n value={venue}\n onChange={(e) => setVenue(e.target.value)}\n placeholder=\"e.g. Riverside Stadium\"\n />\n </FormField>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Scheduled at\" htmlFor=\"scheduledAt\" required>\n <input\n id=\"scheduledAt\"\n type=\"datetime-local\"\n className={fieldInputClass}\n value={scheduledAt}\n onChange={(e) => setScheduledAt(e.target.value)}\n />\n </FormField>\n\n <FormField label=\"Kick-off at\" htmlFor=\"kickoffAt\">\n <input\n id=\"kickoffAt\"\n type=\"datetime-local\"\n className={fieldInputClass}\n value={kickoffAt}\n onChange={(e) => setKickoffAt(e.target.value)}\n />\n </FormField>\n </div>\n\n <FormField label=\"Notes\" htmlFor=\"notes\">\n <textarea\n id=\"notes\"\n className={fieldInputClass}\n rows={3}\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n placeholder=\"Any extra context for this fixture.\"\n />\n </FormField>\n\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n\n <div className=\"pt-2\">\n <button\n type=\"submit\"\n disabled={scheduleFixture.isPending}\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 {scheduleFixture.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"h-4 w-4\" />\n )}\n Schedule fixture\n </button>\n </div>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
|
|
2
|
+
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
|
+
import { FixtureCard as n } from "../../components/FixtureCard.js";
|
|
4
|
+
import { EmptyState as r } from "../../components/EmptyState.js";
|
|
5
|
+
import { ErrorState as i, LoadingState as a } from "../../components/LoadingState.js";
|
|
6
|
+
import { useFixtures as o } from "../../hooks/useAthleteBridgeApi.js";
|
|
7
|
+
import { FilterSelect as s } from "../../components/FilterSelect.js";
|
|
8
|
+
import { CursorPager as c } from "../../components/CursorPager.js";
|
|
9
|
+
import { useState as l } from "react";
|
|
10
|
+
import { CalendarDays as u, Plus as d } from "lucide-react";
|
|
11
|
+
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
12
|
+
//#region src/atheletebridge/pages/fixtures/FixturesListPage.tsx
|
|
13
|
+
var h = 12, g = [
|
|
14
|
+
{
|
|
15
|
+
value: "SCHEDULED",
|
|
16
|
+
label: "Scheduled"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: "LIVE",
|
|
20
|
+
label: "Live"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: "COMPLETED",
|
|
24
|
+
label: "Completed"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
value: "POSTPONED",
|
|
28
|
+
label: "Postponed"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: "CANCELLED",
|
|
32
|
+
label: "Cancelled"
|
|
33
|
+
}
|
|
34
|
+
];
|
|
35
|
+
function _() {
|
|
36
|
+
let { navigateTo: _ } = e(), [v, y] = l(""), [b, x] = l(0), S = o({
|
|
37
|
+
status: v || void 0,
|
|
38
|
+
pagination: {
|
|
39
|
+
limit: h,
|
|
40
|
+
offset: b * h
|
|
41
|
+
}
|
|
42
|
+
}), C = S.data?.items ?? [], w = S.data?.pageInfo.hasMore ?? !1;
|
|
43
|
+
return /* @__PURE__ */ m(t, {
|
|
44
|
+
title: "Fixtures",
|
|
45
|
+
description: "Matches across friendlies, league games, cups, tournaments and scrimmages.",
|
|
46
|
+
actions: /* @__PURE__ */ m("button", {
|
|
47
|
+
type: "button",
|
|
48
|
+
onClick: () => _("/fixtures/new"),
|
|
49
|
+
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",
|
|
50
|
+
children: [/* @__PURE__ */ p(d, { className: "h-4 w-4" }), " Schedule fixture"]
|
|
51
|
+
}),
|
|
52
|
+
children: [/* @__PURE__ */ p("div", {
|
|
53
|
+
className: "mb-6 flex flex-wrap items-center gap-3",
|
|
54
|
+
children: /* @__PURE__ */ p(s, {
|
|
55
|
+
ariaLabel: "Filter by status",
|
|
56
|
+
allLabel: "All statuses",
|
|
57
|
+
value: v,
|
|
58
|
+
onChange: (e) => {
|
|
59
|
+
y(e), x(0);
|
|
60
|
+
},
|
|
61
|
+
options: g
|
|
62
|
+
})
|
|
63
|
+
}), S.isLoading ? /* @__PURE__ */ p(a, { label: "Loading fixtures…" }) : S.isError ? /* @__PURE__ */ p(i, { onRetry: () => void S.refetch() }) : C.length === 0 ? /* @__PURE__ */ p(r, {
|
|
64
|
+
illustration: "empty-calendar",
|
|
65
|
+
icon: /* @__PURE__ */ p(u, { className: "h-10 w-10" }),
|
|
66
|
+
title: "No fixtures found",
|
|
67
|
+
description: v ? "Try clearing your filter to see all fixtures." : "Schedule a match to start tracking results and standings.",
|
|
68
|
+
action: /* @__PURE__ */ p("button", {
|
|
69
|
+
type: "button",
|
|
70
|
+
onClick: () => _("/fixtures/new"),
|
|
71
|
+
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",
|
|
72
|
+
children: "Schedule fixture"
|
|
73
|
+
})
|
|
74
|
+
}) : /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", {
|
|
75
|
+
className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",
|
|
76
|
+
children: C.map((e) => /* @__PURE__ */ p(n, {
|
|
77
|
+
fixture: e,
|
|
78
|
+
onClick: () => _(`/fixtures/${e.id}`)
|
|
79
|
+
}, e.id))
|
|
80
|
+
}), /* @__PURE__ */ p(c, {
|
|
81
|
+
className: "mt-6",
|
|
82
|
+
page: b,
|
|
83
|
+
hasMore: w,
|
|
84
|
+
onPrev: () => x((e) => Math.max(0, e - 1)),
|
|
85
|
+
onNext: () => x((e) => e + 1)
|
|
86
|
+
})] })]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { _ as FixturesListPage };
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=FixturesListPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixturesListPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/fixtures/FixturesListPage.tsx"],"sourcesContent":["/**\n * Fixtures List\n * @module atheletebridge/pages/fixtures\n */\n\nimport { useState } from 'react';\nimport { CalendarDays, Plus } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { FixtureCard } from '../../components/FixtureCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FilterSelect } from '../../components/FilterSelect';\nimport { CursorPager } from '../../components/CursorPager';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useFixtures } from '../../hooks/useAthleteBridgeApi';\nimport type { AthFixtureStatus } from '../../types';\n\nconst PAGE_SIZE = 12;\n\nconst STATUS_OPTS: ReadonlyArray<{ value: AthFixtureStatus; label: string }> = [\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'LIVE', label: 'Live' },\n { value: 'COMPLETED', label: 'Completed' },\n { value: 'POSTPONED', label: 'Postponed' },\n { value: 'CANCELLED', label: 'Cancelled' },\n];\n\nexport function FixturesListPage() {\n const { navigateTo } = useAthleteBridge();\n const [status, setStatus] = useState<AthFixtureStatus | ''>('');\n const [page, setPage] = useState(0);\n\n const fixtures = useFixtures({\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset: page * PAGE_SIZE },\n });\n\n const items = fixtures.data?.items ?? [];\n const hasMore = fixtures.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Fixtures\"\n description=\"Matches across friendlies, league games, cups, tournaments and scrimmages.\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures/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\" /> Schedule fixture\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\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 {fixtures.isLoading ? (\n <LoadingState label=\"Loading fixtures…\" />\n ) : fixtures.isError ? (\n <ErrorState onRetry={() => void fixtures.refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<CalendarDays className=\"h-10 w-10\" />}\n title=\"No fixtures found\"\n description={\n status\n ? 'Try clearing your filter to see all fixtures.'\n : 'Schedule a match to start tracking results and standings.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures/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 Schedule fixture\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((fixture) => (\n <FixtureCard\n key={fixture.id}\n fixture={fixture}\n onClick={() => navigateTo(`/fixtures/${fixture.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":";;;;;;;;;;;;AAiBA,IAAM,IAAY,IAEZ,IAAyE;CAC7E;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAa,OAAO;EAAa;CAC3C;AAED,SAAgB,IAAmB;CACjC,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAQ,KAAa,EAAgC,GAAG,EACzD,CAAC,GAAM,KAAW,EAAS,EAAE,EAE7B,IAAW,EAAY;EAC3B,QAAQ,KAAU,KAAA;EAClB,YAAY;GAAE,OAAO;GAAW,QAAQ,IAAO;GAAW;EAC3D,CAAC,EAEI,IAAQ,EAAS,MAAM,SAAS,EAAE,EAClC,IAAU,EAAS,MAAM,SAAS,WAAW;AAEnD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,gBAAgB;GAC1C,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,oBACrB;;YAVb,CAaE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IACE,WAAU;IACV,UAAS;IACT,OAAO;IACP,WAAW,MAAM;AAEf,KADA,EAAU,EAAE,EACZ,EAAQ,EAAE;;IAEZ,SAAS;IACT,CAAA;GACE,CAAA,EAEL,EAAS,YACR,kBAAC,GAAD,EAAc,OAAM,qBAAsB,CAAA,GACxC,EAAS,UACX,kBAAC,GAAD,EAAY,eAAe,KAAK,EAAS,SAAS,EAAI,CAAA,GACpD,EAAM,WAAW,IACnB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAc,WAAU,aAAc,CAAA;GAC5C,OAAM;GACN,aACE,IACI,kDACA;GAEN,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,gBAAgB;IAC1C,WAAU;cACX;IAEQ,CAAA;GAEX,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,GAAD;IAEW;IACT,eAAe,EAAW,aAAa,EAAQ,KAAK;IACpD,EAHK,EAAQ,GAGb,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"}
|