@burdenoff/microfe-technospam 2026.704.1 → 2026.705.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/technospam/api/technospamApi.js +232 -150
- package/dist/technospam/api/technospamApi.js.map +1 -1
- package/dist/technospam/components/LoadMore.js +18 -2
- package/dist/technospam/components/LoadMore.js.map +1 -0
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js +664 -334
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js +79 -72
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +140 -87
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js +75 -68
- package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesMyLearningPagePage.js +3 -0
- package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js +76 -53
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +36 -35
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js +112 -103
- package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.js +219 -110
- package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,189 +6,298 @@ import { StatusBadge as o } from "../components/StatusBadge.js";
|
|
|
6
6
|
import { EmptyView as s, ErrorView as c, LoadingRows as l } from "../components/StateViews.js";
|
|
7
7
|
import "../components/index.js";
|
|
8
8
|
import { notify as u } from "../lib/toast.js";
|
|
9
|
-
import { useCancelSession as d,
|
|
10
|
-
import { useState as
|
|
11
|
-
import { CalendarClock as
|
|
12
|
-
import { jsx as
|
|
13
|
-
import { Button as
|
|
9
|
+
import { useCancelSession as d, useCompleteSession as f, useConfirmSession as p, useMentorsQuery as m, useSessionsQuery as h } from "../api/technospamApi.js";
|
|
10
|
+
import { useState as g } from "react";
|
|
11
|
+
import { CalendarClock as _, Check as v, CheckCircle2 as y, Clock as b, MessageSquare as x, Users as S, Video as C, X as w } from "lucide-react";
|
|
12
|
+
import { jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
13
|
+
import { Button as D, GlassCard as O, Input as k, Tabs as A, TabsList as j, TabsTrigger as M } from "@burdenoff/fe-libs/ui";
|
|
14
14
|
//#region src/technospam/pages/MentorshipSessionsPagePage.tsx
|
|
15
|
-
var
|
|
16
|
-
function
|
|
17
|
-
let
|
|
18
|
-
return /* @__PURE__ */
|
|
19
|
-
className: "flex flex-col gap-3 p-4
|
|
20
|
-
children: [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
var N = new Set(["REQUESTED", "CONFIRMED"]);
|
|
16
|
+
function P({ session: e, showMentor: t, isMentor: n, onCancel: r, onConfirm: s, onComplete: c, busy: l }) {
|
|
17
|
+
let u = N.has(e.status), [d, f] = g("none"), [p, m] = g(""), [h, x] = g("5"), [S, A] = g("");
|
|
18
|
+
return /* @__PURE__ */ E(O, {
|
|
19
|
+
className: "flex flex-col gap-3 p-4",
|
|
20
|
+
children: [
|
|
21
|
+
/* @__PURE__ */ E("div", {
|
|
22
|
+
className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
|
|
23
|
+
children: [/* @__PURE__ */ E("div", {
|
|
24
|
+
className: "flex items-start gap-3",
|
|
25
|
+
children: [/* @__PURE__ */ T("span", {
|
|
26
|
+
className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-accent-wash text-accent-primary",
|
|
27
|
+
children: /* @__PURE__ */ T(C, { size: 18 })
|
|
28
|
+
}), /* @__PURE__ */ E("div", {
|
|
29
|
+
className: "min-w-0",
|
|
30
|
+
children: [
|
|
31
|
+
/* @__PURE__ */ E("div", {
|
|
32
|
+
className: "flex flex-wrap items-center gap-2",
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ T("span", {
|
|
35
|
+
className: "truncate text-sm font-semibold text-text-primary",
|
|
36
|
+
children: e.topic
|
|
37
|
+
}),
|
|
38
|
+
/* @__PURE__ */ T(o, { status: e.status }),
|
|
39
|
+
e.rating ? /* @__PURE__ */ E("span", {
|
|
40
|
+
className: "text-xs text-text-muted",
|
|
41
|
+
children: [
|
|
42
|
+
"★ ",
|
|
43
|
+
e.rating,
|
|
44
|
+
"/5"
|
|
45
|
+
]
|
|
46
|
+
}) : null
|
|
47
|
+
]
|
|
48
|
+
}),
|
|
49
|
+
t && e.mentor?.headline ? /* @__PURE__ */ E("div", {
|
|
50
|
+
className: "mt-0.5 truncate text-xs text-text-secondary",
|
|
51
|
+
children: ["with ", e.mentor.headline]
|
|
52
|
+
}) : null,
|
|
53
|
+
/* @__PURE__ */ E("div", {
|
|
54
|
+
className: "mt-1 flex flex-wrap items-center gap-3 text-xs text-text-muted",
|
|
55
|
+
children: [/* @__PURE__ */ E("span", {
|
|
56
|
+
className: "inline-flex items-center gap-1",
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ T(_, { size: 13 }),
|
|
59
|
+
" ",
|
|
60
|
+
i(e.scheduledAt)
|
|
61
|
+
]
|
|
62
|
+
}), /* @__PURE__ */ E("span", {
|
|
63
|
+
className: "inline-flex items-center gap-1",
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ T(b, { size: 13 }),
|
|
66
|
+
" ",
|
|
67
|
+
a(e.durationMinutes)
|
|
68
|
+
]
|
|
69
|
+
})]
|
|
70
|
+
}),
|
|
71
|
+
e.agenda ? /* @__PURE__ */ T("p", {
|
|
72
|
+
className: "mt-1 line-clamp-2 text-xs text-text-secondary",
|
|
73
|
+
children: e.agenda
|
|
74
|
+
}) : null
|
|
75
|
+
]
|
|
76
|
+
})]
|
|
77
|
+
}), /* @__PURE__ */ E("div", {
|
|
78
|
+
className: "flex shrink-0 flex-wrap items-center gap-2",
|
|
79
|
+
children: [
|
|
80
|
+
e.meetingUrl ? /* @__PURE__ */ E(D, {
|
|
81
|
+
variant: "outline",
|
|
82
|
+
size: "sm",
|
|
83
|
+
onClick: () => window.open(e.meetingUrl ?? "", "_blank", "noopener,noreferrer"),
|
|
84
|
+
children: [/* @__PURE__ */ T(C, { size: 15 }), " Join"]
|
|
85
|
+
}) : null,
|
|
86
|
+
n && e.status === "REQUESTED" ? /* @__PURE__ */ E(D, {
|
|
87
|
+
variant: "outline",
|
|
88
|
+
size: "sm",
|
|
89
|
+
onClick: () => f(d === "confirm" ? "none" : "confirm"),
|
|
90
|
+
children: [/* @__PURE__ */ T(v, { size: 15 }), " Confirm"]
|
|
91
|
+
}) : null,
|
|
92
|
+
n && e.status === "CONFIRMED" ? /* @__PURE__ */ E(D, {
|
|
93
|
+
variant: "outline",
|
|
94
|
+
size: "sm",
|
|
95
|
+
onClick: () => f(d === "complete" ? "none" : "complete"),
|
|
96
|
+
children: [/* @__PURE__ */ T(y, { size: 15 }), " Mark complete"]
|
|
97
|
+
}) : null,
|
|
98
|
+
u ? /* @__PURE__ */ E(D, {
|
|
99
|
+
variant: "ghost",
|
|
100
|
+
size: "sm",
|
|
101
|
+
onClick: () => r(e.id),
|
|
102
|
+
disabled: l,
|
|
103
|
+
children: [/* @__PURE__ */ T(w, { size: 15 }), " Cancel"]
|
|
104
|
+
}) : null
|
|
105
|
+
]
|
|
106
|
+
})]
|
|
107
|
+
}),
|
|
108
|
+
d === "confirm" ? /* @__PURE__ */ E("div", {
|
|
109
|
+
className: "flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3 sm:flex-row sm:items-center",
|
|
110
|
+
children: [/* @__PURE__ */ T(k, {
|
|
111
|
+
className: "flex-1",
|
|
112
|
+
placeholder: "Meeting link (e.g. https://meet.…)",
|
|
113
|
+
value: p,
|
|
114
|
+
onChange: (e) => m(e.target.value)
|
|
115
|
+
}), /* @__PURE__ */ T(D, {
|
|
116
|
+
size: "sm",
|
|
117
|
+
onClick: async () => {
|
|
118
|
+
await s(e.id, p.trim()), f("none"), m("");
|
|
119
|
+
},
|
|
120
|
+
disabled: l,
|
|
121
|
+
children: "Confirm session"
|
|
122
|
+
})]
|
|
123
|
+
}) : null,
|
|
124
|
+
d === "complete" ? /* @__PURE__ */ E("div", {
|
|
125
|
+
className: "flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3",
|
|
27
126
|
children: [
|
|
28
|
-
/* @__PURE__ */
|
|
29
|
-
className: "flex
|
|
30
|
-
children: [/* @__PURE__ */
|
|
31
|
-
className: "
|
|
32
|
-
children:
|
|
33
|
-
}), /* @__PURE__ */
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
className: "mt-1 flex flex-wrap items-center gap-3 text-xs text-text-muted",
|
|
41
|
-
children: [/* @__PURE__ */ S("span", {
|
|
42
|
-
className: "inline-flex items-center gap-1",
|
|
43
|
-
children: [
|
|
44
|
-
/* @__PURE__ */ x(h, { size: 13 }),
|
|
45
|
-
" ",
|
|
46
|
-
i(e.scheduledAt)
|
|
47
|
-
]
|
|
48
|
-
}), /* @__PURE__ */ S("span", {
|
|
49
|
-
className: "inline-flex items-center gap-1",
|
|
50
|
-
children: [
|
|
51
|
-
/* @__PURE__ */ x(g, { size: 13 }),
|
|
52
|
-
" ",
|
|
53
|
-
a(e.durationMinutes)
|
|
54
|
-
]
|
|
127
|
+
/* @__PURE__ */ E("div", {
|
|
128
|
+
className: "flex items-center gap-2",
|
|
129
|
+
children: [/* @__PURE__ */ T("label", {
|
|
130
|
+
className: "text-xs text-text-secondary",
|
|
131
|
+
children: "Rating (1–5)"
|
|
132
|
+
}), /* @__PURE__ */ T(k, {
|
|
133
|
+
type: "number",
|
|
134
|
+
min: 1,
|
|
135
|
+
max: 5,
|
|
136
|
+
className: "w-20",
|
|
137
|
+
value: h,
|
|
138
|
+
onChange: (e) => x(e.target.value)
|
|
55
139
|
})]
|
|
56
140
|
}),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
141
|
+
/* @__PURE__ */ T(k, {
|
|
142
|
+
placeholder: "Feedback for the mentee (optional)",
|
|
143
|
+
value: S,
|
|
144
|
+
onChange: (e) => A(e.target.value)
|
|
145
|
+
}),
|
|
146
|
+
/* @__PURE__ */ T("div", { children: /* @__PURE__ */ T(D, {
|
|
147
|
+
size: "sm",
|
|
148
|
+
onClick: async () => {
|
|
149
|
+
await c(e.id, Math.min(5, Math.max(1, Number(h) || 5)), S.trim()), f("none");
|
|
150
|
+
},
|
|
151
|
+
disabled: l,
|
|
152
|
+
children: "Complete session"
|
|
153
|
+
}) })
|
|
61
154
|
]
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
className: "flex shrink-0 items-center gap-2",
|
|
65
|
-
children: [e.meetingUrl ? /* @__PURE__ */ S(C, {
|
|
66
|
-
variant: "outline",
|
|
67
|
-
size: "sm",
|
|
68
|
-
onClick: () => window.open(e.meetingUrl ?? "", "_blank", "noopener,noreferrer"),
|
|
69
|
-
children: [/* @__PURE__ */ x(y, { size: 15 }), " Join"]
|
|
70
|
-
}) : null, s ? /* @__PURE__ */ S(C, {
|
|
71
|
-
variant: "ghost",
|
|
72
|
-
size: "sm",
|
|
73
|
-
onClick: () => n(e.id),
|
|
74
|
-
disabled: r,
|
|
75
|
-
children: [/* @__PURE__ */ x(b, { size: 15 }), " Cancel"]
|
|
76
|
-
}) : null]
|
|
77
|
-
})]
|
|
155
|
+
}) : null
|
|
156
|
+
]
|
|
78
157
|
});
|
|
79
158
|
}
|
|
80
|
-
function
|
|
81
|
-
return e && n.length === 0 ? /* @__PURE__ */
|
|
159
|
+
function F({ loading: e, error: t, sessions: n, showMentor: r, emptyTitle: i, emptyDescription: a, emptyAction: o, isMentor: u, onCancel: d, onConfirm: f, onComplete: p, busyId: m }) {
|
|
160
|
+
return e && n.length === 0 ? /* @__PURE__ */ T(l, {
|
|
82
161
|
count: 3,
|
|
83
162
|
height: "h-24"
|
|
84
|
-
}) : t ? /* @__PURE__ */
|
|
163
|
+
}) : t ? /* @__PURE__ */ T(c, {
|
|
85
164
|
title: "Couldn't load sessions",
|
|
86
165
|
error: t
|
|
87
|
-
}) : n.length === 0 ? /* @__PURE__ */
|
|
88
|
-
icon: /* @__PURE__ */ x
|
|
166
|
+
}) : n.length === 0 ? /* @__PURE__ */ T(s, {
|
|
167
|
+
icon: /* @__PURE__ */ T(x, { size: 26 }),
|
|
89
168
|
title: i,
|
|
90
169
|
description: a,
|
|
91
170
|
action: o
|
|
92
|
-
}) : /* @__PURE__ */
|
|
171
|
+
}) : /* @__PURE__ */ T("div", {
|
|
93
172
|
className: "space-y-3",
|
|
94
|
-
children: [...n].sort((e, t) => new Date(t.scheduledAt).getTime() - new Date(e.scheduledAt).getTime()).map((e) => /* @__PURE__ */
|
|
173
|
+
children: [...n].sort((e, t) => new Date(t.scheduledAt).getTime() - new Date(e.scheduledAt).getTime()).map((e) => /* @__PURE__ */ T(P, {
|
|
95
174
|
session: e,
|
|
96
175
|
showMentor: r,
|
|
97
|
-
|
|
98
|
-
|
|
176
|
+
isMentor: u,
|
|
177
|
+
onCancel: d,
|
|
178
|
+
onConfirm: f,
|
|
179
|
+
onComplete: p,
|
|
180
|
+
busy: m === e.id
|
|
99
181
|
}, e.id))
|
|
100
182
|
});
|
|
101
183
|
}
|
|
102
|
-
function
|
|
103
|
-
let i = t(), { currentUser: a } = e(), [o, c] =
|
|
104
|
-
|
|
184
|
+
function I() {
|
|
185
|
+
let i = t(), { currentUser: a } = e(), [o, c] = g("mentee"), [_, v] = g(null), y = a?.id, b = h(y ? { menteeId: y } : {}), C = m({}), w = C.data?.tecListMentors.items.find((e) => e.userId === a?.id), O = w?.id, k = h(O ? { mentorId: O } : {}), [N] = d(), [P] = p(), [I] = f(), L = y ? b.data?.tecListSessions ?? [] : [], R = O ? k.data?.tecListSessions ?? [] : [], z = async (e) => {
|
|
186
|
+
v(e);
|
|
187
|
+
try {
|
|
188
|
+
(await N({ variables: { id: e } })).data?.tecCancelSession && u.success("Session cancelled", "The session has been cancelled.");
|
|
189
|
+
} finally {
|
|
190
|
+
v(null);
|
|
191
|
+
}
|
|
192
|
+
}, B = async (e, t) => {
|
|
193
|
+
v(e);
|
|
194
|
+
try {
|
|
195
|
+
(await P({ variables: {
|
|
196
|
+
id: e,
|
|
197
|
+
meetingUrl: t || void 0
|
|
198
|
+
} })).data?.tecConfirmSession && (u.success("Session confirmed", "The mentee has been notified."), await k.refetch());
|
|
199
|
+
} finally {
|
|
200
|
+
v(null);
|
|
201
|
+
}
|
|
202
|
+
}, V = async (e, t, n) => {
|
|
203
|
+
v(e);
|
|
105
204
|
try {
|
|
106
|
-
(await
|
|
205
|
+
(await I({ variables: {
|
|
206
|
+
id: e,
|
|
207
|
+
rating: t,
|
|
208
|
+
feedback: n || void 0
|
|
209
|
+
} })).data?.tecCompleteSession && (u.success("Session completed", "Nice work — the session is wrapped up."), await k.refetch());
|
|
107
210
|
} finally {
|
|
108
|
-
|
|
211
|
+
v(null);
|
|
109
212
|
}
|
|
110
213
|
};
|
|
111
|
-
return a?.id ? /* @__PURE__ */
|
|
214
|
+
return a?.id ? /* @__PURE__ */ E(n, {
|
|
112
215
|
hero: !0,
|
|
113
216
|
title: "My Sessions",
|
|
114
217
|
description: "Manage the mentorship sessions you've booked and the ones you host.",
|
|
115
|
-
actions: /* @__PURE__ */
|
|
218
|
+
actions: /* @__PURE__ */ E(D, {
|
|
116
219
|
variant: "outline",
|
|
117
220
|
onClick: () => i("/mentorship/mentors-page"),
|
|
118
|
-
children: [/* @__PURE__ */
|
|
221
|
+
children: [/* @__PURE__ */ T(S, { size: 16 }), " Find a mentor"]
|
|
119
222
|
}),
|
|
120
223
|
children: [
|
|
121
|
-
/* @__PURE__ */
|
|
224
|
+
/* @__PURE__ */ E("div", {
|
|
122
225
|
className: "mb-5 grid grid-cols-2 gap-3 sm:max-w-md",
|
|
123
|
-
children: [/* @__PURE__ */
|
|
226
|
+
children: [/* @__PURE__ */ T(r, {
|
|
124
227
|
label: "As mentee",
|
|
125
|
-
value:
|
|
126
|
-
icon:
|
|
127
|
-
}), /* @__PURE__ */
|
|
228
|
+
value: L.length,
|
|
229
|
+
icon: x
|
|
230
|
+
}), /* @__PURE__ */ T(r, {
|
|
128
231
|
label: "As mentor",
|
|
129
|
-
value:
|
|
130
|
-
icon:
|
|
232
|
+
value: O ? R.length : 0,
|
|
233
|
+
icon: S
|
|
131
234
|
})]
|
|
132
235
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
236
|
+
/* @__PURE__ */ T(A, {
|
|
134
237
|
value: o,
|
|
135
238
|
onValueChange: (e) => c(e),
|
|
136
239
|
className: "mb-4",
|
|
137
|
-
children: /* @__PURE__ */
|
|
240
|
+
children: /* @__PURE__ */ E(j, { children: [/* @__PURE__ */ T(M, {
|
|
138
241
|
value: "mentee",
|
|
139
242
|
children: "As mentee"
|
|
140
|
-
}), /* @__PURE__ */
|
|
243
|
+
}), /* @__PURE__ */ T(M, {
|
|
141
244
|
value: "mentor",
|
|
142
245
|
children: "As mentor"
|
|
143
246
|
})] })
|
|
144
247
|
}),
|
|
145
|
-
o === "mentee" ? /* @__PURE__ */
|
|
248
|
+
o === "mentee" ? /* @__PURE__ */ T(F, {
|
|
146
249
|
loading: b.loading,
|
|
147
250
|
error: b.error,
|
|
148
|
-
sessions:
|
|
251
|
+
sessions: L,
|
|
149
252
|
showMentor: !0,
|
|
150
253
|
emptyTitle: "No sessions booked yet",
|
|
151
254
|
emptyDescription: "Find a mentor and request a session to get personalized guidance.",
|
|
152
|
-
emptyAction: /* @__PURE__ */
|
|
255
|
+
emptyAction: /* @__PURE__ */ T(D, {
|
|
153
256
|
onClick: () => i("/mentorship/mentors-page"),
|
|
154
257
|
children: "Find a mentor"
|
|
155
258
|
}),
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
259
|
+
isMentor: !1,
|
|
260
|
+
onCancel: z,
|
|
261
|
+
onConfirm: B,
|
|
262
|
+
onComplete: V,
|
|
263
|
+
busyId: _
|
|
264
|
+
}) : C.loading && !w ? /* @__PURE__ */ T(l, {
|
|
159
265
|
count: 3,
|
|
160
266
|
height: "h-24"
|
|
161
|
-
}) :
|
|
162
|
-
loading:
|
|
163
|
-
error:
|
|
164
|
-
sessions:
|
|
267
|
+
}) : O ? /* @__PURE__ */ T(F, {
|
|
268
|
+
loading: k.loading,
|
|
269
|
+
error: k.error,
|
|
270
|
+
sessions: R,
|
|
165
271
|
showMentor: !1,
|
|
166
272
|
emptyTitle: "No sessions to host yet",
|
|
167
273
|
emptyDescription: "When mentees request time with you, their sessions will show up here.",
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
274
|
+
isMentor: !0,
|
|
275
|
+
onCancel: z,
|
|
276
|
+
onConfirm: B,
|
|
277
|
+
onComplete: V,
|
|
278
|
+
busyId: _
|
|
279
|
+
}) : /* @__PURE__ */ T(s, {
|
|
280
|
+
icon: /* @__PURE__ */ T(S, { size: 26 }),
|
|
172
281
|
title: "You're not a mentor yet",
|
|
173
282
|
description: "Create a mentor profile to start hosting sessions and helping others build.",
|
|
174
|
-
action: /* @__PURE__ */
|
|
283
|
+
action: /* @__PURE__ */ T(D, {
|
|
175
284
|
onClick: () => i("/mentorship/mentors-page"),
|
|
176
285
|
children: "Become a mentor"
|
|
177
286
|
})
|
|
178
287
|
})
|
|
179
288
|
]
|
|
180
|
-
}) : /* @__PURE__ */
|
|
289
|
+
}) : /* @__PURE__ */ T(n, {
|
|
181
290
|
hero: !0,
|
|
182
291
|
title: "My Sessions",
|
|
183
292
|
description: "Track your mentorship sessions.",
|
|
184
|
-
children: /* @__PURE__ */
|
|
185
|
-
icon: /* @__PURE__ */ x
|
|
293
|
+
children: /* @__PURE__ */ T(s, {
|
|
294
|
+
icon: /* @__PURE__ */ T(x, { size: 26 }),
|
|
186
295
|
title: "Sign in to view your sessions",
|
|
187
296
|
description: "Your booked and hosted mentorship sessions will appear here once you're signed in."
|
|
188
297
|
})
|
|
189
298
|
});
|
|
190
299
|
}
|
|
191
300
|
//#endregion
|
|
192
|
-
export {
|
|
301
|
+
export { I as MentorshipSessionsPagePage };
|
|
193
302
|
|
|
194
303
|
//# sourceMappingURL=MentorshipSessionsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MentorshipSessionsPagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipSessionsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { CalendarClock, Clock, MessageSquare, Users, Video, X } from 'lucide-react';\nimport { Button, GlassCard, Tabs, TabsList, TabsTrigger } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingRows,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n useCancelSession,\n useMentorsQuery,\n useSessionsQuery,\n type TecMentorSession,\n} from '../api/technospamApi';\nimport { formatDateTime, formatDuration } from '../utils/format';\nimport { notify } from '../lib/toast';\n\ntype Perspective = 'mentee' | 'mentor';\n\nconst CANCELLABLE = new Set(['REQUESTED', 'CONFIRMED']);\n\nfunction SessionRow({\n session,\n showMentor,\n onCancel,\n cancelling,\n}: {\n session: TecMentorSession;\n showMentor: boolean;\n onCancel: (id: string) => void;\n cancelling: boolean;\n}) {\n const canCancel = CANCELLABLE.has(session.status);\n return (\n <GlassCard className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-start gap-3\">\n <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-accent-wash text-accent-primary\">\n <Video size={18} />\n </span>\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {session.topic}\n </span>\n <StatusBadge status={session.status} />\n </div>\n {showMentor && session.mentor?.headline ? (\n <div className=\"mt-0.5 truncate text-xs text-text-secondary\">\n with {session.mentor.headline}\n </div>\n ) : null}\n <div className=\"mt-1 flex flex-wrap items-center gap-3 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <CalendarClock size={13} /> {formatDateTime(session.scheduledAt)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={13} /> {formatDuration(session.durationMinutes)}\n </span>\n </div>\n {session.agenda ? (\n <p className=\"mt-1 line-clamp-2 text-xs text-text-secondary\">{session.agenda}</p>\n ) : null}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {session.meetingUrl ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => window.open(session.meetingUrl ?? '', '_blank', 'noopener,noreferrer')}\n >\n <Video size={15} /> Join\n </Button>\n ) : null}\n {canCancel ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => onCancel(session.id)}\n disabled={cancelling}\n >\n <X size={15} /> Cancel\n </Button>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nfunction SessionsList({\n loading,\n error,\n sessions,\n showMentor,\n emptyTitle,\n emptyDescription,\n emptyAction,\n onCancel,\n cancellingId,\n}: {\n loading: boolean;\n error?: { message?: string };\n sessions: TecMentorSession[];\n showMentor: boolean;\n emptyTitle: string;\n emptyDescription: string;\n emptyAction?: React.ReactNode;\n onCancel: (id: string) => void;\n cancellingId: string | null;\n}) {\n if (loading && sessions.length === 0) return <LoadingRows count={3} height=\"h-24\" />;\n if (error) return <ErrorView title=\"Couldn't load sessions\" error={error} />;\n if (sessions.length === 0) {\n return (\n <EmptyView\n icon={<MessageSquare size={26} />}\n title={emptyTitle}\n description={emptyDescription}\n action={emptyAction}\n />\n );\n }\n const sorted = [...sessions].sort(\n (a, b) => new Date(b.scheduledAt).getTime() - new Date(a.scheduledAt).getTime()\n );\n return (\n <div className=\"space-y-3\">\n {sorted.map((session) => (\n <SessionRow\n key={session.id}\n session={session}\n showMentor={showMentor}\n onCancel={onCancel}\n cancelling={cancellingId === session.id}\n />\n ))}\n </div>\n );\n}\n\nexport function MentorshipSessionsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser } = useTechnoSpam();\n const [tab, setTab] = useState<Perspective>('mentee');\n const [cancellingId, setCancellingId] = useState<string | null>(null);\n\n const menteeId = currentUser?.id;\n\n // As mentee: sessions the current user booked.\n const menteeQ = useSessionsQuery(menteeId ? { menteeId } : {});\n\n // Resolve whether the current user is a mentor, to load their mentor sessions.\n const mentorsQ = useMentorsQuery({});\n const myMentor = mentorsQ.data?.tecListMentors.items.find((m) => m.userId === currentUser?.id);\n const mentorId = myMentor?.id;\n const mentorQ = useSessionsQuery(mentorId ? { mentorId } : {});\n\n const [cancelSession] = useCancelSession();\n\n const menteeSessions = menteeId ? (menteeQ.data?.tecListSessions ?? []) : [];\n const mentorSessions = mentorId ? (mentorQ.data?.tecListSessions ?? []) : [];\n\n const handleCancel = async (id: string) => {\n setCancellingId(id);\n try {\n const res = await cancelSession({ variables: { id } });\n if (res.data?.tecCancelSession) {\n notify.success('Session cancelled', 'The session has been cancelled.');\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n if (!currentUser?.id) {\n return (\n <PageLayout hero title=\"My Sessions\" description=\"Track your mentorship sessions.\">\n <EmptyView\n icon={<MessageSquare size={26} />}\n title=\"Sign in to view your sessions\"\n description=\"Your booked and hosted mentorship sessions will appear here once you're signed in.\"\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n hero\n title=\"My Sessions\"\n description=\"Manage the mentorship sessions you've booked and the ones you host.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/mentors-page')}>\n <Users size={16} /> Find a mentor\n </Button>\n }\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:max-w-md\">\n <StatCard label=\"As mentee\" value={menteeSessions.length} icon={MessageSquare} />\n <StatCard label=\"As mentor\" value={mentorId ? mentorSessions.length : 0} icon={Users} />\n </div>\n\n <Tabs value={tab} onValueChange={(v) => setTab(v as Perspective)} className=\"mb-4\">\n <TabsList>\n <TabsTrigger value=\"mentee\">As mentee</TabsTrigger>\n <TabsTrigger value=\"mentor\">As mentor</TabsTrigger>\n </TabsList>\n </Tabs>\n\n {tab === 'mentee' ? (\n <SessionsList\n loading={menteeQ.loading}\n error={menteeQ.error}\n sessions={menteeSessions}\n showMentor\n emptyTitle=\"No sessions booked yet\"\n emptyDescription=\"Find a mentor and request a session to get personalized guidance.\"\n emptyAction={\n <Button onClick={() => navigate('/mentorship/mentors-page')}>Find a mentor</Button>\n }\n onCancel={handleCancel}\n cancellingId={cancellingId}\n />\n ) : mentorsQ.loading && !myMentor ? (\n <LoadingRows count={3} height=\"h-24\" />\n ) : !mentorId ? (\n <EmptyView\n icon={<Users size={26} />}\n title=\"You're not a mentor yet\"\n description=\"Create a mentor profile to start hosting sessions and helping others build.\"\n action={\n <Button onClick={() => navigate('/mentorship/mentors-page')}>Become a mentor</Button>\n }\n />\n ) : (\n <SessionsList\n loading={mentorQ.loading}\n error={mentorQ.error}\n sessions={mentorSessions}\n showMentor={false}\n emptyTitle=\"No sessions to host yet\"\n emptyDescription=\"When mentees request time with you, their sessions will show up here.\"\n onCancel={handleCancel}\n cancellingId={cancellingId}\n />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MentorshipSessionsPagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipSessionsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n CalendarClock,\n Check,\n CheckCircle2,\n Clock,\n MessageSquare,\n Users,\n Video,\n X,\n} from 'lucide-react';\nimport { Button, GlassCard, Input, Tabs, TabsList, TabsTrigger } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingRows,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n useCancelSession,\n useCompleteSession,\n useConfirmSession,\n useMentorsQuery,\n useSessionsQuery,\n type TecMentorSession,\n} from '../api/technospamApi';\nimport { formatDateTime, formatDuration } from '../utils/format';\nimport { notify } from '../lib/toast';\n\ntype Perspective = 'mentee' | 'mentor';\n\nconst CANCELLABLE = new Set(['REQUESTED', 'CONFIRMED']);\n\nfunction SessionRow({\n session,\n showMentor,\n isMentor,\n onCancel,\n onConfirm,\n onComplete,\n busy,\n}: {\n session: TecMentorSession;\n showMentor: boolean;\n isMentor: boolean;\n onCancel: (id: string) => void;\n onConfirm: (id: string, meetingUrl: string) => Promise<void>;\n onComplete: (id: string, rating: number, feedback: string) => Promise<void>;\n busy: boolean;\n}) {\n const canCancel = CANCELLABLE.has(session.status);\n const [mode, setMode] = useState<'none' | 'confirm' | 'complete'>('none');\n const [meetingUrl, setMeetingUrl] = useState('');\n const [rating, setRating] = useState('5');\n const [feedback, setFeedback] = useState('');\n\n const submitConfirm = async () => {\n await onConfirm(session.id, meetingUrl.trim());\n setMode('none');\n setMeetingUrl('');\n };\n const submitComplete = async () => {\n await onComplete(session.id, Math.min(5, Math.max(1, Number(rating) || 5)), feedback.trim());\n setMode('none');\n };\n\n return (\n <GlassCard className=\"flex flex-col gap-3 p-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-start gap-3\">\n <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-accent-wash text-accent-primary\">\n <Video size={18} />\n </span>\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {session.topic}\n </span>\n <StatusBadge status={session.status} />\n {session.rating ? (\n <span className=\"text-xs text-text-muted\">★ {session.rating}/5</span>\n ) : null}\n </div>\n {showMentor && session.mentor?.headline ? (\n <div className=\"mt-0.5 truncate text-xs text-text-secondary\">\n with {session.mentor.headline}\n </div>\n ) : null}\n <div className=\"mt-1 flex flex-wrap items-center gap-3 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <CalendarClock size={13} /> {formatDateTime(session.scheduledAt)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={13} /> {formatDuration(session.durationMinutes)}\n </span>\n </div>\n {session.agenda ? (\n <p className=\"mt-1 line-clamp-2 text-xs text-text-secondary\">{session.agenda}</p>\n ) : null}\n </div>\n </div>\n <div className=\"flex shrink-0 flex-wrap items-center gap-2\">\n {session.meetingUrl ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => window.open(session.meetingUrl ?? '', '_blank', 'noopener,noreferrer')}\n >\n <Video size={15} /> Join\n </Button>\n ) : null}\n {isMentor && session.status === 'REQUESTED' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setMode(mode === 'confirm' ? 'none' : 'confirm')}\n >\n <Check size={15} /> Confirm\n </Button>\n ) : null}\n {isMentor && session.status === 'CONFIRMED' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setMode(mode === 'complete' ? 'none' : 'complete')}\n >\n <CheckCircle2 size={15} /> Mark complete\n </Button>\n ) : null}\n {canCancel ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => onCancel(session.id)} disabled={busy}>\n <X size={15} /> Cancel\n </Button>\n ) : null}\n </div>\n </div>\n\n {mode === 'confirm' ? (\n <div className=\"flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3 sm:flex-row sm:items-center\">\n <Input\n className=\"flex-1\"\n placeholder=\"Meeting link (e.g. https://meet.…)\"\n value={meetingUrl}\n onChange={(e) => setMeetingUrl(e.target.value)}\n />\n <Button size=\"sm\" onClick={submitConfirm} disabled={busy}>\n Confirm session\n </Button>\n </div>\n ) : null}\n {mode === 'complete' ? (\n <div className=\"flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs text-text-secondary\">Rating (1–5)</label>\n <Input\n type=\"number\"\n min={1}\n max={5}\n className=\"w-20\"\n value={rating}\n onChange={(e) => setRating(e.target.value)}\n />\n </div>\n <Input\n placeholder=\"Feedback for the mentee (optional)\"\n value={feedback}\n onChange={(e) => setFeedback(e.target.value)}\n />\n <div>\n <Button size=\"sm\" onClick={submitComplete} disabled={busy}>\n Complete session\n </Button>\n </div>\n </div>\n ) : null}\n </GlassCard>\n );\n}\n\nfunction SessionsList({\n loading,\n error,\n sessions,\n showMentor,\n emptyTitle,\n emptyDescription,\n emptyAction,\n isMentor,\n onCancel,\n onConfirm,\n onComplete,\n busyId,\n}: {\n loading: boolean;\n error?: { message?: string };\n sessions: TecMentorSession[];\n showMentor: boolean;\n emptyTitle: string;\n emptyDescription: string;\n emptyAction?: React.ReactNode;\n isMentor: boolean;\n onCancel: (id: string) => void;\n onConfirm: (id: string, meetingUrl: string) => Promise<void>;\n onComplete: (id: string, rating: number, feedback: string) => Promise<void>;\n busyId: string | null;\n}) {\n if (loading && sessions.length === 0) return <LoadingRows count={3} height=\"h-24\" />;\n if (error) return <ErrorView title=\"Couldn't load sessions\" error={error} />;\n if (sessions.length === 0) {\n return (\n <EmptyView\n icon={<MessageSquare size={26} />}\n title={emptyTitle}\n description={emptyDescription}\n action={emptyAction}\n />\n );\n }\n const sorted = [...sessions].sort(\n (a, b) => new Date(b.scheduledAt).getTime() - new Date(a.scheduledAt).getTime()\n );\n return (\n <div className=\"space-y-3\">\n {sorted.map((session) => (\n <SessionRow\n key={session.id}\n session={session}\n showMentor={showMentor}\n isMentor={isMentor}\n onCancel={onCancel}\n onConfirm={onConfirm}\n onComplete={onComplete}\n busy={busyId === session.id}\n />\n ))}\n </div>\n );\n}\n\nexport function MentorshipSessionsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser } = useTechnoSpam();\n const [tab, setTab] = useState<Perspective>('mentee');\n const [cancellingId, setCancellingId] = useState<string | null>(null);\n\n const menteeId = currentUser?.id;\n\n // As mentee: sessions the current user booked.\n const menteeQ = useSessionsQuery(menteeId ? { menteeId } : {});\n\n // Resolve whether the current user is a mentor, to load their mentor sessions.\n const mentorsQ = useMentorsQuery({});\n const myMentor = mentorsQ.data?.tecListMentors.items.find((m) => m.userId === currentUser?.id);\n const mentorId = myMentor?.id;\n const mentorQ = useSessionsQuery(mentorId ? { mentorId } : {});\n\n const [cancelSession] = useCancelSession();\n const [confirmSession] = useConfirmSession();\n const [completeSession] = useCompleteSession();\n\n const menteeSessions = menteeId ? (menteeQ.data?.tecListSessions ?? []) : [];\n const mentorSessions = mentorId ? (mentorQ.data?.tecListSessions ?? []) : [];\n\n const handleCancel = async (id: string) => {\n setCancellingId(id);\n try {\n const res = await cancelSession({ variables: { id } });\n if (res.data?.tecCancelSession) {\n notify.success('Session cancelled', 'The session has been cancelled.');\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n const handleConfirm = async (id: string, meetingUrl: string) => {\n setCancellingId(id);\n try {\n const res = await confirmSession({\n variables: { id, meetingUrl: meetingUrl || undefined },\n });\n if (res.data?.tecConfirmSession) {\n notify.success('Session confirmed', 'The mentee has been notified.');\n await mentorQ.refetch();\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n const handleComplete = async (id: string, rating: number, feedback: string) => {\n setCancellingId(id);\n try {\n const res = await completeSession({\n variables: { id, rating, feedback: feedback || undefined },\n });\n if (res.data?.tecCompleteSession) {\n notify.success('Session completed', 'Nice work — the session is wrapped up.');\n await mentorQ.refetch();\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n if (!currentUser?.id) {\n return (\n <PageLayout hero title=\"My Sessions\" description=\"Track your mentorship sessions.\">\n <EmptyView\n icon={<MessageSquare size={26} />}\n title=\"Sign in to view your sessions\"\n description=\"Your booked and hosted mentorship sessions will appear here once you're signed in.\"\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n hero\n title=\"My Sessions\"\n description=\"Manage the mentorship sessions you've booked and the ones you host.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/mentors-page')}>\n <Users size={16} /> Find a mentor\n </Button>\n }\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:max-w-md\">\n <StatCard label=\"As mentee\" value={menteeSessions.length} icon={MessageSquare} />\n <StatCard label=\"As mentor\" value={mentorId ? mentorSessions.length : 0} icon={Users} />\n </div>\n\n <Tabs value={tab} onValueChange={(v) => setTab(v as Perspective)} className=\"mb-4\">\n <TabsList>\n <TabsTrigger value=\"mentee\">As mentee</TabsTrigger>\n <TabsTrigger value=\"mentor\">As mentor</TabsTrigger>\n </TabsList>\n </Tabs>\n\n {tab === 'mentee' ? (\n <SessionsList\n loading={menteeQ.loading}\n error={menteeQ.error}\n sessions={menteeSessions}\n showMentor\n emptyTitle=\"No sessions booked yet\"\n emptyDescription=\"Find a mentor and request a session to get personalized guidance.\"\n emptyAction={\n <Button onClick={() => navigate('/mentorship/mentors-page')}>Find a mentor</Button>\n }\n isMentor={false}\n onCancel={handleCancel}\n onConfirm={handleConfirm}\n onComplete={handleComplete}\n busyId={cancellingId}\n />\n ) : mentorsQ.loading && !myMentor ? (\n <LoadingRows count={3} height=\"h-24\" />\n ) : !mentorId ? (\n <EmptyView\n icon={<Users size={26} />}\n title=\"You're not a mentor yet\"\n description=\"Create a mentor profile to start hosting sessions and helping others build.\"\n action={\n <Button onClick={() => navigate('/mentorship/mentors-page')}>Become a mentor</Button>\n }\n />\n ) : (\n <SessionsList\n loading={mentorQ.loading}\n error={mentorQ.error}\n sessions={mentorSessions}\n showMentor={false}\n emptyTitle=\"No sessions to host yet\"\n emptyDescription=\"When mentees request time with you, their sessions will show up here.\"\n isMentor\n onCancel={handleCancel}\n onConfirm={handleConfirm}\n onComplete={handleComplete}\n busyId={cancellingId}\n />\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAkCA,IAAM,IAAc,IAAI,IAAI,CAAC,aAAa,YAAY,CAAC;AAEvD,SAAS,EAAW,EAClB,YACA,eACA,aACA,aACA,cACA,eACA,WASC;CACD,IAAM,IAAY,EAAY,IAAI,EAAQ,OAAO,EAC3C,CAAC,GAAM,KAAW,EAA0C,OAAO,EACnE,CAAC,GAAY,KAAiB,EAAS,GAAG,EAC1C,CAAC,GAAQ,KAAa,EAAS,IAAI,EACnC,CAAC,GAAU,KAAe,EAAS,GAAG;AAY5C,QACE,kBAAC,GAAD;EAAW,WAAU;YAArB;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MAAM,WAAU;gBACd,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;MACd,CAAA,EACP,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,QAAD;UAAM,WAAU;oBACb,EAAQ;UACJ,CAAA;SACP,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA;SACtC,EAAQ,SACP,kBAAC,QAAD;UAAM,WAAU;oBAAhB;WAA0C;WAAG,EAAQ;WAAO;WAAS;cACnE;SACA;;OACL,KAAc,EAAQ,QAAQ,WAC7B,kBAAC,OAAD;QAAK,WAAU;kBAAf,CAA6D,SACrD,EAAQ,OAAO,SACjB;YACJ;OACJ,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,GAAD,EAAe,MAAM,IAAM,CAAA;;UAAE,EAAe,EAAQ,YAAY;UAC3D;YACP,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;UAAE,EAAe,EAAQ,gBAAgB;UACvD;WACH;;OACL,EAAQ,SACP,kBAAC,KAAD;QAAG,WAAU;kBAAiD,EAAQ;QAAW,CAAA,GAC/E;OACA;QACF;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAQ,aACP,kBAAC,GAAD;OACE,SAAQ;OACR,MAAK;OACL,eAAe,OAAO,KAAK,EAAQ,cAAc,IAAI,UAAU,sBAAsB;iBAHvF,CAKE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA,EAAA,QACZ;WACP;MACH,KAAY,EAAQ,WAAW,cAC9B,kBAAC,GAAD;OACE,SAAQ;OACR,MAAK;OACL,eAAe,EAAQ,MAAS,YAAY,SAAS,UAAU;iBAHjE,CAKE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA,EAAA,WACZ;WACP;MACH,KAAY,EAAQ,WAAW,cAC9B,kBAAC,GAAD;OACE,SAAQ;OACR,MAAK;OACL,eAAe,EAAQ,MAAS,aAAa,SAAS,WAAW;iBAHnE,CAKE,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA,EAAA,iBACnB;WACP;MACH,IACC,kBAAC,GAAD;OAAQ,SAAQ;OAAQ,MAAK;OAAK,eAAe,EAAS,EAAQ,GAAG;OAAE,UAAU;iBAAjF,CACE,kBAAC,GAAD,EAAG,MAAM,IAAM,CAAA,EAAA,UACR;WACP;MACA;OACF;;GAEL,MAAS,YACR,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,WAAU;KACV,aAAY;KACZ,OAAO;KACP,WAAW,MAAM,EAAc,EAAE,OAAO,MAAM;KAC9C,CAAA,EACF,kBAAC,GAAD;KAAQ,MAAK;KAAK,SAzFJ,YAAY;AAGhC,MAFA,MAAM,EAAU,EAAQ,IAAI,EAAW,MAAM,CAAC,EAC9C,EAAQ,OAAO,EACf,EAAc,GAAG;;KAsF+B,UAAU;eAAM;KAEjD,CAAA,CACL;QACJ;GACH,MAAS,aACR,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,SAAD;OAAO,WAAU;iBAA8B;OAAoB,CAAA,EACnE,kBAAC,GAAD;OACE,MAAK;OACL,KAAK;OACL,KAAK;OACL,WAAU;OACV,OAAO;OACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;OAC1C,CAAA,CACE;;KACN,kBAAC,GAAD;MACE,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;MAC5C,CAAA;KACF,kBAAC,OAAD,EAAA,UACE,kBAAC,GAAD;MAAQ,MAAK;MAAK,SA5GL,YAAY;AAEjC,OADA,MAAM,EAAW,EAAQ,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,EAAO,IAAI,EAAE,CAAC,EAAE,EAAS,MAAM,CAAC,EAC5F,EAAQ,OAAO;;MA0GoC,UAAU;gBAAM;MAElD,CAAA,EACL,CAAA;KACF;QACJ;GACM;;;AAIhB,SAAS,EAAa,EACpB,YACA,UACA,aACA,eACA,eACA,qBACA,gBACA,aACA,aACA,cACA,eACA,aAcC;AAgBD,QAfI,KAAW,EAAS,WAAW,IAAU,kBAAC,GAAD;EAAa,OAAO;EAAG,QAAO;EAAS,CAAA,GAChF,IAAc,kBAAC,GAAD;EAAW,OAAM;EAAgC;EAAS,CAAA,GACxE,EAAS,WAAW,IAEpB,kBAAC,GAAD;EACE,MAAM,kBAAC,GAAD,EAAe,MAAM,IAAM,CAAA;EACjC,OAAO;EACP,aAAa;EACb,QAAQ;EACR,CAAA,GAOJ,kBAAC,OAAD;EAAK,WAAU;YAJF,CAAC,GAAG,EAAS,CAAC,MAC1B,GAAG,MAAM,IAAI,KAAK,EAAE,YAAY,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,YAAY,CAAC,SAAS,CAChF,CAGW,KAAK,MACX,kBAAC,GAAD;GAEW;GACG;GACF;GACA;GACC;GACC;GACZ,MAAM,MAAW,EAAQ;GACzB,EARK,EAAQ,GAQb,CACF;EACE,CAAA;;AAIV,SAAgB,IAA6B;CAC3C,IAAM,IAAW,GAAuB,EAClC,EAAE,mBAAgB,GAAe,EACjC,CAAC,GAAK,KAAU,EAAsB,SAAS,EAC/C,CAAC,GAAc,KAAmB,EAAwB,KAAK,EAE/D,IAAW,GAAa,IAGxB,IAAU,EAAiB,IAAW,EAAE,aAAU,GAAG,EAAE,CAAC,EAGxD,IAAW,EAAgB,EAAE,CAAC,EAC9B,IAAW,EAAS,MAAM,eAAe,MAAM,MAAM,MAAM,EAAE,WAAW,GAAa,GAAG,EACxF,IAAW,GAAU,IACrB,IAAU,EAAiB,IAAW,EAAE,aAAU,GAAG,EAAE,CAAC,EAExD,CAAC,KAAiB,GAAkB,EACpC,CAAC,KAAkB,GAAmB,EACtC,CAAC,KAAmB,GAAoB,EAExC,IAAiB,IAAY,EAAQ,MAAM,mBAAmB,EAAE,GAAI,EAAE,EACtE,IAAiB,IAAY,EAAQ,MAAM,mBAAmB,EAAE,GAAI,EAAE,EAEtE,IAAe,OAAO,MAAe;AACzC,IAAgB,EAAG;AACnB,MAAI;AAEF,IADY,MAAM,EAAc,EAAE,WAAW,EAAE,OAAI,EAAE,CAAC,EAC9C,MAAM,oBACZ,EAAO,QAAQ,qBAAqB,kCAAkC;YAEhE;AACR,KAAgB,KAAK;;IAInB,IAAgB,OAAO,GAAY,MAAuB;AAC9D,IAAgB,EAAG;AACnB,MAAI;AAIF,IAHY,MAAM,EAAe,EAC/B,WAAW;IAAE;IAAI,YAAY,KAAc,KAAA;IAAW,EACvD,CAAC,EACM,MAAM,sBACZ,EAAO,QAAQ,qBAAqB,gCAAgC,EACpE,MAAM,EAAQ,SAAS;YAEjB;AACR,KAAgB,KAAK;;IAInB,IAAiB,OAAO,GAAY,GAAgB,MAAqB;AAC7E,IAAgB,EAAG;AACnB,MAAI;AAIF,IAHY,MAAM,EAAgB,EAChC,WAAW;IAAE;IAAI;IAAQ,UAAU,KAAY,KAAA;IAAW,EAC3D,CAAC,EACM,MAAM,uBACZ,EAAO,QAAQ,qBAAqB,yCAAyC,EAC7E,MAAM,EAAQ,SAAS;YAEjB;AACR,KAAgB,KAAK;;;AAgBzB,QAZK,GAAa,KAahB,kBAAC,GAAD;EACE,MAAA;EACA,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,GAAD;GAAQ,SAAQ;GAAU,eAAe,EAAS,2BAA2B;aAA7E,CACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA,EAAA,iBACZ;;YAPb;GAUE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAU,OAAM;KAAY,OAAO,EAAe;KAAQ,MAAM;KAAiB,CAAA,EACjF,kBAAC,GAAD;KAAU,OAAM;KAAY,OAAO,IAAW,EAAe,SAAS;KAAG,MAAM;KAAS,CAAA,CACpF;;GAEN,kBAAC,GAAD;IAAM,OAAO;IAAK,gBAAgB,MAAM,EAAO,EAAiB;IAAE,WAAU;cAC1E,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAa,OAAM;eAAS;KAAuB,CAAA,EACnD,kBAAC,GAAD;KAAa,OAAM;eAAS;KAAuB,CAAA,CAC1C,EAAA,CAAA;IACN,CAAA;GAEN,MAAQ,WACP,kBAAC,GAAD;IACE,SAAS,EAAQ;IACjB,OAAO,EAAQ;IACf,UAAU;IACV,YAAA;IACA,YAAW;IACX,kBAAiB;IACjB,aACE,kBAAC,GAAD;KAAQ,eAAe,EAAS,2BAA2B;eAAE;KAAsB,CAAA;IAErF,UAAU;IACV,UAAU;IACV,WAAW;IACX,YAAY;IACZ,QAAQ;IACR,CAAA,GACA,EAAS,WAAW,CAAC,IACvB,kBAAC,GAAD;IAAa,OAAO;IAAG,QAAO;IAAS,CAAA,GACpC,IAUH,kBAAC,GAAD;IACE,SAAS,EAAQ;IACjB,OAAO,EAAQ;IACf,UAAU;IACV,YAAY;IACZ,YAAW;IACX,kBAAiB;IACjB,UAAA;IACA,UAAU;IACV,WAAW;IACX,YAAY;IACZ,QAAQ;IACR,CAAA,GArBF,kBAAC,GAAD;IACE,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAM;IACN,aAAY;IACZ,QACE,kBAAC,GAAD;KAAQ,eAAe,EAAS,2BAA2B;eAAE;KAAwB,CAAA;IAEvF,CAAA;GAgBO;MA5EX,kBAAC,GAAD;EAAY,MAAA;EAAK,OAAM;EAAc,aAAY;YAC/C,kBAAC,GAAD;GACE,MAAM,kBAAC,GAAD,EAAe,MAAM,IAAM,CAAA;GACjC,OAAM;GACN,aAAY;GACZ,CAAA;EACS,CAAA"}
|