@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.
Files changed (40) hide show
  1. package/dist/technospam/api/technospamApi.js +233 -150
  2. package/dist/technospam/api/technospamApi.js.map +1 -1
  3. package/dist/technospam/components/LoadMore.js +18 -2
  4. package/dist/technospam/components/LoadMore.js.map +1 -0
  5. package/dist/technospam/components/MediaCover.js +57 -0
  6. package/dist/technospam/components/MediaCover.js.map +1 -0
  7. package/dist/technospam/components/PageLayout.js +1 -1
  8. package/dist/technospam/components/PageLayout.js.map +1 -1
  9. package/dist/technospam/components/StatCard.js +19 -11
  10. package/dist/technospam/components/StatCard.js.map +1 -1
  11. package/dist/technospam/components/StatusBadge.js +1 -1
  12. package/dist/technospam/components/StatusBadge.js.map +1 -1
  13. package/dist/technospam/components/index.js +1 -0
  14. package/dist/technospam/pages/AdminAdminDashboardPagePage.js +748 -352
  15. package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
  16. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +167 -127
  17. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  18. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +178 -125
  19. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
  20. package/dist/technospam/pages/ApplicationsProblemsPagePage.js +89 -93
  21. package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
  22. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +295 -141
  23. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
  24. package/dist/technospam/pages/CoursesCoursesPagePage.js +86 -86
  25. package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
  26. package/dist/technospam/pages/CoursesMyLearningPagePage.js +122 -88
  27. package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
  28. package/dist/technospam/pages/DashboardDashboardPagePage.js +232 -199
  29. package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
  30. package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js +128 -106
  31. package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js.map +1 -1
  32. package/dist/technospam/pages/HackathonsHackathonsPagePage.js +89 -73
  33. package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
  34. package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +171 -115
  35. package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
  36. package/dist/technospam/pages/MentorshipMentorsPagePage.js +214 -151
  37. package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
  38. package/dist/technospam/pages/MentorshipSessionsPagePage.js +241 -116
  39. package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
  40. 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, useMentorsQuery as f, useSessionsQuery as p } from "../api/technospamApi.js";
10
- import { useState as m } from "react";
11
- import { CalendarClock as h, Clock as g, MessageSquare as _, Users as v, Video as y, X as b } from "lucide-react";
12
- import { jsx as x, jsxs as S } from "react/jsx-runtime";
13
- import { Button as C, GlassCard as w, Tabs as T, TabsList as E, TabsTrigger as D } from "@burdenoff/fe-libs/ui";
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 O = new Set(["REQUESTED", "CONFIRMED"]);
16
- function k({ session: e, showMentor: t, onCancel: n, cancelling: r }) {
17
- let s = O.has(e.status);
18
- return /* @__PURE__ */ S(w, {
19
- className: "flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between",
20
- children: [/* @__PURE__ */ S("div", {
21
- className: "flex items-start gap-3",
22
- children: [/* @__PURE__ */ x("span", {
23
- className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-accent-wash text-accent-primary",
24
- children: /* @__PURE__ */ x(y, { size: 18 })
25
- }), /* @__PURE__ */ S("div", {
26
- className: "min-w-0",
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__ */ S("div", {
29
- className: "flex flex-wrap items-center gap-2",
30
- children: [/* @__PURE__ */ x("span", {
31
- className: "truncate text-sm font-semibold text-text-primary",
32
- children: e.topic
33
- }), /* @__PURE__ */ x(o, { status: e.status })]
34
- }),
35
- t && e.mentor?.headline ? /* @__PURE__ */ S("div", {
36
- className: "mt-0.5 truncate text-xs text-text-secondary",
37
- children: ["with ", e.mentor.headline]
38
- }) : null,
39
- /* @__PURE__ */ S("div", {
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
- e.agenda ? /* @__PURE__ */ x("p", {
58
- className: "mt-1 line-clamp-2 text-xs text-text-secondary",
59
- children: e.agenda
60
- }) : null
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
- }), /* @__PURE__ */ S("div", {
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 A({ loading: e, error: t, sessions: n, showMentor: r, emptyTitle: i, emptyDescription: a, emptyAction: o, onCancel: u, cancellingId: d }) {
81
- return e && n.length === 0 ? /* @__PURE__ */ x(l, {
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__ */ x(c, {
162
+ }) : t ? /* @__PURE__ */ T(c, {
85
163
  title: "Couldn't load sessions",
86
164
  error: t
87
- }) : n.length === 0 ? /* @__PURE__ */ x(s, {
88
- icon: /* @__PURE__ */ x(_, { size: 26 }),
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__ */ x("div", {
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__ */ x(k, {
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
- onCancel: u,
98
- cancelling: d === e.id
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 j() {
103
- let i = t(), { currentUser: a } = e(), [o, c] = m("mentee"), [h, g] = m(null), y = a?.id, b = p(y ? { menteeId: y } : {}), w = f({}), O = w.data?.tecListMentors.items.find((e) => e.userId === a?.id), k = O?.id, j = p(k ? { mentorId: k } : {}), [M] = d(), N = y ? b.data?.tecListSessions ?? [] : [], P = k ? j.data?.tecListSessions ?? [] : [], F = async (e) => {
104
- g(e);
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 M({ variables: { id: e } })).data?.tecCancelSession && u.success("Session cancelled", "The session has been cancelled.");
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
- g(null);
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__ */ S(n, {
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__ */ S(C, {
217
+ actions: /* @__PURE__ */ E(D, {
116
218
  variant: "outline",
117
219
  onClick: () => i("/mentorship/mentors-page"),
118
- children: [/* @__PURE__ */ x(v, { size: 16 }), " Find a mentor"]
220
+ children: [/* @__PURE__ */ T(S, { size: 16 }), " Find a mentor"]
119
221
  }),
120
222
  children: [
121
- /* @__PURE__ */ S("div", {
122
- className: "mb-5 grid grid-cols-2 gap-3 sm:max-w-md",
123
- children: [/* @__PURE__ */ x(r, {
124
- label: "As mentee",
125
- value: N.length,
126
- icon: _
127
- }), /* @__PURE__ */ x(r, {
128
- label: "As mentor",
129
- value: k ? P.length : 0,
130
- icon: v
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__ */ x(T, {
252
+ /* @__PURE__ */ T(A, {
134
253
  value: o,
135
254
  onValueChange: (e) => c(e),
136
255
  className: "mb-4",
137
- children: /* @__PURE__ */ S(E, { children: [/* @__PURE__ */ x(D, {
256
+ children: /* @__PURE__ */ E(j, { children: [/* @__PURE__ */ T(M, {
138
257
  value: "mentee",
139
258
  children: "As mentee"
140
- }), /* @__PURE__ */ x(D, {
259
+ }), /* @__PURE__ */ T(M, {
141
260
  value: "mentor",
142
261
  children: "As mentor"
143
262
  })] })
144
263
  }),
145
- o === "mentee" ? /* @__PURE__ */ x(A, {
146
- loading: b.loading,
147
- error: b.error,
148
- sessions: N,
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__ */ x(C, {
271
+ emptyAction: /* @__PURE__ */ T(D, {
153
272
  onClick: () => i("/mentorship/mentors-page"),
154
273
  children: "Find a mentor"
155
274
  }),
156
- onCancel: F,
157
- cancellingId: h
158
- }) : w.loading && !O ? /* @__PURE__ */ x(l, {
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
- }) : k ? /* @__PURE__ */ x(A, {
162
- loading: j.loading,
163
- error: j.error,
164
- sessions: P,
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
- onCancel: F,
169
- cancellingId: h
170
- }) : /* @__PURE__ */ x(s, {
171
- icon: /* @__PURE__ */ x(v, { size: 26 }),
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__ */ x(C, {
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__ */ x(n, {
305
+ }) : /* @__PURE__ */ T(n, {
181
306
  hero: !0,
182
307
  title: "My Sessions",
183
308
  description: "Track your mentorship sessions.",
184
- children: /* @__PURE__ */ x(s, {
185
- icon: /* @__PURE__ */ x(_, { size: 26 }),
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 { j as MentorshipSessionsPagePage };
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-technospam",
3
- "version": "2026.704.2",
3
+ "version": "2026.705.2",
4
4
  "description": "Burdenoff TechnoSpam Microfrontend",
5
5
  "type": "module",
6
6
  "files": [