@burdenoff/microfe-technospam 2026.704.2 → 2026.705.2
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 +233 -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/components/MediaCover.js +57 -0
- package/dist/technospam/components/MediaCover.js.map +1 -0
- package/dist/technospam/components/PageLayout.js +1 -1
- package/dist/technospam/components/PageLayout.js.map +1 -1
- package/dist/technospam/components/StatCard.js +19 -11
- package/dist/technospam/components/StatCard.js.map +1 -1
- package/dist/technospam/components/StatusBadge.js +1 -1
- package/dist/technospam/components/StatusBadge.js.map +1 -1
- package/dist/technospam/components/index.js +1 -0
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js +748 -352
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +167 -127
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +178 -125
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js +89 -93
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +295 -141
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js +86 -86
- package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesMyLearningPagePage.js +122 -88
- package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
- package/dist/technospam/pages/DashboardDashboardPagePage.js +232 -199
- package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js +128 -106
- package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js +89 -73
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +171 -115
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js +214 -151
- package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.js +241 -116
- package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,189 +6,314 @@ 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 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md",
|
|
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-11 w-11 shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-accent-primary to-accent-purple text-white shadow-sm",
|
|
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
|
+
size: "sm",
|
|
82
|
+
onClick: () => window.open(e.meetingUrl ?? "", "_blank", "noopener,noreferrer"),
|
|
83
|
+
children: [/* @__PURE__ */ T(C, { size: 15 }), " Join"]
|
|
84
|
+
}) : null,
|
|
85
|
+
n && e.status === "REQUESTED" ? /* @__PURE__ */ E(D, {
|
|
86
|
+
variant: "outline",
|
|
87
|
+
size: "sm",
|
|
88
|
+
onClick: () => f(d === "confirm" ? "none" : "confirm"),
|
|
89
|
+
children: [/* @__PURE__ */ T(v, { size: 15 }), " Confirm"]
|
|
90
|
+
}) : null,
|
|
91
|
+
n && e.status === "CONFIRMED" ? /* @__PURE__ */ E(D, {
|
|
92
|
+
variant: "outline",
|
|
93
|
+
size: "sm",
|
|
94
|
+
onClick: () => f(d === "complete" ? "none" : "complete"),
|
|
95
|
+
children: [/* @__PURE__ */ T(y, { size: 15 }), " Mark complete"]
|
|
96
|
+
}) : null,
|
|
97
|
+
u ? /* @__PURE__ */ E(D, {
|
|
98
|
+
variant: "ghost",
|
|
99
|
+
size: "sm",
|
|
100
|
+
onClick: () => r(e.id),
|
|
101
|
+
disabled: l,
|
|
102
|
+
children: [/* @__PURE__ */ T(w, { size: 15 }), " Cancel"]
|
|
103
|
+
}) : null
|
|
104
|
+
]
|
|
105
|
+
})]
|
|
106
|
+
}),
|
|
107
|
+
d === "confirm" ? /* @__PURE__ */ E("div", {
|
|
108
|
+
className: "flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3 sm:flex-row sm:items-center",
|
|
109
|
+
children: [/* @__PURE__ */ T(k, {
|
|
110
|
+
className: "flex-1",
|
|
111
|
+
placeholder: "Meeting link (e.g. https://meet.…)",
|
|
112
|
+
value: p,
|
|
113
|
+
onChange: (e) => m(e.target.value)
|
|
114
|
+
}), /* @__PURE__ */ T(D, {
|
|
115
|
+
size: "sm",
|
|
116
|
+
onClick: async () => {
|
|
117
|
+
await s(e.id, p.trim()), f("none"), m("");
|
|
118
|
+
},
|
|
119
|
+
disabled: l,
|
|
120
|
+
children: "Confirm session"
|
|
121
|
+
})]
|
|
122
|
+
}) : null,
|
|
123
|
+
d === "complete" ? /* @__PURE__ */ E("div", {
|
|
124
|
+
className: "flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3",
|
|
27
125
|
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
|
-
]
|
|
126
|
+
/* @__PURE__ */ E("div", {
|
|
127
|
+
className: "flex items-center gap-2",
|
|
128
|
+
children: [/* @__PURE__ */ T("label", {
|
|
129
|
+
className: "text-xs text-text-secondary",
|
|
130
|
+
children: "Rating (1–5)"
|
|
131
|
+
}), /* @__PURE__ */ T(k, {
|
|
132
|
+
type: "number",
|
|
133
|
+
min: 1,
|
|
134
|
+
max: 5,
|
|
135
|
+
className: "w-20",
|
|
136
|
+
value: h,
|
|
137
|
+
onChange: (e) => x(e.target.value)
|
|
55
138
|
})]
|
|
56
139
|
}),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
140
|
+
/* @__PURE__ */ T(k, {
|
|
141
|
+
placeholder: "Feedback for the mentee (optional)",
|
|
142
|
+
value: S,
|
|
143
|
+
onChange: (e) => A(e.target.value)
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ T("div", { children: /* @__PURE__ */ T(D, {
|
|
146
|
+
size: "sm",
|
|
147
|
+
onClick: async () => {
|
|
148
|
+
await c(e.id, Math.min(5, Math.max(1, Number(h) || 5)), S.trim()), f("none");
|
|
149
|
+
},
|
|
150
|
+
disabled: l,
|
|
151
|
+
children: "Complete session"
|
|
152
|
+
}) })
|
|
61
153
|
]
|
|
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
|
-
})]
|
|
154
|
+
}) : null
|
|
155
|
+
]
|
|
78
156
|
});
|
|
79
157
|
}
|
|
80
|
-
function
|
|
81
|
-
return e && n.length === 0 ? /* @__PURE__ */
|
|
158
|
+
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 }) {
|
|
159
|
+
return e && n.length === 0 ? /* @__PURE__ */ T(l, {
|
|
82
160
|
count: 3,
|
|
83
161
|
height: "h-24"
|
|
84
|
-
}) : t ? /* @__PURE__ */
|
|
162
|
+
}) : t ? /* @__PURE__ */ T(c, {
|
|
85
163
|
title: "Couldn't load sessions",
|
|
86
164
|
error: t
|
|
87
|
-
}) : n.length === 0 ? /* @__PURE__ */
|
|
88
|
-
icon: /* @__PURE__ */ x
|
|
165
|
+
}) : n.length === 0 ? /* @__PURE__ */ T(s, {
|
|
166
|
+
icon: /* @__PURE__ */ T(x, { size: 26 }),
|
|
89
167
|
title: i,
|
|
90
168
|
description: a,
|
|
91
169
|
action: o
|
|
92
|
-
}) : /* @__PURE__ */
|
|
170
|
+
}) : /* @__PURE__ */ T("div", {
|
|
93
171
|
className: "space-y-3",
|
|
94
|
-
children: [...n].sort((e, t) => new Date(t.scheduledAt).getTime() - new Date(e.scheduledAt).getTime()).map((e) => /* @__PURE__ */
|
|
172
|
+
children: [...n].sort((e, t) => new Date(t.scheduledAt).getTime() - new Date(e.scheduledAt).getTime()).map((e) => /* @__PURE__ */ T(P, {
|
|
95
173
|
session: e,
|
|
96
174
|
showMentor: r,
|
|
97
|
-
|
|
98
|
-
|
|
175
|
+
isMentor: u,
|
|
176
|
+
onCancel: d,
|
|
177
|
+
onConfirm: f,
|
|
178
|
+
onComplete: p,
|
|
179
|
+
busy: m === e.id
|
|
99
180
|
}, e.id))
|
|
100
181
|
});
|
|
101
182
|
}
|
|
102
|
-
function
|
|
103
|
-
let i = t(), { currentUser: a } = e(), [o, c] =
|
|
104
|
-
|
|
183
|
+
function I() {
|
|
184
|
+
let i = t(), { currentUser: a } = e(), [o, c] = g("mentee"), [v, b] = g(null), C = a?.id, w = h(C ? { menteeId: C } : {}), O = m({}), k = O.data?.tecListMentors.items.find((e) => e.userId === a?.id), N = k?.id, P = h(N ? { mentorId: N } : {}), [I] = d(), [L] = p(), [R] = f(), z = C ? w.data?.tecListSessions ?? [] : [], B = N ? P.data?.tecListSessions ?? [] : [], V = [...z, ...B], H = V.filter((e) => e.status === "REQUESTED" || e.status === "CONFIRMED").length, U = V.filter((e) => e.status === "COMPLETED").length, W = async (e) => {
|
|
185
|
+
b(e);
|
|
186
|
+
try {
|
|
187
|
+
(await I({ variables: { id: e } })).data?.tecCancelSession && u.success("Session cancelled", "The session has been cancelled.");
|
|
188
|
+
} finally {
|
|
189
|
+
b(null);
|
|
190
|
+
}
|
|
191
|
+
}, G = async (e, t) => {
|
|
192
|
+
b(e);
|
|
105
193
|
try {
|
|
106
|
-
(await
|
|
194
|
+
(await L({ variables: {
|
|
195
|
+
id: e,
|
|
196
|
+
meetingUrl: t || void 0
|
|
197
|
+
} })).data?.tecConfirmSession && (u.success("Session confirmed", "The mentee has been notified."), await P.refetch());
|
|
107
198
|
} finally {
|
|
108
|
-
|
|
199
|
+
b(null);
|
|
200
|
+
}
|
|
201
|
+
}, K = async (e, t, n) => {
|
|
202
|
+
b(e);
|
|
203
|
+
try {
|
|
204
|
+
(await R({ variables: {
|
|
205
|
+
id: e,
|
|
206
|
+
rating: t,
|
|
207
|
+
feedback: n || void 0
|
|
208
|
+
} })).data?.tecCompleteSession && (u.success("Session completed", "Nice work — the session is wrapped up."), await P.refetch());
|
|
209
|
+
} finally {
|
|
210
|
+
b(null);
|
|
109
211
|
}
|
|
110
212
|
};
|
|
111
|
-
return a?.id ? /* @__PURE__ */
|
|
213
|
+
return a?.id ? /* @__PURE__ */ E(n, {
|
|
112
214
|
hero: !0,
|
|
113
215
|
title: "My Sessions",
|
|
114
216
|
description: "Manage the mentorship sessions you've booked and the ones you host.",
|
|
115
|
-
actions: /* @__PURE__ */
|
|
217
|
+
actions: /* @__PURE__ */ E(D, {
|
|
116
218
|
variant: "outline",
|
|
117
219
|
onClick: () => i("/mentorship/mentors-page"),
|
|
118
|
-
children: [/* @__PURE__ */
|
|
220
|
+
children: [/* @__PURE__ */ T(S, { size: 16 }), " Find a mentor"]
|
|
119
221
|
}),
|
|
120
222
|
children: [
|
|
121
|
-
/* @__PURE__ */
|
|
122
|
-
className: "mb-5 grid grid-cols-2 gap-3 sm:
|
|
123
|
-
children: [
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
223
|
+
/* @__PURE__ */ E("div", {
|
|
224
|
+
className: "mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4",
|
|
225
|
+
children: [
|
|
226
|
+
/* @__PURE__ */ T(r, {
|
|
227
|
+
label: "As mentee",
|
|
228
|
+
value: z.length,
|
|
229
|
+
icon: x,
|
|
230
|
+
tone: "blue"
|
|
231
|
+
}),
|
|
232
|
+
/* @__PURE__ */ T(r, {
|
|
233
|
+
label: "As mentor",
|
|
234
|
+
value: N ? B.length : 0,
|
|
235
|
+
icon: S,
|
|
236
|
+
tone: "purple"
|
|
237
|
+
}),
|
|
238
|
+
/* @__PURE__ */ T(r, {
|
|
239
|
+
label: "Upcoming",
|
|
240
|
+
value: H,
|
|
241
|
+
icon: _,
|
|
242
|
+
tone: "teal"
|
|
243
|
+
}),
|
|
244
|
+
/* @__PURE__ */ T(r, {
|
|
245
|
+
label: "Completed",
|
|
246
|
+
value: U,
|
|
247
|
+
icon: y,
|
|
248
|
+
tone: "green"
|
|
249
|
+
})
|
|
250
|
+
]
|
|
132
251
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
252
|
+
/* @__PURE__ */ T(A, {
|
|
134
253
|
value: o,
|
|
135
254
|
onValueChange: (e) => c(e),
|
|
136
255
|
className: "mb-4",
|
|
137
|
-
children: /* @__PURE__ */
|
|
256
|
+
children: /* @__PURE__ */ E(j, { children: [/* @__PURE__ */ T(M, {
|
|
138
257
|
value: "mentee",
|
|
139
258
|
children: "As mentee"
|
|
140
|
-
}), /* @__PURE__ */
|
|
259
|
+
}), /* @__PURE__ */ T(M, {
|
|
141
260
|
value: "mentor",
|
|
142
261
|
children: "As mentor"
|
|
143
262
|
})] })
|
|
144
263
|
}),
|
|
145
|
-
o === "mentee" ? /* @__PURE__ */
|
|
146
|
-
loading:
|
|
147
|
-
error:
|
|
148
|
-
sessions:
|
|
264
|
+
o === "mentee" ? /* @__PURE__ */ T(F, {
|
|
265
|
+
loading: w.loading,
|
|
266
|
+
error: w.error,
|
|
267
|
+
sessions: z,
|
|
149
268
|
showMentor: !0,
|
|
150
269
|
emptyTitle: "No sessions booked yet",
|
|
151
270
|
emptyDescription: "Find a mentor and request a session to get personalized guidance.",
|
|
152
|
-
emptyAction: /* @__PURE__ */
|
|
271
|
+
emptyAction: /* @__PURE__ */ T(D, {
|
|
153
272
|
onClick: () => i("/mentorship/mentors-page"),
|
|
154
273
|
children: "Find a mentor"
|
|
155
274
|
}),
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
275
|
+
isMentor: !1,
|
|
276
|
+
onCancel: W,
|
|
277
|
+
onConfirm: G,
|
|
278
|
+
onComplete: K,
|
|
279
|
+
busyId: v
|
|
280
|
+
}) : O.loading && !k ? /* @__PURE__ */ T(l, {
|
|
159
281
|
count: 3,
|
|
160
282
|
height: "h-24"
|
|
161
|
-
}) :
|
|
162
|
-
loading:
|
|
163
|
-
error:
|
|
164
|
-
sessions:
|
|
283
|
+
}) : N ? /* @__PURE__ */ T(F, {
|
|
284
|
+
loading: P.loading,
|
|
285
|
+
error: P.error,
|
|
286
|
+
sessions: B,
|
|
165
287
|
showMentor: !1,
|
|
166
288
|
emptyTitle: "No sessions to host yet",
|
|
167
289
|
emptyDescription: "When mentees request time with you, their sessions will show up here.",
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
290
|
+
isMentor: !0,
|
|
291
|
+
onCancel: W,
|
|
292
|
+
onConfirm: G,
|
|
293
|
+
onComplete: K,
|
|
294
|
+
busyId: v
|
|
295
|
+
}) : /* @__PURE__ */ T(s, {
|
|
296
|
+
icon: /* @__PURE__ */ T(S, { size: 26 }),
|
|
172
297
|
title: "You're not a mentor yet",
|
|
173
298
|
description: "Create a mentor profile to start hosting sessions and helping others build.",
|
|
174
|
-
action: /* @__PURE__ */
|
|
299
|
+
action: /* @__PURE__ */ T(D, {
|
|
175
300
|
onClick: () => i("/mentorship/mentors-page"),
|
|
176
301
|
children: "Become a mentor"
|
|
177
302
|
})
|
|
178
303
|
})
|
|
179
304
|
]
|
|
180
|
-
}) : /* @__PURE__ */
|
|
305
|
+
}) : /* @__PURE__ */ T(n, {
|
|
181
306
|
hero: !0,
|
|
182
307
|
title: "My Sessions",
|
|
183
308
|
description: "Track your mentorship sessions.",
|
|
184
|
-
children: /* @__PURE__ */
|
|
185
|
-
icon: /* @__PURE__ */ x
|
|
309
|
+
children: /* @__PURE__ */ T(s, {
|
|
310
|
+
icon: /* @__PURE__ */ T(x, { size: 26 }),
|
|
186
311
|
title: "Sign in to view your sessions",
|
|
187
312
|
description: "Your booked and hosted mentorship sessions will appear here once you're signed in."
|
|
188
313
|
})
|
|
189
314
|
});
|
|
190
315
|
}
|
|
191
316
|
//#endregion
|
|
192
|
-
export {
|
|
317
|
+
export { I as MentorshipSessionsPagePage };
|
|
193
318
|
|
|
194
319
|
//# 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 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md\">\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-11 w-11 shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-accent-primary to-accent-purple text-white shadow-sm\">\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 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 const allSessions = [...menteeSessions, ...mentorSessions];\n const upcomingCount = allSessions.filter(\n (s) => s.status === 'REQUESTED' || s.status === 'CONFIRMED'\n ).length;\n const completedCount = allSessions.filter((s) => s.status === 'COMPLETED').length;\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:grid-cols-4\">\n <StatCard\n label=\"As mentee\"\n value={menteeSessions.length}\n icon={MessageSquare}\n tone=\"blue\"\n />\n <StatCard\n label=\"As mentor\"\n value={mentorId ? mentorSessions.length : 0}\n icon={Users}\n tone=\"purple\"\n />\n <StatCard label=\"Upcoming\" value={upcomingCount} icon={CalendarClock} tone=\"teal\" />\n <StatCard label=\"Completed\" value={completedCount} icon={CheckCircle2} tone=\"green\" />\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":"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"}
|