@burdenoff/microfe-subscriberbot 2026.801.1 → 2026.829.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/subscriberbot/admin/AdminDashboardPage.d.ts.map +1 -1
- package/dist/subscriberbot/admin/AdminDashboardPage.js +80 -83
- package/dist/subscriberbot/admin/AdminDashboardPage.js.map +1 -1
- package/dist/subscriberbot/components/viz.js +51 -27
- package/dist/subscriberbot/components/viz.js.map +1 -1
- package/dist/subscriberbot/hooks/index.d.ts +2 -1
- package/dist/subscriberbot/hooks/index.d.ts.map +1 -1
- package/dist/subscriberbot/hooks/index.js +1 -0
- package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts +12 -1
- package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts.map +1 -1
- package/dist/subscriberbot/hooks/useSubscriberBotApi.js +82 -56
- package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
- package/dist/subscriberbot/hooks/useTr.d.ts +17 -0
- package/dist/subscriberbot/hooks/useTr.d.ts.map +1 -0
- package/dist/subscriberbot/hooks/useTr.js +14 -0
- package/dist/subscriberbot/hooks/useTr.js.map +1 -0
- package/dist/subscriberbot/pages/AssetVaultPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/AssetVaultPage.js +155 -97
- package/dist/subscriberbot/pages/AssetVaultPage.js.map +1 -1
- package/dist/subscriberbot/pages/DashboardPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/DashboardPage.js +113 -105
- package/dist/subscriberbot/pages/DashboardPage.js.map +1 -1
- package/dist/subscriberbot/pages/InboxPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/InboxPage.js +404 -369
- package/dist/subscriberbot/pages/InboxPage.js.map +1 -1
- package/dist/subscriberbot/pages/InsightsPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/InsightsPage.js +94 -93
- package/dist/subscriberbot/pages/InsightsPage.js.map +1 -1
- package/dist/subscriberbot/pages/InvoicesPage.d.ts +3 -2
- package/dist/subscriberbot/pages/InvoicesPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/InvoicesPage.js +368 -362
- package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -1
- package/dist/subscriberbot/pages/WorkflowsPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/WorkflowsPage.js +209 -193
- package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -1
- package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts +3 -1
- package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/agents/AgentDetailPage.js +296 -228
- package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
- package/dist/subscriberbot/pages/agents/AgentNewPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/agents/AgentNewPage.js +96 -76
- package/dist/subscriberbot/pages/agents/AgentNewPage.js.map +1 -1
- package/dist/subscriberbot/pages/agents/AgentsListPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/agents/AgentsListPage.js +145 -161
- package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -1
- package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts +4 -2
- package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +577 -402
- package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -1
- package/dist/subscriberbot/pages/providers/ProviderNewPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/providers/ProviderNewPage.js +167 -129
- package/dist/subscriberbot/pages/providers/ProviderNewPage.js.map +1 -1
- package/dist/subscriberbot/pages/providers/ProvidersListPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/providers/ProvidersListPage.js +171 -218
- package/dist/subscriberbot/pages/providers/ProvidersListPage.js.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +340 -279
- package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipNewPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +185 -166
- package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipsListPage.d.ts.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js +153 -182
- package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js.map +1 -1
- package/dist/subscriberbot/types/index.d.ts +37 -0
- package/dist/subscriberbot/types/index.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -3,12 +3,13 @@ import { cn as t } from "../../utils/cn.js";
|
|
|
3
3
|
import { PageLayout as n } from "../../components/PageLayout.js";
|
|
4
4
|
import { formatEnumLabel as r } from "../../utils/formatters.js";
|
|
5
5
|
import { useCreateProvider as i } from "../../hooks/useSubscriberBotApi.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { useTr as a } from "../../hooks/useTr.js";
|
|
7
|
+
import { useState as o } from "react";
|
|
8
|
+
import { ArrowLeft as s, Building2 as c, Sparkles as l } from "lucide-react";
|
|
9
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
10
|
+
import { GlassCard as f, PagePurpose as p } from "@burdenoff/fe-libs/ui";
|
|
10
11
|
//#region src/subscriberbot/pages/providers/ProviderNewPage.tsx
|
|
11
|
-
var
|
|
12
|
+
var m = [
|
|
12
13
|
"SAAS",
|
|
13
14
|
"AI_SERVICE",
|
|
14
15
|
"STREAMING",
|
|
@@ -25,213 +26,250 @@ var p = [
|
|
|
25
26
|
"LICENSE",
|
|
26
27
|
"CONTRACT",
|
|
27
28
|
"OTHER"
|
|
28
|
-
],
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
], h = {
|
|
30
|
+
SAAS: "providers.categories.saas",
|
|
31
|
+
AI_SERVICE: "providers.categories.aiService",
|
|
32
|
+
STREAMING: "providers.categories.streaming",
|
|
33
|
+
NEWSLETTER: "providers.categories.newsletter",
|
|
34
|
+
NEWS_DIGEST: "providers.categories.newsDigest",
|
|
35
|
+
MEMBERSHIP: "providers.categories.membership",
|
|
36
|
+
COMMUNITY: "providers.categories.community",
|
|
37
|
+
EDUCATION: "providers.categories.education",
|
|
38
|
+
FINANCIAL: "providers.categories.financial",
|
|
39
|
+
INSURANCE: "providers.categories.insurance",
|
|
40
|
+
TELECOM: "providers.categories.telecom",
|
|
41
|
+
UTILITY: "providers.categories.utility",
|
|
42
|
+
ASSOCIATION: "providers.categories.association",
|
|
43
|
+
LICENSE: "providers.categories.license",
|
|
44
|
+
CONTRACT: "providers.categories.contract",
|
|
45
|
+
OTHER: "providers.categories.other"
|
|
46
|
+
}, g = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]", _ = "mb-1 block text-xs font-medium text-text-secondary";
|
|
47
|
+
function v() {
|
|
48
|
+
let v = a(), { navigateTo: y } = e(), b = i(), [x, S] = o(""), [C, w] = o("SAAS"), [T, E] = o(""), [D, O] = o(""), [k, A] = o(""), [j, M] = o(""), [N, P] = o(""), [F, I] = o(null), L = N.split(",").map((e) => e.trim()).filter(Boolean);
|
|
49
|
+
return /* @__PURE__ */ d(n, {
|
|
50
|
+
title: v("providers.new.title", "Add provider"),
|
|
51
|
+
description: v("providers.new.description", "Register a new provider in the registry"),
|
|
52
|
+
actions: /* @__PURE__ */ d("button", {
|
|
35
53
|
type: "button",
|
|
36
|
-
onClick: () =>
|
|
54
|
+
onClick: () => y("/providers"),
|
|
37
55
|
className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
|
|
38
|
-
children: [
|
|
56
|
+
children: [
|
|
57
|
+
/* @__PURE__ */ u(s, { className: "h-4 w-4" }),
|
|
58
|
+
" ",
|
|
59
|
+
v("providers.new.back", "Back")
|
|
60
|
+
]
|
|
39
61
|
}),
|
|
40
|
-
children: [/* @__PURE__ */
|
|
62
|
+
children: [/* @__PURE__ */ u(p, {
|
|
41
63
|
className: "mb-6",
|
|
42
|
-
children: "Add a provider that isn't in the registry yet so you can attach relationships, plans and assets to it."
|
|
43
|
-
}), /* @__PURE__ */
|
|
64
|
+
children: v("providers.new.purpose", "Add a provider that isn't in the registry yet so you can attach relationships, plans and assets to it.")
|
|
65
|
+
}), /* @__PURE__ */ d("div", {
|
|
44
66
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
45
|
-
children: [/* @__PURE__ */
|
|
67
|
+
children: [/* @__PURE__ */ u(f, {
|
|
46
68
|
treatment: "metric",
|
|
47
69
|
className: "p-6 lg:col-span-2",
|
|
48
|
-
children: /* @__PURE__ */
|
|
70
|
+
children: /* @__PURE__ */ d("form", {
|
|
49
71
|
onSubmit: (e) => {
|
|
50
|
-
if (e.preventDefault(),
|
|
51
|
-
|
|
72
|
+
if (e.preventDefault(), I(null), !x.trim()) {
|
|
73
|
+
I(v("providers.new.nameRequired", "A provider name is required."));
|
|
52
74
|
return;
|
|
53
75
|
}
|
|
54
76
|
let t = {
|
|
55
|
-
name:
|
|
56
|
-
category:
|
|
57
|
-
...
|
|
58
|
-
...
|
|
59
|
-
...
|
|
60
|
-
...
|
|
61
|
-
...
|
|
77
|
+
name: x.trim(),
|
|
78
|
+
category: C,
|
|
79
|
+
...T.trim() ? { description: T.trim() } : {},
|
|
80
|
+
...D.trim() ? { websiteUrl: D.trim() } : {},
|
|
81
|
+
...k.trim() ? { region: k.trim() } : {},
|
|
82
|
+
...j.trim() ? { industry: j.trim() } : {},
|
|
83
|
+
...L.length ? { tags: L } : {}
|
|
62
84
|
};
|
|
63
|
-
|
|
64
|
-
onSuccess: (e) =>
|
|
65
|
-
onError: (e) =>
|
|
85
|
+
b.mutate(t, {
|
|
86
|
+
onSuccess: (e) => y(`/providers/${e.id}`),
|
|
87
|
+
onError: (e) => I(e instanceof Error ? e.message : v("providers.new.error", "Could not create provider."))
|
|
66
88
|
});
|
|
67
89
|
},
|
|
68
90
|
className: "space-y-5",
|
|
69
91
|
children: [
|
|
70
|
-
|
|
92
|
+
F && /* @__PURE__ */ u("div", {
|
|
71
93
|
className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
|
|
72
|
-
children:
|
|
94
|
+
children: F
|
|
73
95
|
}),
|
|
74
|
-
/* @__PURE__ */
|
|
96
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("label", {
|
|
75
97
|
htmlFor: "prov-name",
|
|
76
|
-
className:
|
|
77
|
-
children: [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
98
|
+
className: _,
|
|
99
|
+
children: [
|
|
100
|
+
v("providers.new.nameLabel", "Name"),
|
|
101
|
+
" ",
|
|
102
|
+
/* @__PURE__ */ u("span", {
|
|
103
|
+
className: "text-status-error-text",
|
|
104
|
+
children: "*"
|
|
105
|
+
})
|
|
106
|
+
]
|
|
107
|
+
}), /* @__PURE__ */ u("input", {
|
|
82
108
|
id: "prov-name",
|
|
83
109
|
type: "text",
|
|
84
|
-
value:
|
|
85
|
-
onChange: (e) =>
|
|
86
|
-
placeholder: "e.g. OpenAI, Netflix, AWS",
|
|
87
|
-
className:
|
|
110
|
+
value: x,
|
|
111
|
+
onChange: (e) => S(e.target.value),
|
|
112
|
+
placeholder: v("providers.new.namePlaceholder", "e.g. OpenAI, Netflix, AWS"),
|
|
113
|
+
className: g,
|
|
88
114
|
required: !0
|
|
89
115
|
})] }),
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
className:
|
|
92
|
-
children: "Category"
|
|
93
|
-
}), /* @__PURE__ */
|
|
116
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("span", {
|
|
117
|
+
className: _,
|
|
118
|
+
children: v("providers.new.categoryLabel", "Category")
|
|
119
|
+
}), /* @__PURE__ */ u("div", {
|
|
94
120
|
className: "flex flex-wrap gap-2",
|
|
95
121
|
role: "group",
|
|
96
|
-
"aria-label": "
|
|
97
|
-
children:
|
|
98
|
-
let n =
|
|
99
|
-
return /* @__PURE__ */
|
|
122
|
+
"aria-label": v("providers.new.categoryLabel", "Category"),
|
|
123
|
+
children: m.map((e) => {
|
|
124
|
+
let n = C === e;
|
|
125
|
+
return /* @__PURE__ */ u("button", {
|
|
100
126
|
type: "button",
|
|
101
127
|
"aria-pressed": n,
|
|
102
|
-
onClick: () =>
|
|
128
|
+
onClick: () => w(e),
|
|
103
129
|
className: t("rounded-full border px-3 py-1.5 text-xs font-medium transition-colors", n ? "border-transparent bg-action-primary-bg text-action-primary-text" : "border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary"),
|
|
104
|
-
children: r(e)
|
|
130
|
+
children: v(h[e], r(e))
|
|
105
131
|
}, e);
|
|
106
132
|
})
|
|
107
133
|
})] }),
|
|
108
|
-
/* @__PURE__ */
|
|
134
|
+
/* @__PURE__ */ d("div", {
|
|
109
135
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
110
|
-
children: [/* @__PURE__ */
|
|
136
|
+
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("label", {
|
|
111
137
|
htmlFor: "prov-website",
|
|
112
|
-
className:
|
|
113
|
-
children: "Website"
|
|
114
|
-
}), /* @__PURE__ */
|
|
138
|
+
className: _,
|
|
139
|
+
children: v("providers.new.websiteLabel", "Website")
|
|
140
|
+
}), /* @__PURE__ */ u("input", {
|
|
115
141
|
id: "prov-website",
|
|
116
142
|
type: "url",
|
|
117
|
-
value:
|
|
118
|
-
onChange: (e) =>
|
|
119
|
-
placeholder: "https://…",
|
|
120
|
-
className:
|
|
121
|
-
})] }), /* @__PURE__ */
|
|
143
|
+
value: D,
|
|
144
|
+
onChange: (e) => O(e.target.value),
|
|
145
|
+
placeholder: v("providers.new.websitePlaceholder", "https://…"),
|
|
146
|
+
className: g
|
|
147
|
+
})] }), /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("label", {
|
|
122
148
|
htmlFor: "prov-region",
|
|
123
|
-
className:
|
|
124
|
-
children: "Region"
|
|
125
|
-
}), /* @__PURE__ */
|
|
149
|
+
className: _,
|
|
150
|
+
children: v("providers.new.regionLabel", "Region")
|
|
151
|
+
}), /* @__PURE__ */ u("input", {
|
|
126
152
|
id: "prov-region",
|
|
127
153
|
type: "text",
|
|
128
|
-
value:
|
|
129
|
-
onChange: (e) =>
|
|
130
|
-
placeholder: "e.g. Global, US, EU",
|
|
131
|
-
className:
|
|
154
|
+
value: k,
|
|
155
|
+
onChange: (e) => A(e.target.value),
|
|
156
|
+
placeholder: v("providers.new.regionPlaceholder", "e.g. Global, US, EU"),
|
|
157
|
+
className: g
|
|
132
158
|
})] })]
|
|
133
159
|
}),
|
|
134
|
-
/* @__PURE__ */
|
|
160
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("label", {
|
|
135
161
|
htmlFor: "prov-industry",
|
|
136
|
-
className:
|
|
137
|
-
children: "Industry"
|
|
138
|
-
}), /* @__PURE__ */
|
|
162
|
+
className: _,
|
|
163
|
+
children: v("providers.new.industryLabel", "Industry")
|
|
164
|
+
}), /* @__PURE__ */ u("input", {
|
|
139
165
|
id: "prov-industry",
|
|
140
166
|
type: "text",
|
|
141
|
-
value:
|
|
142
|
-
onChange: (e) =>
|
|
143
|
-
placeholder: "e.g. Cloud, Media",
|
|
144
|
-
className:
|
|
167
|
+
value: j,
|
|
168
|
+
onChange: (e) => M(e.target.value),
|
|
169
|
+
placeholder: v("providers.new.industryPlaceholder", "e.g. Cloud, Media"),
|
|
170
|
+
className: g
|
|
145
171
|
})] }),
|
|
146
|
-
/* @__PURE__ */
|
|
172
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("label", {
|
|
147
173
|
htmlFor: "prov-desc",
|
|
148
|
-
className:
|
|
149
|
-
children: "Description"
|
|
150
|
-
}), /* @__PURE__ */
|
|
174
|
+
className: _,
|
|
175
|
+
children: v("providers.new.descriptionLabel", "Description")
|
|
176
|
+
}), /* @__PURE__ */ u("textarea", {
|
|
151
177
|
id: "prov-desc",
|
|
152
|
-
value:
|
|
153
|
-
onChange: (e) =>
|
|
178
|
+
value: T,
|
|
179
|
+
onChange: (e) => E(e.target.value),
|
|
154
180
|
rows: 3,
|
|
155
|
-
placeholder: "What does this provider offer?",
|
|
156
|
-
className:
|
|
181
|
+
placeholder: v("providers.new.descriptionPlaceholder", "What does this provider offer?"),
|
|
182
|
+
className: g
|
|
157
183
|
})] }),
|
|
158
|
-
/* @__PURE__ */
|
|
184
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("label", {
|
|
159
185
|
htmlFor: "prov-tags",
|
|
160
|
-
className:
|
|
161
|
-
children: [
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
186
|
+
className: _,
|
|
187
|
+
children: [
|
|
188
|
+
v("providers.new.tagsLabel", "Tags"),
|
|
189
|
+
" ",
|
|
190
|
+
/* @__PURE__ */ d("span", {
|
|
191
|
+
className: "text-text-secondary",
|
|
192
|
+
children: [
|
|
193
|
+
"(",
|
|
194
|
+
v("providers.new.tagsHint", "comma-separated"),
|
|
195
|
+
")"
|
|
196
|
+
]
|
|
197
|
+
})
|
|
198
|
+
]
|
|
199
|
+
}), /* @__PURE__ */ u("input", {
|
|
166
200
|
id: "prov-tags",
|
|
167
201
|
type: "text",
|
|
168
|
-
value:
|
|
169
|
-
onChange: (e) =>
|
|
170
|
-
placeholder: "ai, productivity, enterprise",
|
|
171
|
-
className:
|
|
202
|
+
value: N,
|
|
203
|
+
onChange: (e) => P(e.target.value),
|
|
204
|
+
placeholder: v("providers.new.tagsPlaceholder", "ai, productivity, enterprise"),
|
|
205
|
+
className: g
|
|
172
206
|
})] }),
|
|
173
|
-
/* @__PURE__ */
|
|
207
|
+
/* @__PURE__ */ d("div", {
|
|
174
208
|
className: "flex flex-wrap gap-3 border-t border-border-subtle pt-5",
|
|
175
|
-
children: [/* @__PURE__ */
|
|
209
|
+
children: [/* @__PURE__ */ u("button", {
|
|
176
210
|
type: "submit",
|
|
177
|
-
disabled:
|
|
211
|
+
disabled: b.isPending,
|
|
178
212
|
className: "rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50",
|
|
179
|
-
children:
|
|
180
|
-
}), /* @__PURE__ */
|
|
213
|
+
children: b.isPending ? v("providers.new.creating", "Creating…") : v("providers.new.submit", "Create provider")
|
|
214
|
+
}), /* @__PURE__ */ u("button", {
|
|
181
215
|
type: "button",
|
|
182
|
-
onClick: () =>
|
|
216
|
+
onClick: () => y("/providers"),
|
|
183
217
|
className: "rounded-lg border border-border-subtle px-5 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-sunken",
|
|
184
|
-
children: "Cancel"
|
|
218
|
+
children: v("providers.new.cancel", "Cancel")
|
|
185
219
|
})]
|
|
186
220
|
})
|
|
187
221
|
]
|
|
188
222
|
})
|
|
189
|
-
}), /* @__PURE__ */
|
|
223
|
+
}), /* @__PURE__ */ d("div", {
|
|
190
224
|
className: "lg:sticky lg:top-6 lg:self-start",
|
|
191
|
-
children: [/* @__PURE__ */
|
|
225
|
+
children: [/* @__PURE__ */ d("p", {
|
|
192
226
|
className: "mb-2 inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary",
|
|
193
|
-
children: [
|
|
194
|
-
|
|
227
|
+
children: [
|
|
228
|
+
/* @__PURE__ */ u(l, { className: "h-3.5 w-3.5" }),
|
|
229
|
+
" ",
|
|
230
|
+
v("providers.new.preview", "Registry preview")
|
|
231
|
+
]
|
|
232
|
+
}), /* @__PURE__ */ d(f, {
|
|
195
233
|
treatment: "glass",
|
|
196
234
|
className: "flex flex-col p-5",
|
|
197
235
|
children: [
|
|
198
|
-
/* @__PURE__ */
|
|
236
|
+
/* @__PURE__ */ d("div", {
|
|
199
237
|
className: "flex items-start justify-between gap-2",
|
|
200
|
-
children: [/* @__PURE__ */
|
|
238
|
+
children: [/* @__PURE__ */ u("span", {
|
|
201
239
|
className: "flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary",
|
|
202
|
-
children: /* @__PURE__ */
|
|
203
|
-
}), /* @__PURE__ */
|
|
240
|
+
children: /* @__PURE__ */ u(c, { className: "h-5 w-5" })
|
|
241
|
+
}), /* @__PURE__ */ u("span", {
|
|
204
242
|
className: "rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-[11px] font-medium text-status-warning-text",
|
|
205
|
-
children: "Unverified"
|
|
243
|
+
children: v("providers.new.unverified", "Unverified")
|
|
206
244
|
})]
|
|
207
245
|
}),
|
|
208
|
-
/* @__PURE__ */
|
|
246
|
+
/* @__PURE__ */ u("p", {
|
|
209
247
|
className: "mt-3 truncate text-base font-semibold text-text-primary",
|
|
210
|
-
children:
|
|
248
|
+
children: x.trim() || v("providers.new.previewName", "Provider name")
|
|
211
249
|
}),
|
|
212
|
-
/* @__PURE__ */
|
|
250
|
+
/* @__PURE__ */ u("span", {
|
|
213
251
|
className: "mt-1 inline-flex w-fit rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary",
|
|
214
|
-
children: r(
|
|
252
|
+
children: v(h[C], r(C))
|
|
215
253
|
}),
|
|
216
|
-
|
|
254
|
+
T.trim() ? /* @__PURE__ */ u("p", {
|
|
217
255
|
className: "mt-3 line-clamp-3 text-xs leading-relaxed text-text-secondary",
|
|
218
|
-
children:
|
|
219
|
-
}) : /* @__PURE__ */
|
|
256
|
+
children: T.trim()
|
|
257
|
+
}) : /* @__PURE__ */ u("p", {
|
|
220
258
|
className: "mt-3 text-xs italic text-text-secondary/70",
|
|
221
|
-
children: "A short description will appear here."
|
|
259
|
+
children: v("providers.new.previewDescription", "A short description will appear here.")
|
|
222
260
|
}),
|
|
223
|
-
(
|
|
261
|
+
(k.trim() || j.trim() || L.length > 0) && /* @__PURE__ */ d("div", {
|
|
224
262
|
className: "mt-4 flex flex-wrap items-center gap-2 border-t border-border-subtle pt-3",
|
|
225
263
|
children: [
|
|
226
|
-
|
|
264
|
+
j.trim() && /* @__PURE__ */ u("span", {
|
|
227
265
|
className: "text-[11px] text-text-secondary",
|
|
228
|
-
children:
|
|
266
|
+
children: j.trim()
|
|
229
267
|
}),
|
|
230
|
-
|
|
268
|
+
k.trim() && /* @__PURE__ */ d("span", {
|
|
231
269
|
className: "text-[11px] text-text-secondary",
|
|
232
|
-
children: ["· ",
|
|
270
|
+
children: ["· ", k.trim()]
|
|
233
271
|
}),
|
|
234
|
-
|
|
272
|
+
L.slice(0, 4).map((e) => /* @__PURE__ */ u("span", {
|
|
235
273
|
className: "rounded-full bg-bg-sunken px-2 py-0.5 text-[11px] text-text-secondary",
|
|
236
274
|
children: e
|
|
237
275
|
}, e))
|
|
@@ -244,6 +282,6 @@ function g() {
|
|
|
244
282
|
});
|
|
245
283
|
}
|
|
246
284
|
//#endregion
|
|
247
|
-
export {
|
|
285
|
+
export { v as ProviderNewPage };
|
|
248
286
|
|
|
249
287
|
//# sourceMappingURL=ProviderNewPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderNewPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/providers/ProviderNewPage.tsx"],"sourcesContent":["/**\n * Create provider\n * @module subscriberbot/pages/providers\n *\n * Add a provider to the registry. Writes `subCreateProvider`. A card-wrapped\n * form with category chips and a live marketplace-style preview that mirrors\n * exactly what will land in the registry.\n */\n\nimport { useState } from 'react';\nimport { ArrowLeft, Building2, Sparkles } from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useCreateProvider } from '../../hooks/useSubscriberBotApi';\nimport { cn } from '../../utils/cn';\nimport { formatEnumLabel } from '../../utils/formatters';\nimport type { SubCreateProviderInput, SubProviderCategory } from '../../types';\n\nconst CATEGORIES: SubProviderCategory[] = [\n 'SAAS',\n 'AI_SERVICE',\n 'STREAMING',\n 'NEWSLETTER',\n 'NEWS_DIGEST',\n 'MEMBERSHIP',\n 'COMMUNITY',\n 'EDUCATION',\n 'FINANCIAL',\n 'INSURANCE',\n 'TELECOM',\n 'UTILITY',\n 'ASSOCIATION',\n 'LICENSE',\n 'CONTRACT',\n 'OTHER',\n];\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\nexport function ProviderNewPage() {\n const { navigateTo } = useSubscriberBot();\n const create = useCreateProvider();\n\n const [name, setName] = useState('');\n const [category, setCategory] = useState<SubProviderCategory>('SAAS');\n const [description, setDescription] = useState('');\n const [websiteUrl, setWebsiteUrl] = useState('');\n const [region, setRegion] = useState('');\n const [industry, setIndustry] = useState('');\n const [tags, setTags] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n\n const parsedTags = tags\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim()) {\n setFormError('A provider name is required.');\n return;\n }\n const input: SubCreateProviderInput = {\n name: name.trim(),\n category,\n ...(description.trim() ? { description: description.trim() } : {}),\n ...(websiteUrl.trim() ? { websiteUrl: websiteUrl.trim() } : {}),\n ...(region.trim() ? { region: region.trim() } : {}),\n ...(industry.trim() ? { industry: industry.trim() } : {}),\n ...(parsedTags.length ? { tags: parsedTags } : {}),\n };\n create.mutate(input, {\n onSuccess: (provider) => navigateTo(`/providers/${provider.id}`),\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : 'Could not create provider.'),\n });\n };\n\n return (\n <PageLayout\n title=\"Add provider\"\n description=\"Register a new provider in the registry\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/providers')}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n Add a provider that isn't in the registry yet so you can attach relationships, plans and\n assets to it.\n </PagePurpose>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Form */}\n <GlassCard treatment=\"metric\" className=\"p-6 lg:col-span-2\">\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n\n <div>\n <label htmlFor=\"prov-name\" className={labelCls}>\n Name <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"prov-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. OpenAI, Netflix, AWS\"\n className={inputCls}\n required\n />\n </div>\n\n <div>\n <span className={labelCls}>Category</span>\n <div className=\"flex flex-wrap gap-2\" role=\"group\" aria-label=\"Provider category\">\n {CATEGORIES.map((c) => {\n const active = category === c;\n return (\n <button\n key={c}\n type=\"button\"\n aria-pressed={active}\n onClick={() => setCategory(c)}\n className={cn(\n 'rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n active\n ? 'border-transparent bg-action-primary-bg text-action-primary-text'\n : 'border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {formatEnumLabel(c)}\n </button>\n );\n })}\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"prov-website\" className={labelCls}>\n Website\n </label>\n <input\n id=\"prov-website\"\n type=\"url\"\n value={websiteUrl}\n onChange={(e) => setWebsiteUrl(e.target.value)}\n placeholder=\"https://…\"\n className={inputCls}\n />\n </div>\n <div>\n <label htmlFor=\"prov-region\" className={labelCls}>\n Region\n </label>\n <input\n id=\"prov-region\"\n type=\"text\"\n value={region}\n onChange={(e) => setRegion(e.target.value)}\n placeholder=\"e.g. Global, US, EU\"\n className={inputCls}\n />\n </div>\n </div>\n\n <div>\n <label htmlFor=\"prov-industry\" className={labelCls}>\n Industry\n </label>\n <input\n id=\"prov-industry\"\n type=\"text\"\n value={industry}\n onChange={(e) => setIndustry(e.target.value)}\n placeholder=\"e.g. Cloud, Media\"\n className={inputCls}\n />\n </div>\n\n <div>\n <label htmlFor=\"prov-desc\" className={labelCls}>\n Description\n </label>\n <textarea\n id=\"prov-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={3}\n placeholder=\"What does this provider offer?\"\n className={inputCls}\n />\n </div>\n\n <div>\n <label htmlFor=\"prov-tags\" className={labelCls}>\n Tags <span className=\"text-text-secondary\">(comma-separated)</span>\n </label>\n <input\n id=\"prov-tags\"\n type=\"text\"\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n placeholder=\"ai, productivity, enterprise\"\n className={inputCls}\n />\n </div>\n\n <div className=\"flex flex-wrap gap-3 border-t border-border-subtle pt-5\">\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create provider'}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/providers')}\n className=\"rounded-lg border border-border-subtle px-5 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n </div>\n </form>\n </GlassCard>\n\n {/* Live preview — reflects the form state (no fabricated data) */}\n <div className=\"lg:sticky lg:top-6 lg:self-start\">\n <p className=\"mb-2 inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary\">\n <Sparkles className=\"h-3.5 w-3.5\" /> Registry preview\n </p>\n <GlassCard treatment=\"glass\" className=\"flex flex-col p-5\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <Building2 className=\"h-5 w-5\" />\n </span>\n <span className=\"rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-[11px] font-medium text-status-warning-text\">\n Unverified\n </span>\n </div>\n <p className=\"mt-3 truncate text-base font-semibold text-text-primary\">\n {name.trim() || 'Provider name'}\n </p>\n <span className=\"mt-1 inline-flex w-fit rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary\">\n {formatEnumLabel(category)}\n </span>\n {description.trim() ? (\n <p className=\"mt-3 line-clamp-3 text-xs leading-relaxed text-text-secondary\">\n {description.trim()}\n </p>\n ) : (\n <p className=\"mt-3 text-xs italic text-text-secondary/70\">\n A short description will appear here.\n </p>\n )}\n {(region.trim() || industry.trim() || parsedTags.length > 0) && (\n <div className=\"mt-4 flex flex-wrap items-center gap-2 border-t border-border-subtle pt-3\">\n {industry.trim() && (\n <span className=\"text-[11px] text-text-secondary\">{industry.trim()}</span>\n )}\n {region.trim() && (\n <span className=\"text-[11px] text-text-secondary\">· {region.trim()}</span>\n )}\n {parsedTags.slice(0, 4).map((t) => (\n <span\n key={t}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-[11px] text-text-secondary\"\n >\n {t}\n </span>\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProviderNewPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/providers/ProviderNewPage.tsx"],"sourcesContent":["/**\n * Create provider\n * @module subscriberbot/pages/providers\n *\n * Add a provider to the registry. Writes `subCreateProvider`. A card-wrapped\n * form with category chips and a live marketplace-style preview that mirrors\n * exactly what will land in the registry.\n */\n\nimport { useState } from 'react';\nimport { ArrowLeft, Building2, Sparkles } from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useCreateProvider } from '../../hooks/useSubscriberBotApi';\nimport { useTr } from '../../hooks/useTr';\nimport { cn } from '../../utils/cn';\nimport { formatEnumLabel } from '../../utils/formatters';\nimport type { SubCreateProviderInput, SubProviderCategory } from '../../types';\n\nconst CATEGORIES: SubProviderCategory[] = [\n 'SAAS',\n 'AI_SERVICE',\n 'STREAMING',\n 'NEWSLETTER',\n 'NEWS_DIGEST',\n 'MEMBERSHIP',\n 'COMMUNITY',\n 'EDUCATION',\n 'FINANCIAL',\n 'INSURANCE',\n 'TELECOM',\n 'UTILITY',\n 'ASSOCIATION',\n 'LICENSE',\n 'CONTRACT',\n 'OTHER',\n];\n\nconst CATEGORY_KEY: Record<SubProviderCategory, string> = {\n SAAS: 'providers.categories.saas',\n AI_SERVICE: 'providers.categories.aiService',\n STREAMING: 'providers.categories.streaming',\n NEWSLETTER: 'providers.categories.newsletter',\n NEWS_DIGEST: 'providers.categories.newsDigest',\n MEMBERSHIP: 'providers.categories.membership',\n COMMUNITY: 'providers.categories.community',\n EDUCATION: 'providers.categories.education',\n FINANCIAL: 'providers.categories.financial',\n INSURANCE: 'providers.categories.insurance',\n TELECOM: 'providers.categories.telecom',\n UTILITY: 'providers.categories.utility',\n ASSOCIATION: 'providers.categories.association',\n LICENSE: 'providers.categories.license',\n CONTRACT: 'providers.categories.contract',\n OTHER: 'providers.categories.other',\n};\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\nexport function ProviderNewPage() {\n const tr = useTr();\n const { navigateTo } = useSubscriberBot();\n const create = useCreateProvider();\n\n const [name, setName] = useState('');\n const [category, setCategory] = useState<SubProviderCategory>('SAAS');\n const [description, setDescription] = useState('');\n const [websiteUrl, setWebsiteUrl] = useState('');\n const [region, setRegion] = useState('');\n const [industry, setIndustry] = useState('');\n const [tags, setTags] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n\n const parsedTags = tags\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim()) {\n setFormError(tr('providers.new.nameRequired', 'A provider name is required.'));\n return;\n }\n const input: SubCreateProviderInput = {\n name: name.trim(),\n category,\n ...(description.trim() ? { description: description.trim() } : {}),\n ...(websiteUrl.trim() ? { websiteUrl: websiteUrl.trim() } : {}),\n ...(region.trim() ? { region: region.trim() } : {}),\n ...(industry.trim() ? { industry: industry.trim() } : {}),\n ...(parsedTags.length ? { tags: parsedTags } : {}),\n };\n create.mutate(input, {\n onSuccess: (provider) => navigateTo(`/providers/${provider.id}`),\n onError: (err) =>\n setFormError(\n err instanceof Error\n ? err.message\n : tr('providers.new.error', 'Could not create provider.')\n ),\n });\n };\n\n return (\n <PageLayout\n title={tr('providers.new.title', 'Add provider')}\n description={tr('providers.new.description', 'Register a new provider in the registry')}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/providers')}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> {tr('providers.new.back', 'Back')}\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n {tr(\n 'providers.new.purpose',\n \"Add a provider that isn't in the registry yet so you can attach relationships, plans and assets to it.\"\n )}\n </PagePurpose>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Form */}\n <GlassCard treatment=\"metric\" className=\"p-6 lg:col-span-2\">\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n\n <div>\n <label htmlFor=\"prov-name\" className={labelCls}>\n {tr('providers.new.nameLabel', 'Name')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"prov-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={tr('providers.new.namePlaceholder', 'e.g. OpenAI, Netflix, AWS')}\n className={inputCls}\n required\n />\n </div>\n\n <div>\n <span className={labelCls}>{tr('providers.new.categoryLabel', 'Category')}</span>\n <div\n className=\"flex flex-wrap gap-2\"\n role=\"group\"\n aria-label={tr('providers.new.categoryLabel', 'Category')}\n >\n {CATEGORIES.map((c) => {\n const active = category === c;\n return (\n <button\n key={c}\n type=\"button\"\n aria-pressed={active}\n onClick={() => setCategory(c)}\n className={cn(\n 'rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n active\n ? 'border-transparent bg-action-primary-bg text-action-primary-text'\n : 'border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {tr(CATEGORY_KEY[c], formatEnumLabel(c))}\n </button>\n );\n })}\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"prov-website\" className={labelCls}>\n {tr('providers.new.websiteLabel', 'Website')}\n </label>\n <input\n id=\"prov-website\"\n type=\"url\"\n value={websiteUrl}\n onChange={(e) => setWebsiteUrl(e.target.value)}\n placeholder={tr('providers.new.websitePlaceholder', 'https://…')}\n className={inputCls}\n />\n </div>\n <div>\n <label htmlFor=\"prov-region\" className={labelCls}>\n {tr('providers.new.regionLabel', 'Region')}\n </label>\n <input\n id=\"prov-region\"\n type=\"text\"\n value={region}\n onChange={(e) => setRegion(e.target.value)}\n placeholder={tr('providers.new.regionPlaceholder', 'e.g. Global, US, EU')}\n className={inputCls}\n />\n </div>\n </div>\n\n <div>\n <label htmlFor=\"prov-industry\" className={labelCls}>\n {tr('providers.new.industryLabel', 'Industry')}\n </label>\n <input\n id=\"prov-industry\"\n type=\"text\"\n value={industry}\n onChange={(e) => setIndustry(e.target.value)}\n placeholder={tr('providers.new.industryPlaceholder', 'e.g. Cloud, Media')}\n className={inputCls}\n />\n </div>\n\n <div>\n <label htmlFor=\"prov-desc\" className={labelCls}>\n {tr('providers.new.descriptionLabel', 'Description')}\n </label>\n <textarea\n id=\"prov-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={3}\n placeholder={tr(\n 'providers.new.descriptionPlaceholder',\n 'What does this provider offer?'\n )}\n className={inputCls}\n />\n </div>\n\n <div>\n <label htmlFor=\"prov-tags\" className={labelCls}>\n {tr('providers.new.tagsLabel', 'Tags')}{' '}\n <span className=\"text-text-secondary\">\n ({tr('providers.new.tagsHint', 'comma-separated')})\n </span>\n </label>\n <input\n id=\"prov-tags\"\n type=\"text\"\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n placeholder={tr('providers.new.tagsPlaceholder', 'ai, productivity, enterprise')}\n className={inputCls}\n />\n </div>\n\n <div className=\"flex flex-wrap gap-3 border-t border-border-subtle pt-5\">\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending\n ? tr('providers.new.creating', 'Creating…')\n : tr('providers.new.submit', 'Create provider')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/providers')}\n className=\"rounded-lg border border-border-subtle px-5 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n {tr('providers.new.cancel', 'Cancel')}\n </button>\n </div>\n </form>\n </GlassCard>\n\n {/* Live preview — reflects the form state (no fabricated data) */}\n <div className=\"lg:sticky lg:top-6 lg:self-start\">\n <p className=\"mb-2 inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary\">\n <Sparkles className=\"h-3.5 w-3.5\" /> {tr('providers.new.preview', 'Registry preview')}\n </p>\n <GlassCard treatment=\"glass\" className=\"flex flex-col p-5\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <Building2 className=\"h-5 w-5\" />\n </span>\n <span className=\"rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-[11px] font-medium text-status-warning-text\">\n {tr('providers.new.unverified', 'Unverified')}\n </span>\n </div>\n <p className=\"mt-3 truncate text-base font-semibold text-text-primary\">\n {name.trim() || tr('providers.new.previewName', 'Provider name')}\n </p>\n <span className=\"mt-1 inline-flex w-fit rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary\">\n {tr(CATEGORY_KEY[category], formatEnumLabel(category))}\n </span>\n {description.trim() ? (\n <p className=\"mt-3 line-clamp-3 text-xs leading-relaxed text-text-secondary\">\n {description.trim()}\n </p>\n ) : (\n <p className=\"mt-3 text-xs italic text-text-secondary/70\">\n {tr('providers.new.previewDescription', 'A short description will appear here.')}\n </p>\n )}\n {(region.trim() || industry.trim() || parsedTags.length > 0) && (\n <div className=\"mt-4 flex flex-wrap items-center gap-2 border-t border-border-subtle pt-3\">\n {industry.trim() && (\n <span className=\"text-[11px] text-text-secondary\">{industry.trim()}</span>\n )}\n {region.trim() && (\n <span className=\"text-[11px] text-text-secondary\">· {region.trim()}</span>\n )}\n {parsedTags.slice(0, 4).map((t) => (\n <span\n key={t}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-[11px] text-text-secondary\"\n >\n {t}\n </span>\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProvidersListPage.d.ts","sourceRoot":"","sources":["../../../../src/subscriberbot/pages/providers/ProvidersListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"ProvidersListPage.d.ts","sourceRoot":"","sources":["../../../../src/subscriberbot/pages/providers/ProvidersListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoKH,wBAAgB,iBAAiB,gCA8PhC"}
|