@fluid-app/portal-sdk 0.1.124 → 0.1.126
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/{ContactsScreen-CjFnJkt7.mjs → ContactsScreen-BKOHursc.mjs} +261 -610
- package/dist/ContactsScreen-BKOHursc.mjs.map +1 -0
- package/dist/{ContactsScreen-V9dHSQNX.cjs → ContactsScreen-DN8Qt2Ih.cjs} +260 -609
- package/dist/ContactsScreen-DN8Qt2Ih.cjs.map +1 -0
- package/dist/{ContactsScreen-CRROZFdR.cjs → ContactsScreen-FrVLbjGO.cjs} +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/package.json +15 -14
- package/dist/ContactsScreen-CjFnJkt7.mjs.map +0 -1
- package/dist/ContactsScreen-V9dHSQNX.cjs.map +0 -1
|
@@ -1970,7 +1970,7 @@ function formatDueDate$1(dateStr) {
|
|
|
1970
1970
|
year: "numeric"
|
|
1971
1971
|
});
|
|
1972
1972
|
}
|
|
1973
|
-
function EmptyState$
|
|
1973
|
+
function EmptyState$3({ onCreateNote }) {
|
|
1974
1974
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1975
1975
|
className: "flex flex-col items-center justify-center px-4 py-12 text-center",
|
|
1976
1976
|
children: [
|
|
@@ -2145,7 +2145,7 @@ function NotesList({ notes, isLoading, contactId, ref }) {
|
|
|
2145
2145
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { className: "h-3.5 w-3.5" }), "Add Note"]
|
|
2146
2146
|
})]
|
|
2147
2147
|
}),
|
|
2148
|
-
notes.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState$
|
|
2148
|
+
notes.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState$3, { onCreateNote: openCreateModal }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2149
2149
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
2150
2150
|
children: notes.map((note) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NoteCard, {
|
|
2151
2151
|
note,
|
|
@@ -2184,327 +2184,6 @@ function NotesList({ notes, isLoading, contactId, ref }) {
|
|
|
2184
2184
|
});
|
|
2185
2185
|
}
|
|
2186
2186
|
//#endregion
|
|
2187
|
-
//#region ../../contacts/ui/src/portal/components/activities/activity-feed.tsx
|
|
2188
|
-
const SLUG_ICON_MAP = {
|
|
2189
|
-
order_placed: lucide_react.ShoppingCart,
|
|
2190
|
-
abandoned_cart: lucide_react.ShoppingCart,
|
|
2191
|
-
cart_items_added: lucide_react.ShoppingCart,
|
|
2192
|
-
new_cart_items_added: lucide_react.ShoppingCart,
|
|
2193
|
-
direct_message: lucide_react.MessageCircle,
|
|
2194
|
-
comment_reply: lucide_react.MessageCircle,
|
|
2195
|
-
message_received: lucide_react.MessageCircle,
|
|
2196
|
-
message_sent: lucide_react.MessageCircle,
|
|
2197
|
-
video: lucide_react.Play,
|
|
2198
|
-
video_complete: lucide_react.Play,
|
|
2199
|
-
video_contact: lucide_react.Play,
|
|
2200
|
-
video_complete_contact: lucide_react.Play,
|
|
2201
|
-
new_lead: lucide_react.UserPlus,
|
|
2202
|
-
page_views_contact: lucide_react.UserPlus,
|
|
2203
|
-
smart_link_clicked: lucide_react.UserPlus,
|
|
2204
|
-
page_views: lucide_react.Eye,
|
|
2205
|
-
upcoming_event: lucide_react.Calendar,
|
|
2206
|
-
review_left: lucide_react.Star,
|
|
2207
|
-
tasks: lucide_react.SquareCheckBig,
|
|
2208
|
-
announcements: lucide_react.Bell,
|
|
2209
|
-
fantasy_point: lucide_react.Trophy
|
|
2210
|
-
};
|
|
2211
|
-
function getActivityIcon(slug) {
|
|
2212
|
-
return slug && SLUG_ICON_MAP[slug] || lucide_react.User;
|
|
2213
|
-
}
|
|
2214
|
-
function getTypeLabel(slug) {
|
|
2215
|
-
if (!slug) return "Notification";
|
|
2216
|
-
if (slug.includes("message") || slug === "direct_message" || slug === "comment_reply") return "Message";
|
|
2217
|
-
if (slug.includes("page_view")) return "Alert from Fluid.app";
|
|
2218
|
-
if (slug.includes("video")) return "Alert from Fluid.app";
|
|
2219
|
-
if (slug.includes("order") || slug.includes("cart") || slug === "abandoned_cart") return "Alert from Fluid.app";
|
|
2220
|
-
if (slug === "tasks") return "Task";
|
|
2221
|
-
if (slug === "smart_link_clicked" || slug === "new_lead") return "Alert from Fluid.app";
|
|
2222
|
-
if (slug === "announcements") return "Announcement";
|
|
2223
|
-
if (slug === "upcoming_event") return "Event";
|
|
2224
|
-
if (slug === "review_left") return "Review";
|
|
2225
|
-
if (slug === "fantasy_point") return "Points";
|
|
2226
|
-
return "Notification";
|
|
2227
|
-
}
|
|
2228
|
-
function getSlugCategory(slug) {
|
|
2229
|
-
if (!slug) return "other";
|
|
2230
|
-
if (slug.includes("message") || slug === "direct_message" || slug === "comment_reply") return "message";
|
|
2231
|
-
if (slug === "tasks") return "task";
|
|
2232
|
-
if (slug.includes("page_view") || slug === "smart_link_clicked") return "page_view";
|
|
2233
|
-
if (slug.includes("video")) return "video";
|
|
2234
|
-
if (slug.includes("order") || slug.includes("cart") || slug === "abandoned_cart") return "order";
|
|
2235
|
-
return "other";
|
|
2236
|
-
}
|
|
2237
|
-
function getDateKey(timestamp) {
|
|
2238
|
-
return new Date(timestamp).toISOString().split("T")[0] ?? timestamp;
|
|
2239
|
-
}
|
|
2240
|
-
function formatDateHeader(timestamp) {
|
|
2241
|
-
const date = new Date(timestamp);
|
|
2242
|
-
const now = /* @__PURE__ */ new Date();
|
|
2243
|
-
const todayKey = now.toISOString().split("T")[0];
|
|
2244
|
-
const yesterdayKey = (/* @__PURE__ */ new Date(now.getTime() - 864e5)).toISOString().split("T")[0];
|
|
2245
|
-
const key = getDateKey(timestamp);
|
|
2246
|
-
if (key === todayKey) return "Today";
|
|
2247
|
-
if (key === yesterdayKey) return "Yesterday";
|
|
2248
|
-
return date.toLocaleDateString("en-US", {
|
|
2249
|
-
month: "long",
|
|
2250
|
-
day: "numeric"
|
|
2251
|
-
});
|
|
2252
|
-
}
|
|
2253
|
-
function formatTimestamp(timestamp) {
|
|
2254
|
-
return new Date(timestamp).toLocaleTimeString("en-US", {
|
|
2255
|
-
hour: "numeric",
|
|
2256
|
-
minute: "2-digit",
|
|
2257
|
-
hour12: true
|
|
2258
|
-
});
|
|
2259
|
-
}
|
|
2260
|
-
const filterOptions = ["All", "New"];
|
|
2261
|
-
function filterActivities(activities, filter) {
|
|
2262
|
-
if (filter === "New") return activities.filter((a) => !a.read_at);
|
|
2263
|
-
return activities;
|
|
2264
|
-
}
|
|
2265
|
-
function groupByDate(activities) {
|
|
2266
|
-
const sorted = [...activities].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
2267
|
-
const map = /* @__PURE__ */ new Map();
|
|
2268
|
-
for (const activity of sorted) {
|
|
2269
|
-
const key = getDateKey(activity.created_at);
|
|
2270
|
-
const existing = map.get(key);
|
|
2271
|
-
if (existing) existing.push(activity);
|
|
2272
|
-
else map.set(key, [activity]);
|
|
2273
|
-
}
|
|
2274
|
-
return Array.from(map.entries()).map(([, items]) => ({
|
|
2275
|
-
label: formatDateHeader(items[0].created_at),
|
|
2276
|
-
items
|
|
2277
|
-
}));
|
|
2278
|
-
}
|
|
2279
|
-
function EmptyState$3() {
|
|
2280
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2281
|
-
className: "flex flex-col items-center justify-center px-4 py-12 text-center",
|
|
2282
|
-
children: [
|
|
2283
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2284
|
-
className: "relative mb-6",
|
|
2285
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2286
|
-
className: "flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br from-violet-100 to-indigo-100",
|
|
2287
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Rocket, { className: "h-9 w-9 text-violet-500" })
|
|
2288
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2289
|
-
className: "absolute -right-2 -bottom-1 flex h-9 w-9 items-center justify-center rounded-full border-2 border-white bg-gradient-to-br from-pink-100 to-rose-100 shadow-sm",
|
|
2290
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Share2, { className: "h-4 w-4 text-pink-500" })
|
|
2291
|
-
})]
|
|
2292
|
-
}),
|
|
2293
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
2294
|
-
className: "text-foreground text-base font-semibold",
|
|
2295
|
-
children: "No activity yet"
|
|
2296
|
-
}),
|
|
2297
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2298
|
-
className: "text-muted-foreground mt-1.5 max-w-[240px] text-sm leading-relaxed",
|
|
2299
|
-
children: "Reach out and share a product or media to start building this contact's story"
|
|
2300
|
-
})
|
|
2301
|
-
]
|
|
2302
|
-
});
|
|
2303
|
-
}
|
|
2304
|
-
function ContentCard({ activity }) {
|
|
2305
|
-
const category = getSlugCategory(activity.slug);
|
|
2306
|
-
const headerText = activity.formatted_description;
|
|
2307
|
-
const extraDescription = activity.description && activity.description !== headerText ? activity.description : null;
|
|
2308
|
-
const extraTitle = activity.title && activity.title !== headerText ? activity.title : null;
|
|
2309
|
-
if (!extraDescription && !extraTitle && category !== "task") return null;
|
|
2310
|
-
switch (category) {
|
|
2311
|
-
case "message":
|
|
2312
|
-
if (!extraDescription) return null;
|
|
2313
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2314
|
-
className: "border-border bg-background mt-2 rounded-lg border p-3",
|
|
2315
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2316
|
-
className: "text-foreground text-sm leading-relaxed",
|
|
2317
|
-
children: extraDescription
|
|
2318
|
-
})
|
|
2319
|
-
});
|
|
2320
|
-
case "task":
|
|
2321
|
-
if (!extraDescription) return null;
|
|
2322
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2323
|
-
className: "bg-muted/50 mt-2 rounded-lg p-3",
|
|
2324
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2325
|
-
className: "text-muted-foreground text-sm",
|
|
2326
|
-
children: extraDescription
|
|
2327
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2328
|
-
className: "text-primary mt-2 flex items-center gap-1.5",
|
|
2329
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Calendar, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2330
|
-
className: "text-xs font-medium",
|
|
2331
|
-
children: ["Due ", extraTitle || "TBD"]
|
|
2332
|
-
})]
|
|
2333
|
-
})]
|
|
2334
|
-
});
|
|
2335
|
-
case "page_view":
|
|
2336
|
-
if (!extraTitle && !extraDescription) return null;
|
|
2337
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2338
|
-
className: "bg-muted/50 mt-2 rounded-lg p-3",
|
|
2339
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2340
|
-
className: "text-foreground text-sm font-semibold",
|
|
2341
|
-
children: extraTitle || extraDescription
|
|
2342
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2343
|
-
className: "text-muted-foreground text-xs",
|
|
2344
|
-
children: getTypeLabel(activity.slug)
|
|
2345
|
-
})]
|
|
2346
|
-
});
|
|
2347
|
-
case "video":
|
|
2348
|
-
if (!extraTitle && !extraDescription) return null;
|
|
2349
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2350
|
-
className: "bg-muted/50 mt-2 rounded-lg p-3",
|
|
2351
|
-
children: [extraTitle && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2352
|
-
className: "text-foreground text-sm font-semibold",
|
|
2353
|
-
children: extraTitle
|
|
2354
|
-
}), extraDescription && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2355
|
-
className: "text-muted-foreground mt-0.5 text-xs",
|
|
2356
|
-
children: extraDescription
|
|
2357
|
-
})]
|
|
2358
|
-
});
|
|
2359
|
-
case "order":
|
|
2360
|
-
if (!extraTitle && !extraDescription) return null;
|
|
2361
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2362
|
-
className: "bg-muted/50 mt-2 rounded-lg p-3",
|
|
2363
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2364
|
-
className: "text-foreground text-sm font-semibold",
|
|
2365
|
-
children: extraTitle || extraDescription
|
|
2366
|
-
})
|
|
2367
|
-
});
|
|
2368
|
-
default: return null;
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
function ActivityItem({ activity, isFirst, isLast }) {
|
|
2372
|
-
const Icon = getActivityIcon(activity.slug);
|
|
2373
|
-
const isUnread = !activity.read_at;
|
|
2374
|
-
const typeLabel = getTypeLabel(activity.slug);
|
|
2375
|
-
const headerText = activity.formatted_description;
|
|
2376
|
-
const subtitle = activity.description && activity.description !== headerText ? activity.description : activity.title && activity.title !== headerText ? activity.title : null;
|
|
2377
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2378
|
-
className: "relative flex gap-3",
|
|
2379
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2380
|
-
className: "relative flex w-10 shrink-0 flex-col items-center",
|
|
2381
|
-
children: [
|
|
2382
|
-
!isFirst && !isLast && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "absolute top-0 bottom-0 left-1/2 -translate-x-1/2 border-l-2 border-dashed border-blue-400" }),
|
|
2383
|
-
!isFirst && isLast && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "absolute top-0 left-1/2 h-5 -translate-x-1/2 border-l-2 border-dashed border-blue-400" }),
|
|
2384
|
-
isFirst && !isLast && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "absolute top-[44px] bottom-0 left-1/2 -translate-x-1/2 border-l-2 border-dashed border-blue-400" }),
|
|
2385
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2386
|
-
className: "bg-background relative z-10 rounded-full",
|
|
2387
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2388
|
-
className: "bg-foreground text-background flex h-10 w-10 items-center justify-center rounded-full",
|
|
2389
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: "h-4 w-4" })
|
|
2390
|
-
}), isUnread && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-background absolute -top-0.5 -right-0.5 h-3 w-3 rounded-full border-2 bg-blue-600" })]
|
|
2391
|
-
})
|
|
2392
|
-
]
|
|
2393
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2394
|
-
className: "min-w-0 flex-1 pt-1 pb-8",
|
|
2395
|
-
children: [
|
|
2396
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2397
|
-
className: "flex items-start gap-1.5",
|
|
2398
|
-
children: [
|
|
2399
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2400
|
-
className: "text-foreground text-sm font-semibold",
|
|
2401
|
-
children: headerText
|
|
2402
|
-
}),
|
|
2403
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2404
|
-
className: "text-muted-foreground mt-0.5 shrink-0 text-xs",
|
|
2405
|
-
children: typeLabel
|
|
2406
|
-
}),
|
|
2407
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2408
|
-
className: "text-muted-foreground mt-0.5 flex-1 text-right text-xs",
|
|
2409
|
-
children: formatTimestamp(activity.created_at)
|
|
2410
|
-
})
|
|
2411
|
-
]
|
|
2412
|
-
}),
|
|
2413
|
-
subtitle && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2414
|
-
className: "text-muted-foreground mt-0.5 text-sm",
|
|
2415
|
-
children: subtitle
|
|
2416
|
-
}),
|
|
2417
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContentCard, { activity })
|
|
2418
|
-
]
|
|
2419
|
-
})]
|
|
2420
|
-
});
|
|
2421
|
-
}
|
|
2422
|
-
function DateSeparator({ label }) {
|
|
2423
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2424
|
-
className: "py-3",
|
|
2425
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2426
|
-
className: "text-foreground text-base font-bold",
|
|
2427
|
-
children: label
|
|
2428
|
-
})
|
|
2429
|
-
});
|
|
2430
|
-
}
|
|
2431
|
-
function ActivityFeed({ activities, isLoading, onMarkRead }) {
|
|
2432
|
-
const [activeFilter, setActiveFilter] = (0, react.useState)("All");
|
|
2433
|
-
const handleFilterChange = (option) => {
|
|
2434
|
-
setActiveFilter(option);
|
|
2435
|
-
};
|
|
2436
|
-
const hasUnread = activities.some((a) => !a.read_at);
|
|
2437
|
-
const filtered = (0, react.useMemo)(() => filterActivities(activities, activeFilter), [activities, activeFilter]);
|
|
2438
|
-
const grouped = (0, react.useMemo)(() => groupByDate(filtered), [filtered]);
|
|
2439
|
-
const allItems = (0, react.useMemo)(() => grouped.flatMap((g) => g.items), [grouped]);
|
|
2440
|
-
if (isLoading) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2441
|
-
className: "space-y-4",
|
|
2442
|
-
children: [
|
|
2443
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-5 w-24 animate-pulse rounded" }),
|
|
2444
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2445
|
-
className: "flex gap-2",
|
|
2446
|
-
children: [
|
|
2447
|
-
1,
|
|
2448
|
-
2,
|
|
2449
|
-
3
|
|
2450
|
-
].map((i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-6 w-14 animate-pulse rounded-full" }, i))
|
|
2451
|
-
}),
|
|
2452
|
-
[
|
|
2453
|
-
1,
|
|
2454
|
-
2,
|
|
2455
|
-
3
|
|
2456
|
-
].map((i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2457
|
-
className: "flex items-start gap-3",
|
|
2458
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-10 w-10 animate-pulse rounded-full" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2459
|
-
className: "flex-1 space-y-1.5",
|
|
2460
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-4 w-3/4 animate-pulse rounded" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-3 w-1/3 animate-pulse rounded" })]
|
|
2461
|
-
})]
|
|
2462
|
-
}, i))
|
|
2463
|
-
]
|
|
2464
|
-
});
|
|
2465
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2466
|
-
className: "space-y-4",
|
|
2467
|
-
children: [
|
|
2468
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
2469
|
-
className: "text-foreground text-lg font-semibold",
|
|
2470
|
-
children: "Recent Activity"
|
|
2471
|
-
}),
|
|
2472
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2473
|
-
className: "flex items-center gap-2",
|
|
2474
|
-
children: [filterOptions.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2475
|
-
type: "button",
|
|
2476
|
-
onClick: () => handleFilterChange(option),
|
|
2477
|
-
className: require_src.cn("rounded-full px-3 py-1 text-xs font-medium transition-colors", activeFilter === option ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:bg-muted/80"),
|
|
2478
|
-
children: option
|
|
2479
|
-
}, option)), hasUnread && onMarkRead && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2480
|
-
type: "button",
|
|
2481
|
-
onClick: onMarkRead,
|
|
2482
|
-
className: "text-primary hover:text-primary/80 ml-auto text-xs font-medium transition-colors",
|
|
2483
|
-
children: "Mark all read"
|
|
2484
|
-
})]
|
|
2485
|
-
}),
|
|
2486
|
-
activities.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState$3, {}) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
2487
|
-
className: "text-muted-foreground py-8 text-center text-sm",
|
|
2488
|
-
children: [
|
|
2489
|
-
"No ",
|
|
2490
|
-
activeFilter.toLowerCase(),
|
|
2491
|
-
" activities"
|
|
2492
|
-
]
|
|
2493
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: grouped.map((group, groupIndex) => {
|
|
2494
|
-
const itemsBefore = grouped.slice(0, groupIndex).reduce((sum, g) => sum + g.items.length, 0);
|
|
2495
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DateSeparator, { label: group.label }), group.items.map((activity, itemIndex) => {
|
|
2496
|
-
const globalIndex = itemsBefore + itemIndex;
|
|
2497
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActivityItem, {
|
|
2498
|
-
activity,
|
|
2499
|
-
isFirst: globalIndex === 0,
|
|
2500
|
-
isLast: globalIndex === allItems.length - 1
|
|
2501
|
-
}, activity.id);
|
|
2502
|
-
})] }, group.label);
|
|
2503
|
-
}) })
|
|
2504
|
-
]
|
|
2505
|
-
});
|
|
2506
|
-
}
|
|
2507
|
-
//#endregion
|
|
2508
2187
|
//#region ../../contacts/ui/src/portal/hooks/contacts/use-toggle-task-completion.ts
|
|
2509
2188
|
function useToggleTaskCompletion(contactId) {
|
|
2510
2189
|
const queryClient = (0, _tanstack_react_query.useQueryClient)();
|
|
@@ -2921,9 +2600,9 @@ function useMarkContactRead(contactId) {
|
|
|
2921
2600
|
//#endregion
|
|
2922
2601
|
//#region ../../contacts/ui/src/portal/components/contacts/rep-contact-detail-view.tsx
|
|
2923
2602
|
const DEFAULT_COUNTRY_OPTIONS = [];
|
|
2924
|
-
function RepContactDetailView({ contact, contactId, countryOptions = DEFAULT_COUNTRY_OPTIONS, ordersSlot, subscriptionsSlot }) {
|
|
2925
|
-
const [activeTab, setActiveTab] = (0, react.useState)("
|
|
2926
|
-
const { data: activities = [], isLoading:
|
|
2603
|
+
function RepContactDetailView({ contact, contactId, countryOptions = DEFAULT_COUNTRY_OPTIONS, ordersSlot: _ordersSlot, subscriptionsSlot: _subscriptionsSlot }) {
|
|
2604
|
+
const [activeTab, setActiveTab] = (0, react.useState)("tasks");
|
|
2605
|
+
const { data: activities = [], isLoading: _isLoadingActivities } = useContactActivities(contactId);
|
|
2927
2606
|
const { data: tasks = [], isLoading: isLoadingTasks } = useContactTasks(contactId);
|
|
2928
2607
|
const { data: notes = [], isLoading: isLoadingNotes } = useContactNotes(contactId);
|
|
2929
2608
|
const markRead = useMarkContactRead(contactId);
|
|
@@ -2944,7 +2623,7 @@ function RepContactDetailView({ contact, contactId, countryOptions = DEFAULT_COU
|
|
|
2944
2623
|
const hasUnread = (0, react.useMemo)(() => activities.some((a) => !a.read_at), [activities]);
|
|
2945
2624
|
if (hasUnread && !prevHasUnreadRef.current) hasFiredRef.current = false;
|
|
2946
2625
|
prevHasUnreadRef.current = hasUnread;
|
|
2947
|
-
|
|
2626
|
+
(0, react.useCallback)(() => {
|
|
2948
2627
|
if (hasFiredRef.current || markRead.isPending) return;
|
|
2949
2628
|
hasFiredRef.current = true;
|
|
2950
2629
|
markRead.mutate();
|
|
@@ -2998,11 +2677,6 @@ function RepContactDetailView({ contact, contactId, countryOptions = DEFAULT_COU
|
|
|
2998
2677
|
className: "text-muted-foreground data-[state=active]:border-b-primary data-[state=active]:text-foreground rounded-none border-0 border-b-2 border-b-transparent px-4 py-2.5 text-sm font-medium shadow-none focus-visible:ring-0 focus-visible:outline-none data-[state=active]:bg-transparent data-[state=active]:shadow-none",
|
|
2999
2678
|
children: "Edit"
|
|
3000
2679
|
}),
|
|
3001
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.TabsTrigger, {
|
|
3002
|
-
value: "activity",
|
|
3003
|
-
className: "text-muted-foreground data-[state=active]:border-b-primary data-[state=active]:text-foreground rounded-none border-0 border-b-2 border-b-transparent px-4 py-2.5 text-sm font-medium shadow-none focus-visible:ring-0 focus-visible:outline-none data-[state=active]:bg-transparent data-[state=active]:shadow-none",
|
|
3004
|
-
children: "Activity"
|
|
3005
|
-
}),
|
|
3006
2680
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.TabsTrigger, {
|
|
3007
2681
|
value: "tasks",
|
|
3008
2682
|
className: "text-muted-foreground data-[state=active]:border-b-primary data-[state=active]:text-foreground rounded-none border-0 border-b-2 border-b-transparent px-4 py-2.5 text-sm font-medium shadow-none focus-visible:ring-0 focus-visible:outline-none data-[state=active]:bg-transparent data-[state=active]:shadow-none",
|
|
@@ -3012,16 +2686,6 @@ function RepContactDetailView({ contact, contactId, countryOptions = DEFAULT_COU
|
|
|
3012
2686
|
value: "notes",
|
|
3013
2687
|
className: "text-muted-foreground data-[state=active]:border-b-primary data-[state=active]:text-foreground rounded-none border-0 border-b-2 border-b-transparent px-4 py-2.5 text-sm font-medium shadow-none focus-visible:ring-0 focus-visible:outline-none data-[state=active]:bg-transparent data-[state=active]:shadow-none",
|
|
3014
2688
|
children: "Notes"
|
|
3015
|
-
}),
|
|
3016
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.TabsTrigger, {
|
|
3017
|
-
value: "orders",
|
|
3018
|
-
className: "text-muted-foreground data-[state=active]:border-b-primary data-[state=active]:text-foreground rounded-none border-0 border-b-2 border-b-transparent px-4 py-2.5 text-sm font-medium shadow-none focus-visible:ring-0 focus-visible:outline-none data-[state=active]:bg-transparent data-[state=active]:shadow-none",
|
|
3019
|
-
children: "Orders"
|
|
3020
|
-
}),
|
|
3021
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.TabsTrigger, {
|
|
3022
|
-
value: "subscriptions",
|
|
3023
|
-
className: "text-muted-foreground data-[state=active]:border-b-primary data-[state=active]:text-foreground rounded-none border-0 border-b-2 border-b-transparent px-4 py-2.5 text-sm font-medium shadow-none focus-visible:ring-0 focus-visible:outline-none data-[state=active]:bg-transparent data-[state=active]:shadow-none",
|
|
3024
|
-
children: "Subscriptions"
|
|
3025
2689
|
})
|
|
3026
2690
|
]
|
|
3027
2691
|
}),
|
|
@@ -3030,15 +2694,6 @@ function RepContactDetailView({ contact, contactId, countryOptions = DEFAULT_COU
|
|
|
3030
2694
|
className: "mt-6",
|
|
3031
2695
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactDetailsForm, { countries: countryOptions })
|
|
3032
2696
|
}),
|
|
3033
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.TabsContent, {
|
|
3034
|
-
value: "activity",
|
|
3035
|
-
className: "mt-6",
|
|
3036
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActivityFeed, {
|
|
3037
|
-
activities,
|
|
3038
|
-
isLoading: isLoadingActivities,
|
|
3039
|
-
onMarkRead: handleMarkRead
|
|
3040
|
-
})
|
|
3041
|
-
}),
|
|
3042
2697
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.TabsContent, {
|
|
3043
2698
|
value: "tasks",
|
|
3044
2699
|
className: "mt-6",
|
|
@@ -3058,48 +2713,6 @@ function RepContactDetailView({ contact, contactId, countryOptions = DEFAULT_COU
|
|
|
3058
2713
|
contactId,
|
|
3059
2714
|
ref: openNoteModalRef
|
|
3060
2715
|
})
|
|
3061
|
-
}),
|
|
3062
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.TabsContent, {
|
|
3063
|
-
value: "orders",
|
|
3064
|
-
className: "mt-6",
|
|
3065
|
-
children: ordersSlot ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3066
|
-
className: "flex flex-col items-center justify-center py-16 text-center",
|
|
3067
|
-
children: [
|
|
3068
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3069
|
-
className: "bg-muted mb-4 flex h-14 w-14 items-center justify-center rounded-full",
|
|
3070
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ShoppingCart, { className: "text-muted-foreground h-6 w-6" })
|
|
3071
|
-
}),
|
|
3072
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
3073
|
-
className: "text-foreground text-sm font-medium",
|
|
3074
|
-
children: "No orders yet"
|
|
3075
|
-
}),
|
|
3076
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3077
|
-
className: "text-muted-foreground mt-1 text-sm",
|
|
3078
|
-
children: "Orders placed by this contact will appear here."
|
|
3079
|
-
})
|
|
3080
|
-
]
|
|
3081
|
-
})
|
|
3082
|
-
}),
|
|
3083
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.TabsContent, {
|
|
3084
|
-
value: "subscriptions",
|
|
3085
|
-
className: "mt-6",
|
|
3086
|
-
children: subscriptionsSlot ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3087
|
-
className: "flex flex-col items-center justify-center py-16 text-center",
|
|
3088
|
-
children: [
|
|
3089
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3090
|
-
className: "bg-muted mb-4 flex h-14 w-14 items-center justify-center rounded-full",
|
|
3091
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Repeat2, { className: "text-muted-foreground h-6 w-6" })
|
|
3092
|
-
}),
|
|
3093
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
3094
|
-
className: "text-foreground text-sm font-medium",
|
|
3095
|
-
children: "No subscriptions yet"
|
|
3096
|
-
}),
|
|
3097
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3098
|
-
className: "text-muted-foreground mt-1 text-sm",
|
|
3099
|
-
children: "Subscriptions for this contact will appear here."
|
|
3100
|
-
})
|
|
3101
|
-
]
|
|
3102
|
-
})
|
|
3103
2716
|
})
|
|
3104
2717
|
]
|
|
3105
2718
|
})
|
|
@@ -3872,345 +3485,383 @@ function useCreateContactMutation(queryKeyPrefix = "contacts", options) {
|
|
|
3872
3485
|
});
|
|
3873
3486
|
}
|
|
3874
3487
|
//#endregion
|
|
3875
|
-
//#region
|
|
3488
|
+
//#region src/contacts/use-contacts-config.ts
|
|
3876
3489
|
/**
|
|
3877
|
-
*
|
|
3878
|
-
*
|
|
3490
|
+
* Hook that derives a FetchClient from the portal SDK's FluidProvider context.
|
|
3879
3491
|
*
|
|
3880
|
-
*
|
|
3881
|
-
*
|
|
3882
|
-
* @param params? - params?
|
|
3492
|
+
* Maps FluidSDKConfig fields to a FetchClient suitable for contacts, notes, and tasks APIs.
|
|
3493
|
+
* Follows the same pattern as useMessagingConfig.
|
|
3883
3494
|
*/
|
|
3884
|
-
|
|
3885
|
-
|
|
3495
|
+
function useContactsConfig() {
|
|
3496
|
+
const { config } = require_FluidProvider.useFluidContext();
|
|
3497
|
+
return { client: (0, react.useMemo)(() => {
|
|
3498
|
+
const baseUrl = config.baseUrl.replace(/\/+$/, "").replace(/\/api$/, "");
|
|
3499
|
+
const csrfToken = typeof document !== "undefined" ? document.querySelector("meta[name=\"csrf-token\"]")?.getAttribute("content") : null;
|
|
3500
|
+
return require_FluidProvider.createFetchClient({
|
|
3501
|
+
baseUrl,
|
|
3502
|
+
getAuthToken: config.getAuthToken,
|
|
3503
|
+
onAuthError: config.onAuthError,
|
|
3504
|
+
defaultHeaders: {
|
|
3505
|
+
...config.defaultHeaders,
|
|
3506
|
+
...csrfToken ? { "X-CSRF-Token": csrfToken } : {}
|
|
3507
|
+
}
|
|
3508
|
+
});
|
|
3509
|
+
}, [
|
|
3510
|
+
config.baseUrl,
|
|
3511
|
+
config.getAuthToken,
|
|
3512
|
+
config.onAuthError,
|
|
3513
|
+
config.defaultHeaders
|
|
3514
|
+
]) };
|
|
3886
3515
|
}
|
|
3516
|
+
//#endregion
|
|
3517
|
+
//#region ../../api-clients/portal-tenant-contacts/src/namespaces/portal_tenant_contacts.ts
|
|
3887
3518
|
/**
|
|
3888
|
-
*
|
|
3889
|
-
*
|
|
3519
|
+
* List contacts with cursor pagination
|
|
3520
|
+
* Returns a paginated list of contacts belonging to the authenticated member.
|
|
3890
3521
|
*
|
|
3891
3522
|
* @param client - Fetch client instance
|
|
3892
|
-
* @param
|
|
3523
|
+
* @param [params] - params
|
|
3893
3524
|
*/
|
|
3894
|
-
async function
|
|
3895
|
-
return client.
|
|
3525
|
+
async function contacts_list(client, params) {
|
|
3526
|
+
return client.get(`/api/contacts`, params);
|
|
3896
3527
|
}
|
|
3897
3528
|
/**
|
|
3898
|
-
* Create a contact
|
|
3899
|
-
*
|
|
3529
|
+
* Create a new contact
|
|
3530
|
+
* Creates a new contact for the authenticated member.
|
|
3900
3531
|
*
|
|
3901
3532
|
* @param client - Fetch client instance
|
|
3902
3533
|
* @param body - body
|
|
3903
3534
|
*/
|
|
3904
|
-
async function
|
|
3905
|
-
return client.post(`/api/
|
|
3906
|
-
}
|
|
3907
|
-
/**
|
|
3908
|
-
* List user's contacts
|
|
3909
|
-
*
|
|
3910
|
-
*
|
|
3911
|
-
* @param client - Fetch client instance
|
|
3912
|
-
* @param params? - params?
|
|
3913
|
-
*/
|
|
3914
|
-
async function listUserContacts(client, params) {
|
|
3915
|
-
return client.get(`/api/users/v2025-06/contacts`, params);
|
|
3916
|
-
}
|
|
3917
|
-
/**
|
|
3918
|
-
* Delete a contact
|
|
3919
|
-
*
|
|
3920
|
-
*
|
|
3921
|
-
* @param client - Fetch client instance
|
|
3922
|
-
* @param id - id
|
|
3923
|
-
*/
|
|
3924
|
-
async function deleteUserContact(client, id) {
|
|
3925
|
-
return client.delete(`/api/users/v2025-06/contacts/${id}`);
|
|
3535
|
+
async function contacts_create(client, body) {
|
|
3536
|
+
return client.post(`/api/contacts`, body);
|
|
3926
3537
|
}
|
|
3927
3538
|
/**
|
|
3928
|
-
* Get a contact
|
|
3929
|
-
*
|
|
3539
|
+
* Get a specific contact
|
|
3540
|
+
* Returns a single contact by ID.
|
|
3930
3541
|
*
|
|
3931
3542
|
* @param client - Fetch client instance
|
|
3932
3543
|
* @param id - id
|
|
3933
3544
|
*/
|
|
3934
|
-
async function
|
|
3935
|
-
return client.get(`/api/
|
|
3545
|
+
async function contacts_show(client, id) {
|
|
3546
|
+
return client.get(`/api/contacts/${id}`);
|
|
3936
3547
|
}
|
|
3937
3548
|
/**
|
|
3938
3549
|
* Update a contact
|
|
3939
|
-
*
|
|
3550
|
+
* Updates an existing contact's attributes.
|
|
3940
3551
|
*
|
|
3941
3552
|
* @param client - Fetch client instance
|
|
3942
3553
|
* @param id - id
|
|
3943
3554
|
* @param body - body
|
|
3944
3555
|
*/
|
|
3945
|
-
async function
|
|
3946
|
-
return client.patch(`/api/
|
|
3556
|
+
async function contacts_update(client, id, body) {
|
|
3557
|
+
return client.patch(`/api/contacts/${id}`, body);
|
|
3947
3558
|
}
|
|
3948
3559
|
/**
|
|
3949
|
-
*
|
|
3950
|
-
*
|
|
3560
|
+
* Delete a contact
|
|
3561
|
+
* Soft-deletes a contact by ID.
|
|
3951
3562
|
*
|
|
3952
3563
|
* @param client - Fetch client instance
|
|
3953
3564
|
* @param id - id
|
|
3954
|
-
* @param body - body
|
|
3955
3565
|
*/
|
|
3956
|
-
async function
|
|
3957
|
-
return client.
|
|
3566
|
+
async function contacts_destroy(client, id) {
|
|
3567
|
+
return client.delete(`/api/contacts/${id}`);
|
|
3958
3568
|
}
|
|
3959
3569
|
/**
|
|
3960
|
-
*
|
|
3961
|
-
*
|
|
3570
|
+
* Delete multiple contacts
|
|
3571
|
+
* Soft-deletes multiple contacts by their IDs.
|
|
3962
3572
|
*
|
|
3963
3573
|
* @param client - Fetch client instance
|
|
3964
|
-
* @param
|
|
3574
|
+
* @param body - body
|
|
3965
3575
|
*/
|
|
3966
|
-
async function
|
|
3967
|
-
return client.
|
|
3576
|
+
async function contacts_bulk_destroy(client, body) {
|
|
3577
|
+
return client.delete(`/api/contacts/bulk`, { body });
|
|
3968
3578
|
}
|
|
3969
3579
|
/**
|
|
3970
|
-
* List
|
|
3971
|
-
*
|
|
3580
|
+
* List notes for a contact
|
|
3581
|
+
* Returns notes attached to a contact.
|
|
3972
3582
|
*
|
|
3973
3583
|
* @param client - Fetch client instance
|
|
3974
|
-
* @param
|
|
3975
|
-
* @param params
|
|
3584
|
+
* @param contact_id - contact_id
|
|
3585
|
+
* @param [params] - params
|
|
3976
3586
|
*/
|
|
3977
|
-
async function
|
|
3978
|
-
return client.get(`/api/
|
|
3587
|
+
async function contacts_notes_list(client, contact_id, params) {
|
|
3588
|
+
return client.get(`/api/contacts/${contact_id}/notes`, params);
|
|
3979
3589
|
}
|
|
3980
3590
|
/**
|
|
3981
|
-
*
|
|
3982
|
-
*
|
|
3591
|
+
* Create a note for a contact
|
|
3592
|
+
* Adds a new note to a contact.
|
|
3983
3593
|
*
|
|
3984
3594
|
* @param client - Fetch client instance
|
|
3985
|
-
* @param
|
|
3595
|
+
* @param contact_id - contact_id
|
|
3596
|
+
* @param body - body
|
|
3986
3597
|
*/
|
|
3987
|
-
async function
|
|
3988
|
-
return client.post(`/api/
|
|
3598
|
+
async function contacts_notes_create(client, contact_id, body) {
|
|
3599
|
+
return client.post(`/api/contacts/${contact_id}/notes`, body);
|
|
3989
3600
|
}
|
|
3990
3601
|
/**
|
|
3991
|
-
* List
|
|
3992
|
-
*
|
|
3602
|
+
* List tasks for a contact
|
|
3603
|
+
* Returns tasks assigned to a contact.
|
|
3993
3604
|
*
|
|
3994
3605
|
* @param client - Fetch client instance
|
|
3995
|
-
* @param
|
|
3996
|
-
* @param params
|
|
3606
|
+
* @param contact_id - contact_id
|
|
3607
|
+
* @param [params] - params
|
|
3997
3608
|
*/
|
|
3998
|
-
async function
|
|
3999
|
-
return client.get(`/api/
|
|
3609
|
+
async function contacts_tasks_list(client, contact_id, params) {
|
|
3610
|
+
return client.get(`/api/contacts/${contact_id}/tasks`, params);
|
|
4000
3611
|
}
|
|
4001
3612
|
/**
|
|
4002
3613
|
* Create a task for a contact
|
|
4003
|
-
*
|
|
3614
|
+
* Adds a new task to a contact.
|
|
4004
3615
|
*
|
|
4005
3616
|
* @param client - Fetch client instance
|
|
4006
|
-
* @param
|
|
3617
|
+
* @param contact_id - contact_id
|
|
4007
3618
|
* @param body - body
|
|
4008
3619
|
*/
|
|
4009
|
-
async function
|
|
4010
|
-
return client.post(`/api/
|
|
3620
|
+
async function contacts_tasks_create(client, contact_id, body) {
|
|
3621
|
+
return client.post(`/api/contacts/${contact_id}/tasks`, body);
|
|
4011
3622
|
}
|
|
4012
3623
|
/**
|
|
4013
|
-
*
|
|
4014
|
-
*
|
|
3624
|
+
* Update a note
|
|
3625
|
+
* Updates an existing note on a contact.
|
|
4015
3626
|
*
|
|
4016
3627
|
* @param client - Fetch client instance
|
|
3628
|
+
* @param contact_id - contact_id
|
|
4017
3629
|
* @param id - id
|
|
3630
|
+
* @param body - body
|
|
4018
3631
|
*/
|
|
4019
|
-
async function
|
|
4020
|
-
return client.
|
|
3632
|
+
async function contacts_notes_update(client, contact_id, id, body) {
|
|
3633
|
+
return client.patch(`/api/contacts/${contact_id}/notes/${id}`, body);
|
|
4021
3634
|
}
|
|
4022
|
-
//#endregion
|
|
4023
|
-
//#region ../../notes/fluid-user-notes-api-client/src/namespaces/users_notes.ts
|
|
4024
3635
|
/**
|
|
4025
3636
|
* Delete a note
|
|
4026
|
-
*
|
|
3637
|
+
* Removes a note from a contact.
|
|
4027
3638
|
*
|
|
4028
3639
|
* @param client - Fetch client instance
|
|
3640
|
+
* @param contact_id - contact_id
|
|
4029
3641
|
* @param id - id
|
|
4030
|
-
* @param params - params
|
|
4031
3642
|
*/
|
|
4032
|
-
async function
|
|
4033
|
-
return client.delete(`/api/
|
|
3643
|
+
async function contacts_notes_destroy(client, contact_id, id) {
|
|
3644
|
+
return client.delete(`/api/contacts/${contact_id}/notes/${id}`);
|
|
4034
3645
|
}
|
|
4035
3646
|
/**
|
|
4036
|
-
* Update a
|
|
4037
|
-
*
|
|
3647
|
+
* Update a task
|
|
3648
|
+
* Updates an existing task on a contact.
|
|
4038
3649
|
*
|
|
4039
3650
|
* @param client - Fetch client instance
|
|
3651
|
+
* @param contact_id - contact_id
|
|
4040
3652
|
* @param id - id
|
|
4041
3653
|
* @param body - body
|
|
4042
3654
|
*/
|
|
4043
|
-
async function
|
|
4044
|
-
return client.patch(`/api/
|
|
3655
|
+
async function contacts_tasks_update(client, contact_id, id, body) {
|
|
3656
|
+
return client.patch(`/api/contacts/${contact_id}/tasks/${id}`, body);
|
|
4045
3657
|
}
|
|
4046
|
-
//#endregion
|
|
4047
|
-
//#region ../../tasks/fluid-user-tasks-api-client/src/namespaces/users_tasks.ts
|
|
4048
3658
|
/**
|
|
4049
3659
|
* Delete a task
|
|
4050
|
-
*
|
|
3660
|
+
* Removes a task from a contact.
|
|
4051
3661
|
*
|
|
4052
3662
|
* @param client - Fetch client instance
|
|
3663
|
+
* @param contact_id - contact_id
|
|
4053
3664
|
* @param id - id
|
|
4054
3665
|
*/
|
|
4055
|
-
async function
|
|
4056
|
-
return client.delete(`/api/
|
|
4057
|
-
}
|
|
4058
|
-
/**
|
|
4059
|
-
* Update a task
|
|
4060
|
-
*
|
|
4061
|
-
*
|
|
4062
|
-
* @param client - Fetch client instance
|
|
4063
|
-
* @param id - id
|
|
4064
|
-
* @param body - body
|
|
4065
|
-
*/
|
|
4066
|
-
async function updateUserTask(client, id, body) {
|
|
4067
|
-
return client.patch(`/api/users/v2025-06/tasks/${id}`, body);
|
|
3666
|
+
async function contacts_tasks_destroy(client, contact_id, id) {
|
|
3667
|
+
return client.delete(`/api/contacts/${contact_id}/tasks/${id}`);
|
|
4068
3668
|
}
|
|
4069
3669
|
//#endregion
|
|
4070
|
-
//#region
|
|
3670
|
+
//#region src/contacts/create-portal-contacts-adapter.ts
|
|
3671
|
+
const EMPTY_META = {
|
|
3672
|
+
total_count: 0,
|
|
3673
|
+
total_pages: 0,
|
|
3674
|
+
current_page: 1
|
|
3675
|
+
};
|
|
3676
|
+
function paginationFromBff(meta, itemCount, currentPage, pageSize) {
|
|
3677
|
+
if (!meta) return EMPTY_META;
|
|
3678
|
+
const hasNext = !!meta.pagination?.next_cursor;
|
|
3679
|
+
const totalCount = meta.total_count ?? (hasNext ? (currentPage + 1) * pageSize : (currentPage - 1) * pageSize + itemCount);
|
|
3680
|
+
return {
|
|
3681
|
+
total_count: totalCount,
|
|
3682
|
+
total_pages: Math.max(1, Math.ceil(totalCount / pageSize)),
|
|
3683
|
+
current_page: currentPage,
|
|
3684
|
+
request_id: meta.request_id ?? void 0,
|
|
3685
|
+
timestamp: meta.timestamp ?? void 0
|
|
3686
|
+
};
|
|
3687
|
+
}
|
|
3688
|
+
/** BFF Contact → core Contact. Fills missing fields with safe defaults. */
|
|
3689
|
+
function mapContact(raw) {
|
|
3690
|
+
return {
|
|
3691
|
+
id: raw.id,
|
|
3692
|
+
full_name: `${raw.first_name ?? ""} ${raw.last_name ?? ""}`.trim(),
|
|
3693
|
+
first_name: raw.first_name ?? null,
|
|
3694
|
+
last_name: raw.last_name ?? null,
|
|
3695
|
+
email: raw.email ?? null,
|
|
3696
|
+
phone: raw.phone ?? null,
|
|
3697
|
+
status: raw.status ?? null,
|
|
3698
|
+
address: raw.address ?? null,
|
|
3699
|
+
city: raw.city ?? null,
|
|
3700
|
+
state: raw.state ?? null,
|
|
3701
|
+
postal_code: raw.postal_code ?? null,
|
|
3702
|
+
avatar_url: raw.avatar_url ?? null,
|
|
3703
|
+
country: raw.country ?? null,
|
|
3704
|
+
tags: raw.tags ?? [],
|
|
3705
|
+
metadata: {},
|
|
3706
|
+
created_at: raw.created_at,
|
|
3707
|
+
updated_at: raw.updated_at
|
|
3708
|
+
};
|
|
3709
|
+
}
|
|
3710
|
+
/** BFF Note → core ContactNote. */
|
|
3711
|
+
function mapNote(raw) {
|
|
3712
|
+
return {
|
|
3713
|
+
id: raw.id,
|
|
3714
|
+
title: raw.title ?? "",
|
|
3715
|
+
body: raw.body ?? "",
|
|
3716
|
+
note_type: null,
|
|
3717
|
+
due_date: null,
|
|
3718
|
+
due_time: null,
|
|
3719
|
+
pinned: null,
|
|
3720
|
+
created_at: raw.created_at,
|
|
3721
|
+
updated_at: raw.updated_at,
|
|
3722
|
+
contact_id: raw.contact_id ?? 0,
|
|
3723
|
+
assets: []
|
|
3724
|
+
};
|
|
3725
|
+
}
|
|
3726
|
+
/** BFF Task → core ContactTask. */
|
|
3727
|
+
function mapTask(raw) {
|
|
3728
|
+
return {
|
|
3729
|
+
id: raw.id,
|
|
3730
|
+
body: raw.title ?? "",
|
|
3731
|
+
due_at: raw.due_date ?? null,
|
|
3732
|
+
completed_at: raw.completed_at ?? (raw.completed ? (/* @__PURE__ */ new Date()).toISOString() : null),
|
|
3733
|
+
created_at: raw.created_at,
|
|
3734
|
+
contact_id: raw.contact_id ?? null
|
|
3735
|
+
};
|
|
3736
|
+
}
|
|
4071
3737
|
/**
|
|
4072
|
-
*
|
|
3738
|
+
* The contacts-ui sends offset pagination params (page, per_page, sort_by,
|
|
3739
|
+
* sort_direction, search, status). The BFF expects cursor pagination
|
|
3740
|
+
* (page[cursor], page[limit], search, tags). Translate between the two.
|
|
4073
3741
|
*
|
|
4074
|
-
*
|
|
4075
|
-
*
|
|
4076
|
-
*
|
|
4077
|
-
* Read methods map responses through `satisfies` for compile-time drift
|
|
4078
|
-
* detection. Mutation methods use input-side assertions where the port
|
|
4079
|
-
* intentionally uses loose types (Record<string, unknown>) that don't match
|
|
4080
|
-
* the generated client's strict body schemas.
|
|
3742
|
+
* `cursorCache` maps page numbers → cursor tokens so page-2+ requests can
|
|
3743
|
+
* resolve to the correct cursor. The cache is populated from BFF responses.
|
|
4081
3744
|
*/
|
|
4082
|
-
function
|
|
3745
|
+
function mapListParams(params, cursorCache) {
|
|
3746
|
+
if (!params) return void 0;
|
|
3747
|
+
const mapped = {};
|
|
3748
|
+
if (params.per_page || params.limit) mapped["page[limit]"] = params.per_page ?? params.limit;
|
|
3749
|
+
const page = params.page ?? 1;
|
|
3750
|
+
if (page > 1) {
|
|
3751
|
+
const cursor = cursorCache.get(page);
|
|
3752
|
+
if (cursor) mapped["page[cursor]"] = cursor;
|
|
3753
|
+
}
|
|
3754
|
+
if (params.search_query || params.search || params.query) mapped.search = params.search_query ?? params.search ?? params.query;
|
|
3755
|
+
if (params.tags) mapped.tags = params.tags;
|
|
3756
|
+
return mapped;
|
|
3757
|
+
}
|
|
3758
|
+
function createContactsAdapter(client) {
|
|
3759
|
+
const cursorCache = /* @__PURE__ */ new Map();
|
|
4083
3760
|
return {
|
|
4084
3761
|
getContact: async (id) => {
|
|
4085
|
-
return { contact: (await
|
|
3762
|
+
return { contact: mapContact((await contacts_show(client, id)).contact) };
|
|
4086
3763
|
},
|
|
4087
3764
|
listContacts: async (params) => {
|
|
4088
|
-
const
|
|
3765
|
+
const raw = params;
|
|
3766
|
+
const page = raw?.page ?? 1;
|
|
3767
|
+
const pageSize = raw?.per_page ?? 25;
|
|
3768
|
+
const body = await contacts_list(client, mapListParams(raw, cursorCache));
|
|
3769
|
+
const meta = body.meta;
|
|
3770
|
+
const nextCursor = (meta?.pagination)?.next_cursor;
|
|
3771
|
+
if (nextCursor) cursorCache.set(page + 1, nextCursor);
|
|
3772
|
+
const contacts = (body.contacts ?? []).map(mapContact);
|
|
4089
3773
|
return {
|
|
4090
|
-
contacts
|
|
4091
|
-
meta:
|
|
3774
|
+
contacts,
|
|
3775
|
+
meta: paginationFromBff(meta, contacts.length, page, pageSize)
|
|
4092
3776
|
};
|
|
4093
3777
|
},
|
|
4094
|
-
createContact: (data) =>
|
|
4095
|
-
|
|
4096
|
-
id: Number(id),
|
|
4097
|
-
contact: data
|
|
4098
|
-
}),
|
|
4099
|
-
deleteContact: (id) => deleteUserContact(client, id),
|
|
4100
|
-
bulkDeleteContacts: (ids) => bulkDeleteUserContacts(client, { contact_ids: ids }),
|
|
4101
|
-
listActivities: async (contactId) => {
|
|
4102
|
-
const response = await listUserContactActivities(client, contactId);
|
|
4103
|
-
return {
|
|
4104
|
-
activities: response.activities ?? [],
|
|
4105
|
-
meta: response.meta ?? {}
|
|
4106
|
-
};
|
|
3778
|
+
createContact: async (data) => {
|
|
3779
|
+
return contacts_create(client, { contact: data });
|
|
4107
3780
|
},
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
const response = await listUserContactOrders(client, contactId, params);
|
|
4111
|
-
return {
|
|
4112
|
-
orders: response.orders ?? [],
|
|
4113
|
-
meta: response.meta ?? {}
|
|
4114
|
-
};
|
|
3781
|
+
updateContact: async (id, data) => {
|
|
3782
|
+
return contacts_update(client, id, { contact: data });
|
|
4115
3783
|
},
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
3784
|
+
deleteContact: async (id) => {
|
|
3785
|
+
return contacts_destroy(client, id);
|
|
3786
|
+
},
|
|
3787
|
+
bulkDeleteContacts: async (ids) => {
|
|
3788
|
+
return contacts_bulk_destroy(client, { ids });
|
|
3789
|
+
},
|
|
3790
|
+
listActivities: async () => ({
|
|
3791
|
+
activities: [],
|
|
3792
|
+
meta: EMPTY_META
|
|
3793
|
+
}),
|
|
3794
|
+
markRead: async () => ({}),
|
|
3795
|
+
listOrders: async () => ({
|
|
3796
|
+
orders: [],
|
|
3797
|
+
meta: EMPTY_META
|
|
3798
|
+
}),
|
|
3799
|
+
listSubscriptionOrders: async () => ({
|
|
3800
|
+
subscription_orders: [],
|
|
3801
|
+
meta: EMPTY_META
|
|
3802
|
+
})
|
|
4123
3803
|
};
|
|
4124
3804
|
}
|
|
4125
|
-
|
|
4126
|
-
* Creates a NotesApi adapter backed by the user-contacts and user-notes
|
|
4127
|
-
* generated clients.
|
|
4128
|
-
*
|
|
4129
|
-
* List and create use the contact sub-resource endpoints (usersContacts),
|
|
4130
|
-
* while update and delete use the standalone notes endpoints (usersNotes).
|
|
4131
|
-
*/
|
|
4132
|
-
function createNotesApiAdapter(client) {
|
|
3805
|
+
function createNotesAdapter(client) {
|
|
4133
3806
|
return {
|
|
4134
3807
|
listNotes: async (contactId) => {
|
|
4135
|
-
return { notes: (await
|
|
3808
|
+
return { notes: ((await contacts_notes_list(client, contactId)).notes ?? []).map(mapNote) };
|
|
4136
3809
|
},
|
|
4137
|
-
createNote: (contactId, input) =>
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
}
|
|
4146
|
-
deleteNote: (noteId, contactId) => deleteUserNote(client, noteId, { contact_id: Number(contactId) })
|
|
3810
|
+
createNote: async (contactId, input) => {
|
|
3811
|
+
return contacts_notes_create(client, contactId, { note: input });
|
|
3812
|
+
},
|
|
3813
|
+
updateNote: async (noteId, contactId, input) => {
|
|
3814
|
+
return contacts_notes_update(client, contactId, noteId, { note: input });
|
|
3815
|
+
},
|
|
3816
|
+
deleteNote: async (noteId, contactId) => {
|
|
3817
|
+
return contacts_notes_destroy(client, contactId, noteId);
|
|
3818
|
+
}
|
|
4147
3819
|
};
|
|
4148
3820
|
}
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
* generated clients.
|
|
4152
|
-
*
|
|
4153
|
-
* List and create use the contact sub-resource endpoints (usersContacts),
|
|
4154
|
-
* while update and delete use the standalone tasks endpoints (usersTasks).
|
|
4155
|
-
*/
|
|
4156
|
-
function createTasksApiAdapter(client) {
|
|
3821
|
+
function createTasksAdapter(client) {
|
|
3822
|
+
let lastContactId = 0;
|
|
4157
3823
|
return {
|
|
4158
3824
|
listTasks: async (contactId) => {
|
|
4159
|
-
|
|
3825
|
+
lastContactId = contactId;
|
|
3826
|
+
return { tasks: ((await contacts_tasks_list(client, contactId)).tasks ?? []).map(mapTask) };
|
|
4160
3827
|
},
|
|
4161
|
-
createTask: (contactId, input) =>
|
|
4162
|
-
|
|
4163
|
-
task:
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
3828
|
+
createTask: async (contactId, input) => {
|
|
3829
|
+
lastContactId = contactId;
|
|
3830
|
+
return contacts_tasks_create(client, contactId, { task: {
|
|
3831
|
+
title: input.body,
|
|
3832
|
+
due_date: input.due_at
|
|
3833
|
+
} });
|
|
3834
|
+
},
|
|
3835
|
+
updateTask: async (taskId, input) => {
|
|
3836
|
+
return contacts_tasks_update(client, input.contact_id ?? lastContactId, taskId, { task: {
|
|
3837
|
+
title: input.body ?? void 0,
|
|
3838
|
+
completed: input.completed_at !== void 0 ? input.completed_at !== null : void 0,
|
|
3839
|
+
due_date: input.due_at
|
|
3840
|
+
} });
|
|
3841
|
+
},
|
|
3842
|
+
deleteTask: async (taskId) => {
|
|
3843
|
+
if (!lastContactId) throw new Error("deleteTask called before contact context is established");
|
|
3844
|
+
return contacts_tasks_destroy(client, lastContactId, taskId);
|
|
3845
|
+
}
|
|
4170
3846
|
};
|
|
4171
3847
|
}
|
|
4172
3848
|
/**
|
|
4173
|
-
* Creates a composite ContactsDomainApi
|
|
4174
|
-
*
|
|
4175
|
-
* ContactsApiProvider context.
|
|
3849
|
+
* Creates a composite ContactsDomainApi backed by the portal-tenant
|
|
3850
|
+
* Contacts BFF endpoints.
|
|
4176
3851
|
*/
|
|
4177
|
-
function
|
|
3852
|
+
function createPortalContactsDomainApiAdapter(client) {
|
|
4178
3853
|
return {
|
|
4179
|
-
contacts:
|
|
4180
|
-
notes:
|
|
4181
|
-
tasks:
|
|
3854
|
+
contacts: createContactsAdapter(client),
|
|
3855
|
+
notes: createNotesAdapter(client),
|
|
3856
|
+
tasks: createTasksAdapter(client)
|
|
4182
3857
|
};
|
|
4183
3858
|
}
|
|
4184
3859
|
//#endregion
|
|
4185
|
-
//#region src/contacts/use-contacts-config.ts
|
|
4186
|
-
/**
|
|
4187
|
-
* Hook that derives a FetchClient from the portal SDK's FluidProvider context.
|
|
4188
|
-
*
|
|
4189
|
-
* Maps FluidSDKConfig fields to a FetchClient suitable for contacts, notes, and tasks APIs.
|
|
4190
|
-
* Follows the same pattern as useMessagingConfig.
|
|
4191
|
-
*/
|
|
4192
|
-
function useContactsConfig() {
|
|
4193
|
-
const { config } = require_FluidProvider.useFluidContext();
|
|
4194
|
-
return { client: (0, react.useMemo)(() => {
|
|
4195
|
-
return require_FluidProvider.createFetchClient({
|
|
4196
|
-
baseUrl: config.baseUrl.replace(/\/+$/, "").replace(/\/api$/, ""),
|
|
4197
|
-
getAuthToken: config.getAuthToken,
|
|
4198
|
-
onAuthError: config.onAuthError,
|
|
4199
|
-
defaultHeaders: config.defaultHeaders
|
|
4200
|
-
});
|
|
4201
|
-
}, [
|
|
4202
|
-
config.baseUrl,
|
|
4203
|
-
config.getAuthToken,
|
|
4204
|
-
config.onAuthError,
|
|
4205
|
-
config.defaultHeaders
|
|
4206
|
-
]) };
|
|
4207
|
-
}
|
|
4208
|
-
//#endregion
|
|
4209
3860
|
//#region src/contacts/PortalContactsApiProvider.tsx
|
|
4210
3861
|
function PortalContactsApiProvider({ children }) {
|
|
4211
3862
|
const { client } = useContactsConfig();
|
|
4212
3863
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactsApiProvider, {
|
|
4213
|
-
value: (0, react.useMemo)(() =>
|
|
3864
|
+
value: (0, react.useMemo)(() => createPortalContactsDomainApiAdapter(client), [client]),
|
|
4214
3865
|
children
|
|
4215
3866
|
});
|
|
4216
3867
|
}
|
|
@@ -4420,4 +4071,4 @@ Object.defineProperty(exports, "contactsScreenPropertySchema", {
|
|
|
4420
4071
|
}
|
|
4421
4072
|
});
|
|
4422
4073
|
|
|
4423
|
-
//# sourceMappingURL=ContactsScreen-
|
|
4074
|
+
//# sourceMappingURL=ContactsScreen-DN8Qt2Ih.cjs.map
|