@burdenoff/microfe-technospam 2026.1101.2 → 2026.1101.4
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/stories/journeys/Courses.stories.d.ts +5 -0
- package/dist/stories/journeys/Courses.stories.d.ts.map +1 -1
- package/dist/stories/journeys/Mentorship.stories.d.ts +5 -0
- package/dist/stories/journeys/Mentorship.stories.d.ts.map +1 -1
- package/dist/stories/journeys/Problems.stories.d.ts +5 -0
- package/dist/stories/journeys/Problems.stories.d.ts.map +1 -1
- package/dist/technospam/components/CardOpenButton.d.ts +26 -0
- package/dist/technospam/components/CardOpenButton.d.ts.map +1 -0
- package/dist/technospam/components/CardOpenButton.js +15 -0
- package/dist/technospam/components/CardOpenButton.js.map +1 -0
- package/dist/technospam/components/index.d.ts +1 -0
- package/dist/technospam/components/index.d.ts.map +1 -1
- package/dist/technospam/components/index.js +1 -0
- package/dist/technospam/pages/ApplicationsProblemsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js +80 -77
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js +68 -65
- package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js +75 -72
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js +1 -0
- package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,68 +9,71 @@ import { StatusBadge as l } from "../components/StatusBadge.js";
|
|
|
9
9
|
import { LoadMore as u } from "../components/LoadMore.js";
|
|
10
10
|
import { EmptyView as d, ErrorView as f, LoadingGrid as p } from "../components/StateViews.js";
|
|
11
11
|
import { pageArg as m, useHackathonsQuery as h, usePageLimit as g } from "../api/technospamApi.js";
|
|
12
|
+
import { CardOpenButton as _ } from "../components/CardOpenButton.js";
|
|
12
13
|
import "../components/index.js";
|
|
13
|
-
import { TAB_PANEL_FOCUS_CLASS as
|
|
14
|
-
import { useMemo as
|
|
15
|
-
import { Award as
|
|
16
|
-
import { jsx as
|
|
17
|
-
import { Badge as
|
|
14
|
+
import { TAB_PANEL_FOCUS_CLASS as v } from "../lib/a11y.js";
|
|
15
|
+
import { useMemo as y, useState as b } from "react";
|
|
16
|
+
import { Award as x, CalendarDays as S, Search as C, Sparkles as w, Trophy as T, Users as E } from "lucide-react";
|
|
17
|
+
import { jsx as D, jsxs as O } from "react/jsx-runtime";
|
|
18
|
+
import { Badge as k, GlassCard as A, Input as j, Tabs as M, TabsContent as N, TabsList as P, TabsTrigger as F } from "@burdenoff/fe-libs/ui";
|
|
18
19
|
//#region src/technospam/pages/HackathonsHackathonsPagePage.tsx
|
|
19
|
-
function
|
|
20
|
+
function I({ hackathon: e, onOpen: t }) {
|
|
20
21
|
let n = r();
|
|
21
|
-
return /* @__PURE__ */
|
|
22
|
+
return /* @__PURE__ */ O(A, {
|
|
22
23
|
className: "group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg",
|
|
23
|
-
|
|
24
|
-
children: [/* @__PURE__ */ E(o, {
|
|
24
|
+
children: [/* @__PURE__ */ D(o, {
|
|
25
25
|
height: "h-32",
|
|
26
26
|
seed: e.theme ?? e.id,
|
|
27
|
-
icon:
|
|
28
|
-
children: /* @__PURE__ */
|
|
29
|
-
}), /* @__PURE__ */
|
|
27
|
+
icon: T,
|
|
28
|
+
children: /* @__PURE__ */ D(l, { status: e.status })
|
|
29
|
+
}), /* @__PURE__ */ O("div", {
|
|
30
30
|
className: "flex flex-1 flex-col gap-3 p-4",
|
|
31
31
|
children: [
|
|
32
|
-
/* @__PURE__ */
|
|
32
|
+
/* @__PURE__ */ O("div", {
|
|
33
33
|
className: "min-w-0",
|
|
34
|
-
children: [/* @__PURE__ */
|
|
34
|
+
children: [/* @__PURE__ */ D("h3", {
|
|
35
35
|
className: "truncate text-base font-semibold text-text-primary group-hover:text-accent-primary",
|
|
36
|
-
children:
|
|
37
|
-
|
|
36
|
+
children: /* @__PURE__ */ D(_, {
|
|
37
|
+
onOpen: t,
|
|
38
|
+
children: e.title
|
|
39
|
+
})
|
|
40
|
+
}), e.theme ? /* @__PURE__ */ D("p", {
|
|
38
41
|
className: "mt-1 line-clamp-2 text-sm text-text-secondary",
|
|
39
42
|
children: e.theme
|
|
40
43
|
}) : null]
|
|
41
44
|
}),
|
|
42
|
-
/* @__PURE__ */
|
|
45
|
+
/* @__PURE__ */ O("div", {
|
|
43
46
|
className: "mt-auto flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-muted",
|
|
44
|
-
children: [/* @__PURE__ */
|
|
47
|
+
children: [/* @__PURE__ */ O("span", {
|
|
45
48
|
className: "inline-flex items-center gap-1",
|
|
46
49
|
children: [
|
|
47
|
-
/* @__PURE__ */
|
|
50
|
+
/* @__PURE__ */ D(S, { size: 13 }),
|
|
48
51
|
" ",
|
|
49
52
|
s(e.startAt),
|
|
50
53
|
" –",
|
|
51
54
|
" ",
|
|
52
55
|
s(e.endAt)
|
|
53
56
|
]
|
|
54
|
-
}), /* @__PURE__ */
|
|
57
|
+
}), /* @__PURE__ */ O("span", {
|
|
55
58
|
className: "inline-flex items-center gap-1",
|
|
56
59
|
children: [
|
|
57
|
-
/* @__PURE__ */ E
|
|
60
|
+
/* @__PURE__ */ D(E, { size: 13 }),
|
|
58
61
|
" ",
|
|
59
62
|
n("technospam.hackathons.teamSize", "Team of {{size}}", { size: e.maxTeamSize })
|
|
60
63
|
]
|
|
61
64
|
})]
|
|
62
65
|
}),
|
|
63
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ O("div", {
|
|
64
67
|
className: "flex items-center gap-1.5 text-sm font-medium text-accent-teal",
|
|
65
68
|
children: [
|
|
66
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ D(x, { size: 15 }),
|
|
67
70
|
" ",
|
|
68
71
|
n("technospam.hackathons.prizePool", "{{prize}} prize pool", { prize: c(e.prizePool, e.currency) })
|
|
69
72
|
]
|
|
70
73
|
}),
|
|
71
|
-
e.tags.length ? /* @__PURE__ */
|
|
74
|
+
e.tags.length ? /* @__PURE__ */ D("div", {
|
|
72
75
|
className: "flex flex-wrap gap-1.5",
|
|
73
|
-
children: e.tags.slice(0, 4).map((e) => /* @__PURE__ */
|
|
76
|
+
children: e.tags.slice(0, 4).map((e) => /* @__PURE__ */ D(k, {
|
|
74
77
|
variant: "secondary",
|
|
75
78
|
className: "text-[11px]",
|
|
76
79
|
children: e
|
|
@@ -80,81 +83,81 @@ function F({ hackathon: e, onOpen: t }) {
|
|
|
80
83
|
})]
|
|
81
84
|
});
|
|
82
85
|
}
|
|
83
|
-
function
|
|
84
|
-
let o = t(), { workspaceId: s } = e(), { emit: l } = n(),
|
|
86
|
+
function L() {
|
|
87
|
+
let o = t(), { workspaceId: s } = e(), { emit: l } = n(), _ = r(), [S, E] = b("ALL"), [k, A] = b(""), { limit: L, more: R } = g(), z = y(() => [
|
|
85
88
|
{
|
|
86
89
|
value: "ALL",
|
|
87
|
-
label:
|
|
90
|
+
label: _("technospam.hackathons.filterAll", "All")
|
|
88
91
|
},
|
|
89
92
|
{
|
|
90
93
|
value: "REGISTRATION_OPEN",
|
|
91
|
-
label:
|
|
94
|
+
label: _("technospam.hackathons.filterRegistrationOpen", "Registration open")
|
|
92
95
|
},
|
|
93
96
|
{
|
|
94
97
|
value: "IN_PROGRESS",
|
|
95
|
-
label:
|
|
98
|
+
label: _("technospam.hackathons.filterInProgress", "In progress")
|
|
96
99
|
},
|
|
97
100
|
{
|
|
98
101
|
value: "JUDGING",
|
|
99
|
-
label:
|
|
102
|
+
label: _("technospam.hackathons.filterJudging", "Judging")
|
|
100
103
|
},
|
|
101
104
|
{
|
|
102
105
|
value: "COMPLETED",
|
|
103
|
-
label:
|
|
106
|
+
label: _("technospam.hackathons.filterCompleted", "Completed")
|
|
104
107
|
}
|
|
105
|
-
], [
|
|
108
|
+
], [_]), { data: B, loading: V, error: H } = h({
|
|
106
109
|
pagination: m(L),
|
|
107
|
-
...
|
|
108
|
-
}), U = B?.tecListHackathons?.items ?? [], W = B?.tecListHackathons?.pageInfo?.hasMore ?? !1, G =
|
|
110
|
+
...S === "ALL" ? {} : { status: S }
|
|
111
|
+
}), U = B?.tecListHackathons?.items ?? [], W = B?.tecListHackathons?.pageInfo?.hasMore ?? !1, G = y(() => {
|
|
109
112
|
let e = k.trim().toLowerCase();
|
|
110
113
|
return e ? U.filter((t) => t.title.toLowerCase().includes(e) || (t.theme ?? "").toLowerCase().includes(e) || t.tags.some((t) => t.toLowerCase().includes(e))) : U;
|
|
111
114
|
}, [U, k]), K = G.filter((e) => e.status === "REGISTRATION_OPEN").length, q = G.reduce((e, t) => e + t.prizePool, 0), J = G[0]?.currency ?? "USD";
|
|
112
|
-
return /* @__PURE__ */
|
|
115
|
+
return /* @__PURE__ */ O(i, {
|
|
113
116
|
hero: !0,
|
|
114
|
-
title:
|
|
115
|
-
description:
|
|
116
|
-
children: [/* @__PURE__ */
|
|
117
|
+
title: _("technospam.hackathons.title", "Hackathons"),
|
|
118
|
+
description: _("technospam.hackathons.description", "Compete, collaborate, and ship real projects with a team in a fixed window."),
|
|
119
|
+
children: [/* @__PURE__ */ O("div", {
|
|
117
120
|
className: "mb-5 grid grid-cols-1 gap-3 sm:grid-cols-3",
|
|
118
121
|
children: [
|
|
119
|
-
/* @__PURE__ */
|
|
120
|
-
label:
|
|
122
|
+
/* @__PURE__ */ D(a, {
|
|
123
|
+
label: _("technospam.hackathons.statHackathons", "Hackathons"),
|
|
121
124
|
value: G.length,
|
|
122
|
-
icon:
|
|
125
|
+
icon: T,
|
|
123
126
|
tone: "purple"
|
|
124
127
|
}),
|
|
125
|
-
/* @__PURE__ */
|
|
126
|
-
label:
|
|
128
|
+
/* @__PURE__ */ D(a, {
|
|
129
|
+
label: _("technospam.hackathons.statRegistrationOpen", "Registration open"),
|
|
127
130
|
value: K,
|
|
128
|
-
icon:
|
|
131
|
+
icon: w,
|
|
129
132
|
tone: "green"
|
|
130
133
|
}),
|
|
131
|
-
/* @__PURE__ */
|
|
132
|
-
label:
|
|
134
|
+
/* @__PURE__ */ D(a, {
|
|
135
|
+
label: _("technospam.hackathons.statTotalPrizePool", "Total prize pool"),
|
|
133
136
|
value: c(q, J),
|
|
134
|
-
icon:
|
|
137
|
+
icon: x,
|
|
135
138
|
tone: "amber"
|
|
136
139
|
})
|
|
137
140
|
]
|
|
138
|
-
}), /* @__PURE__ */
|
|
141
|
+
}), /* @__PURE__ */ O(M, {
|
|
139
142
|
className: "gap-0",
|
|
140
|
-
value:
|
|
141
|
-
onValueChange: (e) =>
|
|
142
|
-
children: [/* @__PURE__ */
|
|
143
|
+
value: S,
|
|
144
|
+
onValueChange: (e) => E(e),
|
|
145
|
+
children: [/* @__PURE__ */ O("div", {
|
|
143
146
|
className: "mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
147
|
+
children: [/* @__PURE__ */ D(P, { children: z.map((e) => /* @__PURE__ */ D(F, {
|
|
145
148
|
value: e.value,
|
|
146
149
|
children: e.label
|
|
147
|
-
}, e.value)) }), /* @__PURE__ */
|
|
150
|
+
}, e.value)) }), /* @__PURE__ */ O("div", {
|
|
148
151
|
className: "relative w-full sm:w-72",
|
|
149
|
-
children: [/* @__PURE__ */
|
|
152
|
+
children: [/* @__PURE__ */ D(C, {
|
|
150
153
|
className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted",
|
|
151
154
|
size: 16
|
|
152
|
-
}), /* @__PURE__ */
|
|
155
|
+
}), /* @__PURE__ */ D(j, {
|
|
153
156
|
className: "pl-9",
|
|
154
|
-
"aria-label":
|
|
155
|
-
placeholder:
|
|
157
|
+
"aria-label": _("technospam.hackathons.searchLabel", "Search hackathons"),
|
|
158
|
+
placeholder: _("technospam.hackathons.searchPlaceholder", "Search hackathons…"),
|
|
156
159
|
value: k,
|
|
157
|
-
onChange: (e) =>
|
|
160
|
+
onChange: (e) => A(e.target.value),
|
|
158
161
|
onBlur: () => {
|
|
159
162
|
let e = k.trim();
|
|
160
163
|
e && l("technospam.search.performed", {
|
|
@@ -165,19 +168,19 @@ function I() {
|
|
|
165
168
|
}
|
|
166
169
|
})]
|
|
167
170
|
})]
|
|
168
|
-
}), /* @__PURE__ */
|
|
169
|
-
value:
|
|
170
|
-
className:
|
|
171
|
-
children: [V && !G.length ? /* @__PURE__ */
|
|
172
|
-
title:
|
|
171
|
+
}), /* @__PURE__ */ O(N, {
|
|
172
|
+
value: S,
|
|
173
|
+
className: v,
|
|
174
|
+
children: [V && !G.length ? /* @__PURE__ */ D(p, {}) : H ? /* @__PURE__ */ D(f, {
|
|
175
|
+
title: _("technospam.common.errorLoadHackathons", "Couldn't load hackathons"),
|
|
173
176
|
error: H
|
|
174
|
-
}) : G.length === 0 ? /* @__PURE__ */
|
|
175
|
-
icon: /* @__PURE__ */
|
|
176
|
-
title:
|
|
177
|
-
description:
|
|
178
|
-
}) : /* @__PURE__ */
|
|
177
|
+
}) : G.length === 0 ? /* @__PURE__ */ D(d, {
|
|
178
|
+
icon: /* @__PURE__ */ D(T, { size: 26 }),
|
|
179
|
+
title: S === "ALL" ? _("technospam.hackathons.emptyDefaultTitle", "No hackathons yet") : _("technospam.hackathons.emptyFilteredTitle", "No hackathons in this stage"),
|
|
180
|
+
description: S === "ALL" ? _("technospam.hackathons.emptyDefaultDesc", "Upcoming hackathons will appear here. Check back soon — TechnoSpam is pre-launch.") : _("technospam.hackathons.emptyFilteredDesc", "Try a different stage filter.")
|
|
181
|
+
}) : /* @__PURE__ */ D("div", {
|
|
179
182
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
180
|
-
children: G.map((e) => /* @__PURE__ */
|
|
183
|
+
children: G.map((e) => /* @__PURE__ */ D(I, {
|
|
181
184
|
hackathon: e,
|
|
182
185
|
onOpen: () => {
|
|
183
186
|
l("technospam.hackathon.viewed", {
|
|
@@ -187,7 +190,7 @@ function I() {
|
|
|
187
190
|
}), o(`/hackathons/hackathon-details-page?id=${e.id}`);
|
|
188
191
|
}
|
|
189
192
|
}, e.id))
|
|
190
|
-
}), /* @__PURE__ */
|
|
193
|
+
}), /* @__PURE__ */ D(u, {
|
|
191
194
|
hasMore: W,
|
|
192
195
|
loading: V,
|
|
193
196
|
onClick: R
|
|
@@ -197,6 +200,6 @@ function I() {
|
|
|
197
200
|
});
|
|
198
201
|
}
|
|
199
202
|
//#endregion
|
|
200
|
-
export {
|
|
203
|
+
export { L as HackathonsHackathonsPagePage };
|
|
201
204
|
|
|
202
205
|
//# sourceMappingURL=HackathonsHackathonsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HackathonsHackathonsPagePage.js","names":[],"sources":["../../../src/technospam/pages/HackathonsHackathonsPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Award, CalendarDays, Search, Sparkles, Trophy, Users } from 'lucide-react';\nimport {\n Badge,\n GlassCard,\n Input,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { TAB_PANEL_FOCUS_CLASS } from '../lib/a11y';\nimport {\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n MediaCover,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useHackathonsQuery,\n usePageLimit,\n type TecHackathon,\n type TecHackathonStatus,\n} from '../api/technospamApi';\nimport { formatDate, formatMoney } from '../utils/format';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\nimport { useTr } from '../hooks/useTr';\n\nfunction HackathonCard({ hackathon, onOpen }: { hackathon: TecHackathon; onOpen: () => void }) {\n const tr = useTr();\n return (\n <GlassCard\n className=\"group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\"\n onClick={onOpen}\n >\n <MediaCover height=\"h-32\" seed={hackathon.theme ?? hackathon.id} icon={Trophy}>\n <StatusBadge status={hackathon.status} />\n </MediaCover>\n <div className=\"flex flex-1 flex-col gap-3 p-4\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary group-hover:text-accent-primary\">\n {hackathon.title}\n </h3>\n {hackathon.theme ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-secondary\">{hackathon.theme}</p>\n ) : null}\n </div>\n\n <div className=\"mt-auto flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <CalendarDays size={13} /> {formatDate(hackathon.startAt)} –{' '}\n {formatDate(hackathon.endAt)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Users size={13} />{' '}\n {tr('technospam.hackathons.teamSize', 'Team of {{size}}', {\n size: hackathon.maxTeamSize,\n })}\n </span>\n </div>\n\n <div className=\"flex items-center gap-1.5 text-sm font-medium text-accent-teal\">\n <Award size={15} />{' '}\n {tr('technospam.hackathons.prizePool', '{{prize}} prize pool', {\n prize: formatMoney(hackathon.prizePool, hackathon.currency),\n })}\n </div>\n\n {hackathon.tags.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {hackathon.tags.slice(0, 4).map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-[11px]\">\n {t}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nexport function HackathonsHackathonsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const tr = useTr();\n const [status, setStatus] = useState<'ALL' | TecHackathonStatus>('ALL');\n const [search, setSearch] = useState('');\n const { limit, more } = usePageLimit();\n\n const statuses = useMemo(\n () => [\n { value: 'ALL' as const, label: tr('technospam.hackathons.filterAll', 'All') },\n {\n value: 'REGISTRATION_OPEN' as TecHackathonStatus,\n label: tr('technospam.hackathons.filterRegistrationOpen', 'Registration open'),\n },\n {\n value: 'IN_PROGRESS' as TecHackathonStatus,\n label: tr('technospam.hackathons.filterInProgress', 'In progress'),\n },\n {\n value: 'JUDGING' as TecHackathonStatus,\n label: tr('technospam.hackathons.filterJudging', 'Judging'),\n },\n {\n value: 'COMPLETED' as TecHackathonStatus,\n label: tr('technospam.hackathons.filterCompleted', 'Completed'),\n },\n ],\n [tr]\n );\n\n const { data, loading, error } = useHackathonsQuery({\n pagination: pageArg(limit),\n ...(status !== 'ALL' ? { status } : {}),\n });\n\n const allHackathons = data?.tecListHackathons?.items ?? [];\n const hasMore = data?.tecListHackathons?.pageInfo?.hasMore ?? false;\n const hackathons = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return allHackathons;\n return allHackathons.filter(\n (h) =>\n h.title.toLowerCase().includes(q) ||\n (h.theme ?? '').toLowerCase().includes(q) ||\n h.tags.some((t) => t.toLowerCase().includes(q))\n );\n }, [allHackathons, search]);\n const openCount = hackathons.filter((h) => h.status === 'REGISTRATION_OPEN').length;\n const totalPrize = hackathons.reduce((s, h) => s + h.prizePool, 0);\n const prizeCurrency = hackathons[0]?.currency ?? 'USD';\n\n return (\n <PageLayout\n hero\n title={tr('technospam.hackathons.title', 'Hackathons')}\n description={tr(\n 'technospam.hackathons.description',\n 'Compete, collaborate, and ship real projects with a team in a fixed window.'\n )}\n >\n <div className=\"mb-5 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <StatCard\n label={tr('technospam.hackathons.statHackathons', 'Hackathons')}\n value={hackathons.length}\n icon={Trophy}\n tone=\"purple\"\n />\n <StatCard\n label={tr('technospam.hackathons.statRegistrationOpen', 'Registration open')}\n value={openCount}\n icon={Sparkles}\n tone=\"green\"\n />\n <StatCard\n label={tr('technospam.hackathons.statTotalPrizePool', 'Total prize pool')}\n value={formatMoney(totalPrize, prizeCurrency)}\n icon={Award}\n tone=\"amber\"\n />\n </div>\n\n {/* The tabs filter one list, so that list is their tab panel: Radix points every\n trigger's aria-controls at a panel id, and without a TabsContent the id\n resolved to nothing (axe aria-valid-attr-value, critical; BOFF-3157). */}\n <Tabs\n className=\"gap-0\"\n value={status}\n onValueChange={(v) => setStatus(v as 'ALL' | TecHackathonStatus)}\n >\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <TabsList>\n {statuses.map((s) => (\n <TabsTrigger key={s.value} value={s.value}>\n {s.label}\n </TabsTrigger>\n ))}\n </TabsList>\n <div className=\"relative w-full sm:w-72\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted\"\n size={16}\n />\n <Input\n className=\"pl-9\"\n aria-label={tr('technospam.hackathons.searchLabel', 'Search hackathons')}\n placeholder={tr('technospam.hackathons.searchPlaceholder', 'Search hackathons…')}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onBlur={() => {\n const value = search.trim();\n if (value) {\n emit('technospam.search.performed', {\n workspaceId,\n entityType: 'hackathon',\n queryLength: value.length,\n });\n }\n }}\n />\n </div>\n </div>\n\n <TabsContent value={status} className={TAB_PANEL_FOCUS_CLASS}>\n {loading && !hackathons.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView\n title={tr('technospam.common.errorLoadHackathons', \"Couldn't load hackathons\")}\n error={error}\n />\n ) : hackathons.length === 0 ? (\n <EmptyView\n icon={<Trophy size={26} />}\n title={\n status !== 'ALL'\n ? tr('technospam.hackathons.emptyFilteredTitle', 'No hackathons in this stage')\n : tr('technospam.hackathons.emptyDefaultTitle', 'No hackathons yet')\n }\n description={\n status !== 'ALL'\n ? tr('technospam.hackathons.emptyFilteredDesc', 'Try a different stage filter.')\n : tr(\n 'technospam.hackathons.emptyDefaultDesc',\n 'Upcoming hackathons will appear here. Check back soon — TechnoSpam is pre-launch.'\n )\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {hackathons.map((hackathon) => (\n <HackathonCard\n key={hackathon.id}\n hackathon={hackathon}\n onOpen={() => {\n emit('technospam.hackathon.viewed', {\n workspaceId,\n entityId: hackathon.id,\n entityType: 'TEC_HACKATHON',\n });\n navigate(`/hackathons/hackathon-details-page?id=${hackathon.id}`);\n }}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </TabsContent>\n </Tabs>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HackathonsHackathonsPagePage.js","names":[],"sources":["../../../src/technospam/pages/HackathonsHackathonsPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Award, CalendarDays, Search, Sparkles, Trophy, Users } from 'lucide-react';\nimport {\n Badge,\n GlassCard,\n Input,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { TAB_PANEL_FOCUS_CLASS } from '../lib/a11y';\nimport {\n CardOpenButton,\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n MediaCover,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useHackathonsQuery,\n usePageLimit,\n type TecHackathon,\n type TecHackathonStatus,\n} from '../api/technospamApi';\nimport { formatDate, formatMoney } from '../utils/format';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\nimport { useTr } from '../hooks/useTr';\n\nfunction HackathonCard({ hackathon, onOpen }: { hackathon: TecHackathon; onOpen: () => void }) {\n const tr = useTr();\n return (\n <GlassCard className=\"group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\">\n <MediaCover height=\"h-32\" seed={hackathon.theme ?? hackathon.id} icon={Trophy}>\n <StatusBadge status={hackathon.status} />\n </MediaCover>\n <div className=\"flex flex-1 flex-col gap-3 p-4\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary group-hover:text-accent-primary\">\n <CardOpenButton onOpen={onOpen}>{hackathon.title}</CardOpenButton>\n </h3>\n {hackathon.theme ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-secondary\">{hackathon.theme}</p>\n ) : null}\n </div>\n\n <div className=\"mt-auto flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <CalendarDays size={13} /> {formatDate(hackathon.startAt)} –{' '}\n {formatDate(hackathon.endAt)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Users size={13} />{' '}\n {tr('technospam.hackathons.teamSize', 'Team of {{size}}', {\n size: hackathon.maxTeamSize,\n })}\n </span>\n </div>\n\n <div className=\"flex items-center gap-1.5 text-sm font-medium text-accent-teal\">\n <Award size={15} />{' '}\n {tr('technospam.hackathons.prizePool', '{{prize}} prize pool', {\n prize: formatMoney(hackathon.prizePool, hackathon.currency),\n })}\n </div>\n\n {hackathon.tags.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {hackathon.tags.slice(0, 4).map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-[11px]\">\n {t}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nexport function HackathonsHackathonsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const tr = useTr();\n const [status, setStatus] = useState<'ALL' | TecHackathonStatus>('ALL');\n const [search, setSearch] = useState('');\n const { limit, more } = usePageLimit();\n\n const statuses = useMemo(\n () => [\n { value: 'ALL' as const, label: tr('technospam.hackathons.filterAll', 'All') },\n {\n value: 'REGISTRATION_OPEN' as TecHackathonStatus,\n label: tr('technospam.hackathons.filterRegistrationOpen', 'Registration open'),\n },\n {\n value: 'IN_PROGRESS' as TecHackathonStatus,\n label: tr('technospam.hackathons.filterInProgress', 'In progress'),\n },\n {\n value: 'JUDGING' as TecHackathonStatus,\n label: tr('technospam.hackathons.filterJudging', 'Judging'),\n },\n {\n value: 'COMPLETED' as TecHackathonStatus,\n label: tr('technospam.hackathons.filterCompleted', 'Completed'),\n },\n ],\n [tr]\n );\n\n const { data, loading, error } = useHackathonsQuery({\n pagination: pageArg(limit),\n ...(status !== 'ALL' ? { status } : {}),\n });\n\n const allHackathons = data?.tecListHackathons?.items ?? [];\n const hasMore = data?.tecListHackathons?.pageInfo?.hasMore ?? false;\n const hackathons = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return allHackathons;\n return allHackathons.filter(\n (h) =>\n h.title.toLowerCase().includes(q) ||\n (h.theme ?? '').toLowerCase().includes(q) ||\n h.tags.some((t) => t.toLowerCase().includes(q))\n );\n }, [allHackathons, search]);\n const openCount = hackathons.filter((h) => h.status === 'REGISTRATION_OPEN').length;\n const totalPrize = hackathons.reduce((s, h) => s + h.prizePool, 0);\n const prizeCurrency = hackathons[0]?.currency ?? 'USD';\n\n return (\n <PageLayout\n hero\n title={tr('technospam.hackathons.title', 'Hackathons')}\n description={tr(\n 'technospam.hackathons.description',\n 'Compete, collaborate, and ship real projects with a team in a fixed window.'\n )}\n >\n <div className=\"mb-5 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <StatCard\n label={tr('technospam.hackathons.statHackathons', 'Hackathons')}\n value={hackathons.length}\n icon={Trophy}\n tone=\"purple\"\n />\n <StatCard\n label={tr('technospam.hackathons.statRegistrationOpen', 'Registration open')}\n value={openCount}\n icon={Sparkles}\n tone=\"green\"\n />\n <StatCard\n label={tr('technospam.hackathons.statTotalPrizePool', 'Total prize pool')}\n value={formatMoney(totalPrize, prizeCurrency)}\n icon={Award}\n tone=\"amber\"\n />\n </div>\n\n {/* The tabs filter one list, so that list is their tab panel: Radix points every\n trigger's aria-controls at a panel id, and without a TabsContent the id\n resolved to nothing (axe aria-valid-attr-value, critical; BOFF-3157). */}\n <Tabs\n className=\"gap-0\"\n value={status}\n onValueChange={(v) => setStatus(v as 'ALL' | TecHackathonStatus)}\n >\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <TabsList>\n {statuses.map((s) => (\n <TabsTrigger key={s.value} value={s.value}>\n {s.label}\n </TabsTrigger>\n ))}\n </TabsList>\n <div className=\"relative w-full sm:w-72\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted\"\n size={16}\n />\n <Input\n className=\"pl-9\"\n aria-label={tr('technospam.hackathons.searchLabel', 'Search hackathons')}\n placeholder={tr('technospam.hackathons.searchPlaceholder', 'Search hackathons…')}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onBlur={() => {\n const value = search.trim();\n if (value) {\n emit('technospam.search.performed', {\n workspaceId,\n entityType: 'hackathon',\n queryLength: value.length,\n });\n }\n }}\n />\n </div>\n </div>\n\n <TabsContent value={status} className={TAB_PANEL_FOCUS_CLASS}>\n {loading && !hackathons.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView\n title={tr('technospam.common.errorLoadHackathons', \"Couldn't load hackathons\")}\n error={error}\n />\n ) : hackathons.length === 0 ? (\n <EmptyView\n icon={<Trophy size={26} />}\n title={\n status !== 'ALL'\n ? tr('technospam.hackathons.emptyFilteredTitle', 'No hackathons in this stage')\n : tr('technospam.hackathons.emptyDefaultTitle', 'No hackathons yet')\n }\n description={\n status !== 'ALL'\n ? tr('technospam.hackathons.emptyFilteredDesc', 'Try a different stage filter.')\n : tr(\n 'technospam.hackathons.emptyDefaultDesc',\n 'Upcoming hackathons will appear here. Check back soon — TechnoSpam is pre-launch.'\n )\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {hackathons.map((hackathon) => (\n <HackathonCard\n key={hackathon.id}\n hackathon={hackathon}\n onOpen={() => {\n emit('technospam.hackathon.viewed', {\n workspaceId,\n entityId: hackathon.id,\n entityType: 'TEC_HACKATHON',\n });\n navigate(`/hackathons/hackathon-details-page?id=${hackathon.id}`);\n }}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </TabsContent>\n </Tabs>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmCA,SAAS,EAAc,EAAE,cAAW,aAA2D;CAC7F,IAAM,IAAK,GAAO;AAClB,QACE,kBAAC,GAAD;EAAW,WAAU;YAArB,CACE,kBAAC,GAAD;GAAY,QAAO;GAAO,MAAM,EAAU,SAAS,EAAU;GAAI,MAAM;aACrE,kBAAC,GAAD,EAAa,QAAQ,EAAU,QAAU,CAAA;GAC9B,CAAA,EACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACZ,kBAAC,GAAD;OAAwB;iBAAS,EAAU;OAAuB,CAAA;MAC/D,CAAA,EACJ,EAAU,QACT,kBAAC,KAAD;MAAG,WAAU;gBAAiD,EAAU;MAAU,CAAA,GAChF,KACA;;IAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACE,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA;;OAAE,EAAW,EAAU,QAAQ;OAAC;OAAG;OAC5D,EAAW,EAAU,MAAM;OACvB;SACP,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;OAAC;OACnB,EAAG,kCAAkC,oBAAoB,EACxD,MAAM,EAAU,aACjB,CAAC;OACG;QACH;;IAEN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;MAAC;MACnB,EAAG,mCAAmC,wBAAwB,EAC7D,OAAO,EAAY,EAAU,WAAW,EAAU,SAAS,EAC5D,CAAC;MACE;;IAEL,EAAU,KAAK,SACd,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAU,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAC/B,kBAAC,GAAD;MAAe,SAAQ;MAAY,WAAU;gBAC1C;MACK,EAFI,EAEJ,CACR;KACE,CAAA,GACJ;IACA;KACI;;;AAIhB,SAAgB,IAA+B;CAC7C,IAAM,IAAW,GAAuB,EAClC,EAAE,mBAAgB,GAAe,EACjC,EAAE,YAAS,GAAwB,EACnC,IAAK,GAAO,EACZ,CAAC,GAAQ,KAAa,EAAqC,MAAM,EACjE,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,EAAE,UAAO,YAAS,GAAc,EAEhC,IAAW,QACT;EACJ;GAAE,OAAO;GAAgB,OAAO,EAAG,mCAAmC,MAAM;GAAE;EAC9E;GACE,OAAO;GACP,OAAO,EAAG,gDAAgD,oBAAoB;GAC/E;EACD;GACE,OAAO;GACP,OAAO,EAAG,0CAA0C,cAAc;GACnE;EACD;GACE,OAAO;GACP,OAAO,EAAG,uCAAuC,UAAU;GAC5D;EACD;GACE,OAAO;GACP,OAAO,EAAG,yCAAyC,YAAY;GAChE;EACF,EACD,CAAC,EAAG,CACL,EAEK,EAAE,SAAM,YAAS,aAAU,EAAmB;EAClD,YAAY,EAAQ,EAAM;EAC1B,GAAI,MAAW,QAAqB,EAAE,GAAf,EAAE,WAAQ;EAClC,CAAC,EAEI,IAAgB,GAAM,mBAAmB,SAAS,EAAE,EACpD,IAAU,GAAM,mBAAmB,UAAU,WAAW,IACxD,IAAa,QAAc;EAC/B,IAAM,IAAI,EAAO,MAAM,CAAC,aAAa;AAErC,SADK,IACE,EAAc,QAClB,MACC,EAAE,MAAM,aAAa,CAAC,SAAS,EAAE,KAChC,EAAE,SAAS,IAAI,aAAa,CAAC,SAAS,EAAE,IACzC,EAAE,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC,SAAS,EAAE,CAAC,CAClD,GANc;IAOd,CAAC,GAAe,EAAO,CAAC,EACrB,IAAY,EAAW,QAAQ,MAAM,EAAE,WAAW,oBAAoB,CAAC,QACvE,IAAa,EAAW,QAAQ,GAAG,MAAM,IAAI,EAAE,WAAW,EAAE,EAC5D,IAAgB,EAAW,IAAI,YAAY;AAEjD,QACE,kBAAC,GAAD;EACE,MAAA;EACA,OAAO,EAAG,+BAA+B,aAAa;EACtD,aAAa,EACX,qCACA,8EACD;YANH,CAQE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,OAAO,EAAG,wCAAwC,aAAa;KAC/D,OAAO,EAAW;KAClB,MAAM;KACN,MAAK;KACL,CAAA;IACF,kBAAC,GAAD;KACE,OAAO,EAAG,8CAA8C,oBAAoB;KAC5E,OAAO;KACP,MAAM;KACN,MAAK;KACL,CAAA;IACF,kBAAC,GAAD;KACE,OAAO,EAAG,4CAA4C,mBAAmB;KACzE,OAAO,EAAY,GAAY,EAAc;KAC7C,MAAM;KACN,MAAK;KACL,CAAA;IACE;MAKN,kBAAC,GAAD;GACE,WAAU;GACV,OAAO;GACP,gBAAgB,MAAM,EAAU,EAAgC;aAHlE,CAKE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAA,UACG,EAAS,KAAK,MACb,kBAAC,GAAD;KAA2B,OAAO,EAAE;eACjC,EAAE;KACS,EAFI,EAAE,MAEN,CACd,EACO,CAAA,EACX,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,WAAU;MACV,MAAM;MACN,CAAA,EACF,kBAAC,GAAD;MACE,WAAU;MACV,cAAY,EAAG,qCAAqC,oBAAoB;MACxE,aAAa,EAAG,2CAA2C,qBAAqB;MAChF,OAAO;MACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;MAC1C,cAAc;OACZ,IAAM,IAAQ,EAAO,MAAM;AAC3B,OAAI,KACF,EAAK,+BAA+B;QAClC;QACA,YAAY;QACZ,aAAa,EAAM;QACpB,CAAC;;MAGN,CAAA,CACE;OACF;OAEN,kBAAC,GAAD;IAAa,OAAO;IAAQ,WAAW;cAAvC,CACG,KAAW,CAAC,EAAW,SACtB,kBAAC,GAAD,EAAe,CAAA,GACb,IACF,kBAAC,GAAD;KACE,OAAO,EAAG,yCAAyC,2BAA2B;KACvE;KACP,CAAA,GACA,EAAW,WAAW,IACxB,kBAAC,GAAD;KACE,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;KAC1B,OACE,MAAW,QAEP,EAAG,2CAA2C,oBAAoB,GADlE,EAAG,4CAA4C,8BAA8B;KAGnF,aACE,MAAW,QAEP,EACE,0CACA,oFACD,GAJD,EAAG,2CAA2C,gCAAgC;KAMpF,CAAA,GAEF,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAW,KAAK,MACf,kBAAC,GAAD;MAEa;MACX,cAAc;AAMZ,OALA,EAAK,+BAA+B;QAClC;QACA,UAAU,EAAU;QACpB,YAAY;QACb,CAAC,EACF,EAAS,yCAAyC,EAAU,KAAK;;MAEnE,EAVK,EAAU,GAUf,CACF;KACE,CAAA,EAER,kBAAC,GAAD;KAAmB;KAAkB;KAAS,SAAS;KAAQ,CAAA,CACnD;MACT;KACI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MentorshipMentorsPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/MentorshipMentorsPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MentorshipMentorsPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/MentorshipMentorsPagePage.tsx"],"names":[],"mappings":"AAsTA,wBAAgB,yBAAyB,gCAgLxC"}
|
|
@@ -31,6 +31,7 @@ function L({ mentor: e, size: t = "md" }) {
|
|
|
31
31
|
function R({ mentor: e, onOpen: t }) {
|
|
32
32
|
let n = r();
|
|
33
33
|
return /* @__PURE__ */ j(P, {
|
|
34
|
+
"data-testid": "mentor-card",
|
|
34
35
|
className: "group flex cursor-pointer flex-col gap-4 p-5 transition-all duration-200 hover:-translate-y-1 hover:shadow-lg",
|
|
35
36
|
onClick: t,
|
|
36
37
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MentorshipMentorsPagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipMentorsPagePage.tsx"],"sourcesContent":["import { createElement, useMemo, useState } from 'react';\nimport { Award, MessageSquare, Search, Sparkles, Star, UserPlus, Users, X } from 'lucide-react';\nimport { Badge, Button, GlassCard, Input, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n PageLayout,\n StatCard,\n coverGradient,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useBecomeMentor,\n useMentorsQuery,\n usePageLimit,\n type TecMentor,\n} from '../api/technospamApi';\nimport { formatMoneyFromMinorUnits } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport { notify } from '../lib/toast';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\nimport { useTr } from '../hooks/useTr';\n\n/** Circular gradient medallion standing in for a mentor avatar, with a live\n * \"accepting\" presence dot — mirrors the directory mockup within the dark theme. */\nfunction MentorMedallion({ mentor, size = 'md' }: { mentor: TecMentor; size?: 'md' | 'lg' }) {\n const box = size === 'lg' ? 'h-20 w-20' : 'h-16 w-16';\n return (\n <div className=\"relative shrink-0\">\n <span\n className={cn(\n 'flex items-center justify-center rounded-full bg-gradient-to-br text-white shadow-md ring-1 ring-white/15',\n box,\n coverGradient(mentor.headline)\n )}\n >\n {createElement(topicIcon(mentor.expertise.join(' ') || mentor.headline), {\n size: size === 'lg' ? 32 : 26,\n strokeWidth: 1.7,\n })}\n </span>\n {mentor.isAcceptingMentees ? (\n <span className=\"absolute -bottom-0.5 -right-0.5 h-4 w-4 rounded-full border-2 border-bg-surface bg-status-success-text\" />\n ) : null}\n </div>\n );\n}\n\nfunction MentorCard({ mentor, onOpen }: { mentor: TecMentor; onOpen: () => void }) {\n const tr = useTr();\n return (\n <GlassCard\n className=\"group flex cursor-pointer flex-col gap-4 p-5 transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\"\n onClick={onOpen}\n >\n <div className=\"flex items-start gap-4\">\n <MentorMedallion mentor={mentor} />\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-base font-semibold text-text-primary group-hover:text-accent-primary\">\n {mentor.headline}\n </h3>\n {mentor.role ? (\n <p className=\"mt-0.5 truncate text-xs font-medium text-text-secondary\">{mentor.role}</p>\n ) : null}\n {mentor.isAcceptingMentees ? (\n <Badge\n variant=\"outline\"\n className=\"mt-1.5 inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text\"\n >\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-success-text\" />{' '}\n {tr('technospam.common.acceptingMentees', 'Accepting mentees')}\n </Badge>\n ) : (\n <Badge\n variant=\"outline\"\n className=\"mt-1.5 border-border-seam bg-bg-sunken text-text-secondary\"\n >\n {tr('technospam.common.notAcceptingMentees', 'Not accepting')}\n </Badge>\n )}\n </div>\n </div>\n\n {mentor.bio ? <p className=\"line-clamp-2 text-sm text-text-secondary\">{mentor.bio}</p> : null}\n\n {mentor.expertise.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {mentor.expertise.slice(0, 4).map((skill) => (\n <Badge key={skill} variant=\"secondary\" className=\"text-[11px]\">\n {skill}\n </Badge>\n ))}\n {mentor.expertise.length > 4 ? (\n <span className=\"self-center text-xs text-text-muted\">\n +{mentor.expertise.length - 4}\n </span>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"mt-auto grid grid-cols-3 divide-x divide-border-seam rounded-xl border border-border-seam bg-bg-sunken text-center\">\n <div className=\"px-2 py-2.5\">\n <div className=\"flex items-center justify-center gap-1 text-sm font-semibold text-text-primary\">\n <Star size={13} className=\"text-accent-teal\" />\n {mentor.ratingAvg > 0 ? mentor.ratingAvg.toFixed(1) : 'New'}\n </div>\n <div className=\"text-[11px] text-text-muted\">\n {tr('technospam.common.rating', 'rating')}\n </div>\n </div>\n <div className=\"px-2 py-2.5\">\n <div className=\"text-sm font-semibold text-text-primary\">{mentor.sessionsCount}</div>\n <div className=\"text-[11px] text-text-muted\">\n {tr('technospam.common.sessions', 'sessions')}\n </div>\n </div>\n <div className=\"px-2 py-2.5\">\n <div className=\"text-sm font-semibold text-text-primary\">\n {formatMoneyFromMinorUnits(mentor.hourlyRate, mentor.currency)}\n </div>\n <div className=\"text-[11px] text-text-muted\">\n {tr('technospam.common.perHour', '/ hr')}\n </div>\n </div>\n </div>\n\n <Button\n className=\"w-full\"\n onClick={(e) => {\n e.stopPropagation();\n onOpen();\n }}\n >\n {tr('technospam.common.viewProfile', 'View profile')}\n </Button>\n </GlassCard>\n );\n}\n\nfunction BecomeMentorForm({\n onClose,\n onDone,\n workspaceId,\n}: {\n onClose: () => void;\n onDone: () => void;\n workspaceId?: string;\n}) {\n const [headline, setHeadline] = useState('');\n const [role, setRole] = useState('');\n const [bio, setBio] = useState('');\n const [expertise, setExpertise] = useState('');\n const [hourlyRate, setHourlyRate] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [becomeMentor, { loading }] = useBecomeMentor();\n const { emit } = useTechnoSpamAnalytics();\n\n const canSubmit = headline.trim().length > 0 && !loading;\n\n const handleSubmit = async () => {\n if (!canSubmit) return;\n const input: {\n headline: string;\n role?: string;\n bio?: string;\n expertise?: string[];\n hourlyRate?: number;\n currency?: string;\n } = { headline: headline.trim() };\n if (role.trim()) input.role = role.trim();\n if (bio.trim()) input.bio = bio.trim();\n const exp = expertise\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n if (exp.length) input.expertise = exp;\n // The form collects a dollars-and-cents rate (e.g. \"50\" or \"49.99\") but\n // TecMentor.hourlyRate is stored in the smallest currency unit (cents)\n // so BOFF-4433's fee math never loses precision to floating point --\n // convert here rather than storing the raw dollar figure as if it were\n // cents (which would under-charge/under-pay by 100x).\n const rateDollars = Number.parseFloat(hourlyRate);\n if (!Number.isNaN(rateDollars) && rateDollars >= 0) {\n input.hourlyRate = Math.round(rateDollars * 100);\n }\n if (currency.trim()) input.currency = currency.trim().toUpperCase();\n\n emit('technospam.mentor.become_mentor_clicked', { workspaceId });\n const res = await becomeMentor({ variables: { input } });\n if (res.data?.tecBecomeMentor) {\n emit('technospam.mentor.became_mentor', {\n workspaceId,\n entityId: res.data.tecBecomeMentor.id,\n entityType: 'TEC_MENTOR',\n });\n notify.success('Mentor profile created', 'Your profile is pending review.');\n onDone();\n }\n };\n\n return (\n <GlassCard className=\"mb-6 p-5\">\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-accent-primary to-accent-indigo text-white shadow-sm\">\n <UserPlus size={20} />\n </span>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Become a mentor</h2>\n <p className=\"text-sm text-text-secondary\">\n Share your expertise and start mentoring builders in the community.\n </p>\n </div>\n </div>\n <Button variant=\"ghost\" size=\"sm\" onClick={onClose} aria-label=\"Close\">\n <X size={16} />\n </Button>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Headline <span className=\"text-status-error-text\">*</span>\n </label>\n <Input\n placeholder=\"e.g. Staff Engineer · Distributed systems & career growth\"\n value={headline}\n onChange={(e) => setHeadline(e.target.value)}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Role & company\n </label>\n <Input\n placeholder=\"e.g. Staff Engineer @ Acme\"\n value={role}\n onChange={(e) => setRole(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n Shown as a subtitle under your headline. Optional.\n </p>\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Bio</label>\n <Textarea\n rows={3}\n placeholder=\"Tell mentees about your experience and how you can help.\"\n value={bio}\n onChange={(e) => setBio(e.target.value)}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Expertise</label>\n <Input\n placeholder=\"React, System design, Career coaching\"\n value={expertise}\n onChange={(e) => setExpertise(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">Comma-separated topics.</p>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Hourly rate\n </label>\n <Input\n type=\"number\"\n min={0}\n step={0.01}\n placeholder=\"0.00\"\n value={hourlyRate}\n onChange={(e) => setHourlyRate(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n Dollars per hour (e.g. 50 or 49.99). Leave 0 for free.\n </p>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Currency</label>\n <Input\n placeholder=\"USD\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value)}\n />\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button onClick={handleSubmit} disabled={!canSubmit}>\n <UserPlus size={16} /> {loading ? 'Submitting…' : 'Submit profile'}\n </Button>\n <Button variant=\"outline\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n </div>\n </div>\n </GlassCard>\n );\n}\n\nexport function MentorshipMentorsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser, workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const tr = useTr();\n const [search, setSearch] = useState('');\n const [showForm, setShowForm] = useState(false);\n\n const { limit, more } = usePageLimit();\n const { data, loading, error, refetch } = useMentorsQuery({\n status: 'ACTIVE',\n pagination: pageArg(limit),\n });\n\n const mentors = data?.tecListMentors?.items ?? [];\n const hasMore = data?.tecListMentors?.pageInfo?.hasMore ?? false;\n const userId = currentUser?.id;\n const alreadyMentor = Boolean(userId && mentors.some((m) => m.userId === userId));\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return mentors;\n return mentors.filter(\n (m) =>\n m.headline.toLowerCase().includes(q) ||\n m.expertise.some((skill) => skill.toLowerCase().includes(q))\n );\n }, [mentors, search]);\n\n const accepting = mentors.filter((m) => m.isAcceptingMentees).length;\n const totalSessions = mentors.reduce((s, m) => s + m.sessionsCount, 0);\n const rated = mentors.filter((m) => m.ratingAvg > 0);\n const avgRating = rated.length\n ? (rated.reduce((s, m) => s + m.ratingAvg, 0) / rated.length).toFixed(1)\n : '—';\n\n return (\n <PageLayout\n hero\n title={tr('technospam.mentorship.findAMentorTitle', 'Find a Mentor')}\n description={tr(\n 'technospam.mentorship.description',\n 'Connect with experienced builders for 1:1 guidance, code review, and career coaching.'\n )}\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/sessions-page')}>\n <MessageSquare size={16} /> {tr('technospam.common.mySessions', 'My sessions')}\n </Button>\n }\n >\n {alreadyMentor ? (\n <GlassCard className=\"mb-6 flex items-center gap-3 p-4\">\n <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-status-success-bg-subtle text-status-success-text\">\n <Award size={20} />\n </span>\n <div>\n <div className=\"text-sm font-semibold text-text-primary\">You're a mentor</div>\n <div className=\"text-xs text-text-secondary\">\n Your mentor profile is live. Mentees can request sessions with you.\n </div>\n </div>\n </GlassCard>\n ) : showForm ? (\n <BecomeMentorForm\n onClose={() => setShowForm(false)}\n onDone={() => {\n setShowForm(false);\n void refetch();\n }}\n workspaceId={workspaceId}\n />\n ) : null}\n\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard\n label={tr('technospam.mentorship.statMentors', 'Mentors')}\n value={mentors.length}\n icon={Users}\n tone=\"blue\"\n />\n <StatCard\n label={tr('technospam.mentorship.statAcceptingMentees', 'Accepting mentees')}\n value={accepting}\n icon={Sparkles}\n tone=\"green\"\n />\n <StatCard\n label={tr('technospam.mentorship.statAvgRating', 'Avg rating')}\n value={avgRating}\n icon={Star}\n tone=\"amber\"\n />\n <StatCard\n label={tr('technospam.mentorship.statTotalSessions', 'Total sessions')}\n value={totalSessions}\n icon={MessageSquare}\n tone=\"purple\"\n />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"relative w-full sm:w-80\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted\"\n size={16}\n />\n <Input\n className=\"pl-9\"\n aria-label={tr('technospam.mentorship.searchLabel', 'Search mentors')}\n placeholder={tr(\n 'technospam.mentorship.searchPlaceholder',\n 'Search by headline or expertise…'\n )}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n {!alreadyMentor && !showForm ? (\n <Button onClick={() => setShowForm(true)}>\n <UserPlus size={16} /> {tr('technospam.common.becomeAMentor', 'Become a mentor')}\n </Button>\n ) : null}\n </div>\n\n {loading && !mentors.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView\n title={tr('technospam.common.errorLoadMentors', \"Couldn't load mentors\")}\n error={error}\n />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<Users size={26} />}\n title={\n search\n ? tr('technospam.mentorship.emptySearchTitle', 'No matching mentors')\n : tr('technospam.mentorship.emptyDefaultTitle', 'No mentors yet')\n }\n description={\n search\n ? tr('technospam.mentorship.emptySearchDesc', 'Try a different search term.')\n : tr(\n 'technospam.mentorship.emptyDefaultDesc',\n 'Active mentors will appear here. TechnoSpam is pre-launch — be one of the first to sign up.'\n )\n }\n action={\n !search && !alreadyMentor ? (\n <Button onClick={() => setShowForm(true)}>\n {tr('technospam.common.becomeAMentor', 'Become a mentor')}\n </Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((mentor) => (\n <MentorCard\n key={mentor.id}\n mentor={mentor}\n onOpen={() => {\n emit('technospam.mentor.viewed', {\n workspaceId,\n entityId: mentor.id,\n entityType: 'TEC_MENTOR',\n });\n navigate(`/mentorship/mentor-profile-page?id=${mentor.id}`);\n }}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MentorshipMentorsPagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipMentorsPagePage.tsx"],"sourcesContent":["import { createElement, useMemo, useState } from 'react';\nimport { Award, MessageSquare, Search, Sparkles, Star, UserPlus, Users, X } from 'lucide-react';\nimport { Badge, Button, GlassCard, Input, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n PageLayout,\n StatCard,\n coverGradient,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useBecomeMentor,\n useMentorsQuery,\n usePageLimit,\n type TecMentor,\n} from '../api/technospamApi';\nimport { formatMoneyFromMinorUnits } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport { notify } from '../lib/toast';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\nimport { useTr } from '../hooks/useTr';\n\n/** Circular gradient medallion standing in for a mentor avatar, with a live\n * \"accepting\" presence dot — mirrors the directory mockup within the dark theme. */\nfunction MentorMedallion({ mentor, size = 'md' }: { mentor: TecMentor; size?: 'md' | 'lg' }) {\n const box = size === 'lg' ? 'h-20 w-20' : 'h-16 w-16';\n return (\n <div className=\"relative shrink-0\">\n <span\n className={cn(\n 'flex items-center justify-center rounded-full bg-gradient-to-br text-white shadow-md ring-1 ring-white/15',\n box,\n coverGradient(mentor.headline)\n )}\n >\n {createElement(topicIcon(mentor.expertise.join(' ') || mentor.headline), {\n size: size === 'lg' ? 32 : 26,\n strokeWidth: 1.7,\n })}\n </span>\n {mentor.isAcceptingMentees ? (\n <span className=\"absolute -bottom-0.5 -right-0.5 h-4 w-4 rounded-full border-2 border-bg-surface bg-status-success-text\" />\n ) : null}\n </div>\n );\n}\n\nfunction MentorCard({ mentor, onOpen }: { mentor: TecMentor; onOpen: () => void }) {\n const tr = useTr();\n return (\n <GlassCard\n data-testid=\"mentor-card\"\n className=\"group flex cursor-pointer flex-col gap-4 p-5 transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\"\n onClick={onOpen}\n >\n <div className=\"flex items-start gap-4\">\n <MentorMedallion mentor={mentor} />\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-base font-semibold text-text-primary group-hover:text-accent-primary\">\n {mentor.headline}\n </h3>\n {mentor.role ? (\n <p className=\"mt-0.5 truncate text-xs font-medium text-text-secondary\">{mentor.role}</p>\n ) : null}\n {mentor.isAcceptingMentees ? (\n <Badge\n variant=\"outline\"\n className=\"mt-1.5 inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text\"\n >\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-success-text\" />{' '}\n {tr('technospam.common.acceptingMentees', 'Accepting mentees')}\n </Badge>\n ) : (\n <Badge\n variant=\"outline\"\n className=\"mt-1.5 border-border-seam bg-bg-sunken text-text-secondary\"\n >\n {tr('technospam.common.notAcceptingMentees', 'Not accepting')}\n </Badge>\n )}\n </div>\n </div>\n\n {mentor.bio ? <p className=\"line-clamp-2 text-sm text-text-secondary\">{mentor.bio}</p> : null}\n\n {mentor.expertise.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {mentor.expertise.slice(0, 4).map((skill) => (\n <Badge key={skill} variant=\"secondary\" className=\"text-[11px]\">\n {skill}\n </Badge>\n ))}\n {mentor.expertise.length > 4 ? (\n <span className=\"self-center text-xs text-text-muted\">\n +{mentor.expertise.length - 4}\n </span>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"mt-auto grid grid-cols-3 divide-x divide-border-seam rounded-xl border border-border-seam bg-bg-sunken text-center\">\n <div className=\"px-2 py-2.5\">\n <div className=\"flex items-center justify-center gap-1 text-sm font-semibold text-text-primary\">\n <Star size={13} className=\"text-accent-teal\" />\n {mentor.ratingAvg > 0 ? mentor.ratingAvg.toFixed(1) : 'New'}\n </div>\n <div className=\"text-[11px] text-text-muted\">\n {tr('technospam.common.rating', 'rating')}\n </div>\n </div>\n <div className=\"px-2 py-2.5\">\n <div className=\"text-sm font-semibold text-text-primary\">{mentor.sessionsCount}</div>\n <div className=\"text-[11px] text-text-muted\">\n {tr('technospam.common.sessions', 'sessions')}\n </div>\n </div>\n <div className=\"px-2 py-2.5\">\n <div className=\"text-sm font-semibold text-text-primary\">\n {formatMoneyFromMinorUnits(mentor.hourlyRate, mentor.currency)}\n </div>\n <div className=\"text-[11px] text-text-muted\">\n {tr('technospam.common.perHour', '/ hr')}\n </div>\n </div>\n </div>\n\n <Button\n className=\"w-full\"\n onClick={(e) => {\n e.stopPropagation();\n onOpen();\n }}\n >\n {tr('technospam.common.viewProfile', 'View profile')}\n </Button>\n </GlassCard>\n );\n}\n\nfunction BecomeMentorForm({\n onClose,\n onDone,\n workspaceId,\n}: {\n onClose: () => void;\n onDone: () => void;\n workspaceId?: string;\n}) {\n const [headline, setHeadline] = useState('');\n const [role, setRole] = useState('');\n const [bio, setBio] = useState('');\n const [expertise, setExpertise] = useState('');\n const [hourlyRate, setHourlyRate] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [becomeMentor, { loading }] = useBecomeMentor();\n const { emit } = useTechnoSpamAnalytics();\n\n const canSubmit = headline.trim().length > 0 && !loading;\n\n const handleSubmit = async () => {\n if (!canSubmit) return;\n const input: {\n headline: string;\n role?: string;\n bio?: string;\n expertise?: string[];\n hourlyRate?: number;\n currency?: string;\n } = { headline: headline.trim() };\n if (role.trim()) input.role = role.trim();\n if (bio.trim()) input.bio = bio.trim();\n const exp = expertise\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n if (exp.length) input.expertise = exp;\n // The form collects a dollars-and-cents rate (e.g. \"50\" or \"49.99\") but\n // TecMentor.hourlyRate is stored in the smallest currency unit (cents)\n // so BOFF-4433's fee math never loses precision to floating point --\n // convert here rather than storing the raw dollar figure as if it were\n // cents (which would under-charge/under-pay by 100x).\n const rateDollars = Number.parseFloat(hourlyRate);\n if (!Number.isNaN(rateDollars) && rateDollars >= 0) {\n input.hourlyRate = Math.round(rateDollars * 100);\n }\n if (currency.trim()) input.currency = currency.trim().toUpperCase();\n\n emit('technospam.mentor.become_mentor_clicked', { workspaceId });\n const res = await becomeMentor({ variables: { input } });\n if (res.data?.tecBecomeMentor) {\n emit('technospam.mentor.became_mentor', {\n workspaceId,\n entityId: res.data.tecBecomeMentor.id,\n entityType: 'TEC_MENTOR',\n });\n notify.success('Mentor profile created', 'Your profile is pending review.');\n onDone();\n }\n };\n\n return (\n <GlassCard className=\"mb-6 p-5\">\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-accent-primary to-accent-indigo text-white shadow-sm\">\n <UserPlus size={20} />\n </span>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Become a mentor</h2>\n <p className=\"text-sm text-text-secondary\">\n Share your expertise and start mentoring builders in the community.\n </p>\n </div>\n </div>\n <Button variant=\"ghost\" size=\"sm\" onClick={onClose} aria-label=\"Close\">\n <X size={16} />\n </Button>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Headline <span className=\"text-status-error-text\">*</span>\n </label>\n <Input\n placeholder=\"e.g. Staff Engineer · Distributed systems & career growth\"\n value={headline}\n onChange={(e) => setHeadline(e.target.value)}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Role & company\n </label>\n <Input\n placeholder=\"e.g. Staff Engineer @ Acme\"\n value={role}\n onChange={(e) => setRole(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n Shown as a subtitle under your headline. Optional.\n </p>\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Bio</label>\n <Textarea\n rows={3}\n placeholder=\"Tell mentees about your experience and how you can help.\"\n value={bio}\n onChange={(e) => setBio(e.target.value)}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Expertise</label>\n <Input\n placeholder=\"React, System design, Career coaching\"\n value={expertise}\n onChange={(e) => setExpertise(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">Comma-separated topics.</p>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Hourly rate\n </label>\n <Input\n type=\"number\"\n min={0}\n step={0.01}\n placeholder=\"0.00\"\n value={hourlyRate}\n onChange={(e) => setHourlyRate(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n Dollars per hour (e.g. 50 or 49.99). Leave 0 for free.\n </p>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Currency</label>\n <Input\n placeholder=\"USD\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value)}\n />\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button onClick={handleSubmit} disabled={!canSubmit}>\n <UserPlus size={16} /> {loading ? 'Submitting…' : 'Submit profile'}\n </Button>\n <Button variant=\"outline\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n </div>\n </div>\n </GlassCard>\n );\n}\n\nexport function MentorshipMentorsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser, workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const tr = useTr();\n const [search, setSearch] = useState('');\n const [showForm, setShowForm] = useState(false);\n\n const { limit, more } = usePageLimit();\n const { data, loading, error, refetch } = useMentorsQuery({\n status: 'ACTIVE',\n pagination: pageArg(limit),\n });\n\n const mentors = data?.tecListMentors?.items ?? [];\n const hasMore = data?.tecListMentors?.pageInfo?.hasMore ?? false;\n const userId = currentUser?.id;\n const alreadyMentor = Boolean(userId && mentors.some((m) => m.userId === userId));\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return mentors;\n return mentors.filter(\n (m) =>\n m.headline.toLowerCase().includes(q) ||\n m.expertise.some((skill) => skill.toLowerCase().includes(q))\n );\n }, [mentors, search]);\n\n const accepting = mentors.filter((m) => m.isAcceptingMentees).length;\n const totalSessions = mentors.reduce((s, m) => s + m.sessionsCount, 0);\n const rated = mentors.filter((m) => m.ratingAvg > 0);\n const avgRating = rated.length\n ? (rated.reduce((s, m) => s + m.ratingAvg, 0) / rated.length).toFixed(1)\n : '—';\n\n return (\n <PageLayout\n hero\n title={tr('technospam.mentorship.findAMentorTitle', 'Find a Mentor')}\n description={tr(\n 'technospam.mentorship.description',\n 'Connect with experienced builders for 1:1 guidance, code review, and career coaching.'\n )}\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/sessions-page')}>\n <MessageSquare size={16} /> {tr('technospam.common.mySessions', 'My sessions')}\n </Button>\n }\n >\n {alreadyMentor ? (\n <GlassCard className=\"mb-6 flex items-center gap-3 p-4\">\n <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-status-success-bg-subtle text-status-success-text\">\n <Award size={20} />\n </span>\n <div>\n <div className=\"text-sm font-semibold text-text-primary\">You're a mentor</div>\n <div className=\"text-xs text-text-secondary\">\n Your mentor profile is live. Mentees can request sessions with you.\n </div>\n </div>\n </GlassCard>\n ) : showForm ? (\n <BecomeMentorForm\n onClose={() => setShowForm(false)}\n onDone={() => {\n setShowForm(false);\n void refetch();\n }}\n workspaceId={workspaceId}\n />\n ) : null}\n\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard\n label={tr('technospam.mentorship.statMentors', 'Mentors')}\n value={mentors.length}\n icon={Users}\n tone=\"blue\"\n />\n <StatCard\n label={tr('technospam.mentorship.statAcceptingMentees', 'Accepting mentees')}\n value={accepting}\n icon={Sparkles}\n tone=\"green\"\n />\n <StatCard\n label={tr('technospam.mentorship.statAvgRating', 'Avg rating')}\n value={avgRating}\n icon={Star}\n tone=\"amber\"\n />\n <StatCard\n label={tr('technospam.mentorship.statTotalSessions', 'Total sessions')}\n value={totalSessions}\n icon={MessageSquare}\n tone=\"purple\"\n />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"relative w-full sm:w-80\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted\"\n size={16}\n />\n <Input\n className=\"pl-9\"\n aria-label={tr('technospam.mentorship.searchLabel', 'Search mentors')}\n placeholder={tr(\n 'technospam.mentorship.searchPlaceholder',\n 'Search by headline or expertise…'\n )}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n {!alreadyMentor && !showForm ? (\n <Button onClick={() => setShowForm(true)}>\n <UserPlus size={16} /> {tr('technospam.common.becomeAMentor', 'Become a mentor')}\n </Button>\n ) : null}\n </div>\n\n {loading && !mentors.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView\n title={tr('technospam.common.errorLoadMentors', \"Couldn't load mentors\")}\n error={error}\n />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<Users size={26} />}\n title={\n search\n ? tr('technospam.mentorship.emptySearchTitle', 'No matching mentors')\n : tr('technospam.mentorship.emptyDefaultTitle', 'No mentors yet')\n }\n description={\n search\n ? tr('technospam.mentorship.emptySearchDesc', 'Try a different search term.')\n : tr(\n 'technospam.mentorship.emptyDefaultDesc',\n 'Active mentors will appear here. TechnoSpam is pre-launch — be one of the first to sign up.'\n )\n }\n action={\n !search && !alreadyMentor ? (\n <Button onClick={() => setShowForm(true)}>\n {tr('technospam.common.becomeAMentor', 'Become a mentor')}\n </Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((mentor) => (\n <MentorCard\n key={mentor.id}\n mentor={mentor}\n onOpen={() => {\n emit('technospam.mentor.viewed', {\n workspaceId,\n entityId: mentor.id,\n entityType: 'TEC_MENTOR',\n });\n navigate(`/mentorship/mentor-profile-page?id=${mentor.id}`);\n }}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|