@sesionario/blocks 1.39.0 → 1.40.0

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/index.js CHANGED
@@ -23,6 +23,7 @@ import flags from 'react-phone-number-input/flags';
23
23
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
24
24
  import { MessageScroller as MessageScroller$1 } from '@shadcn/react/message-scroller';
25
25
  export { useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility } from '@shadcn/react/message-scroller';
26
+ import { Slot as Slot$1 } from 'radix-ui';
26
27
 
27
28
  var LanguageContext = createContext(null);
28
29
  function useLanguageContext() {
@@ -602,7 +603,7 @@ function useEditableSection({
602
603
  },
603
604
  resolvedLabels,
604
605
  contentStyle: stableHeight && minHeightPx != null ? { minHeight: minHeightPx } : void 0,
605
- actionsClassName: "flex min-h-9 min-w-[11rem] flex-wrap items-center justify-end gap-2"
606
+ actionsClassName: "flex min-h-9 w-full flex-wrap items-center gap-2 *:flex-1 sm:w-auto sm:min-w-[11rem] sm:justify-end sm:*:flex-none"
606
607
  };
607
608
  }
608
609
  function EditableSection({
@@ -4700,6 +4701,7 @@ function useSearchHotkey(options = {}) {
4700
4701
  }
4701
4702
 
4702
4703
  // src/lib/scroll-restoration/store.ts
4704
+ var programmaticDepth = 0;
4703
4705
  var MAX_MARKS = 30;
4704
4706
  var MAX_SNAPSHOT_ROUTES = 3;
4705
4707
  var PENDING_TRAVERSAL_TTL_MS = 1e3;
@@ -4791,6 +4793,9 @@ function consumePendingTraversal(routeKey) {
4791
4793
  clearPendingTraversalTimer();
4792
4794
  return true;
4793
4795
  }
4796
+ function isProgrammaticScroll() {
4797
+ return programmaticDepth > 0;
4798
+ }
4794
4799
  function getScrollTop(container) {
4795
4800
  if (!container) {
4796
4801
  return window.scrollY || document.documentElement.scrollTop || 0;
@@ -4798,11 +4803,37 @@ function getScrollTop(container) {
4798
4803
  return container.scrollTop;
4799
4804
  }
4800
4805
  function setScrollTop(container, top) {
4801
- if (!container) {
4802
- window.scrollTo(0, top);
4803
- return;
4806
+ programmaticDepth += 1;
4807
+ try {
4808
+ if (!container) {
4809
+ window.scrollTo({ top, left: 0, behavior: "instant" });
4810
+ return;
4811
+ }
4812
+ container.scrollTop = top;
4813
+ } finally {
4814
+ queueMicrotask(() => {
4815
+ programmaticDepth = Math.max(0, programmaticDepth - 1);
4816
+ });
4804
4817
  }
4805
- container.scrollTop = top;
4818
+ }
4819
+ function isOverflowScrollport(element) {
4820
+ const overflow = getComputedStyle(element).overflowY;
4821
+ return overflow === "auto" || overflow === "scroll" || overflow === "overlay";
4822
+ }
4823
+ function resolveScrollPort(container) {
4824
+ if (!container) return "window";
4825
+ const windowTop = getScrollTop(null);
4826
+ const nestedTop = container.scrollTop;
4827
+ if (nestedTop > windowTop) return "container";
4828
+ if (windowTop > nestedTop) return "window";
4829
+ return isOverflowScrollport(container) ? "container" : "window";
4830
+ }
4831
+ function resetScrollports(container) {
4832
+ setScrollTop(null, 0);
4833
+ if (container) setScrollTop(container, 0);
4834
+ }
4835
+ function portNode(container, port) {
4836
+ return port === "container" ? container : null;
4806
4837
  }
4807
4838
  function scrollportTop(container) {
4808
4839
  return container ? container.getBoundingClientRect().top : 0;
@@ -4844,11 +4875,14 @@ function resolveAnchor(container, attribute) {
4844
4875
  return { id: bestId, top: bestTop };
4845
4876
  }
4846
4877
  function captureMark(container, attribute) {
4847
- const anchor = resolveAnchor(container, attribute);
4878
+ const port = resolveScrollPort(container);
4879
+ const node = portNode(container, port);
4880
+ const anchor = resolveAnchor(node, attribute);
4848
4881
  return {
4849
- top: getScrollTop(container),
4882
+ top: getScrollTop(node),
4850
4883
  anchorId: anchor?.id ?? null,
4851
- anchorTop: anchor?.top ?? 0
4884
+ anchorTop: anchor?.top ?? 0,
4885
+ port
4852
4886
  };
4853
4887
  }
4854
4888
  function applyMark(container, mark, attribute) {
@@ -4868,6 +4902,22 @@ function applyMark(container, mark, attribute) {
4868
4902
  setScrollTop(container, mark.top);
4869
4903
  return false;
4870
4904
  }
4905
+ function restoreScrollports(container, mark, attribute) {
4906
+ const port = mark.port ?? "window";
4907
+ switch (port) {
4908
+ case "container":
4909
+ setScrollTop(null, 0);
4910
+ if (!container) return false;
4911
+ return applyMark(container, mark, attribute);
4912
+ case "window":
4913
+ if (container) setScrollTop(container, 0);
4914
+ return applyMark(null, mark, attribute);
4915
+ default: {
4916
+ const exhaustive = port;
4917
+ return exhaustive;
4918
+ }
4919
+ }
4920
+ }
4871
4921
  function getScrollHeight(container) {
4872
4922
  if (!container) {
4873
4923
  return Math.max(
@@ -4883,8 +4933,37 @@ var ScrollRestorationContext = createContext(null);
4883
4933
  function useScrollRestorationContext() {
4884
4934
  return useContext(ScrollRestorationContext);
4885
4935
  }
4886
- function readContainer(containerRef) {
4887
- return containerRef?.current ?? null;
4936
+ function readContainer(containerRef, registered) {
4937
+ return registered ?? containerRef?.current ?? null;
4938
+ }
4939
+ var USER_INTENT_EVENTS = [
4940
+ "wheel",
4941
+ "touchstart",
4942
+ "keydown",
4943
+ "pointerdown"
4944
+ ];
4945
+ function listenForUserIntent(onIntent) {
4946
+ for (const type of USER_INTENT_EVENTS) {
4947
+ window.addEventListener(type, onIntent, { passive: true, once: true });
4948
+ }
4949
+ return () => {
4950
+ for (const type of USER_INTENT_EVENTS) {
4951
+ window.removeEventListener(type, onIntent);
4952
+ }
4953
+ };
4954
+ }
4955
+ function useRegisterScrollContainer(containerRef) {
4956
+ const ctx = useScrollRestorationContext();
4957
+ const setContainerRef = useRef(ctx?.setScrollContainer);
4958
+ setContainerRef.current = ctx?.setScrollContainer;
4959
+ useLayoutEffect(() => {
4960
+ const setContainer = setContainerRef.current;
4961
+ if (!setContainer) return;
4962
+ setContainer(containerRef.current);
4963
+ return () => {
4964
+ setContainer(null);
4965
+ };
4966
+ }, [containerRef]);
4888
4967
  }
4889
4968
  function ScrollRestorationProvider({
4890
4969
  routeKey,
@@ -4901,13 +4980,23 @@ function ScrollRestorationProvider({
4901
4980
  };
4902
4981
  }
4903
4982
  const isTraversal = traversalForRouteRef.current.isTraversal;
4983
+ const registeredContainerRef = useRef(null);
4984
+ const [scrollContainerNode, setScrollContainerNode] = useState(null);
4985
+ const setScrollContainer = useCallback((node) => {
4986
+ registeredContainerRef.current = node;
4987
+ setScrollContainerNode((current) => current === node ? current : node);
4988
+ }, []);
4989
+ const readActiveContainer = useCallback(() => {
4990
+ return readContainer(containerRef, registeredContainerRef.current);
4991
+ }, [containerRef]);
4904
4992
  const value = useMemo(
4905
4993
  () => ({
4906
4994
  routeKey,
4907
4995
  isTraversal,
4908
- anchorAttribute
4996
+ anchorAttribute,
4997
+ setScrollContainer
4909
4998
  }),
4910
- [routeKey, isTraversal, anchorAttribute]
4999
+ [routeKey, isTraversal, anchorAttribute, setScrollContainer]
4911
5000
  );
4912
5001
  useEffect(() => {
4913
5002
  if (typeof window === "undefined" || !("scrollRestoration" in history)) {
@@ -4922,34 +5011,50 @@ function ScrollRestorationProvider({
4922
5011
  const prevRouteKeyRef = useRef(routeKey);
4923
5012
  const anchorAttributeRef = useRef(anchorAttribute);
4924
5013
  anchorAttributeRef.current = anchorAttribute;
5014
+ useLayoutEffect(() => {
5015
+ const nodes = [document.documentElement];
5016
+ const container = readActiveContainer();
5017
+ if (container) nodes.push(container);
5018
+ const previous = nodes.map((node) => node.style.overflowAnchor);
5019
+ for (const node of nodes) node.style.overflowAnchor = "none";
5020
+ return () => {
5021
+ nodes.forEach((node, index) => {
5022
+ node.style.overflowAnchor = previous[index] ?? "";
5023
+ });
5024
+ };
5025
+ }, [readActiveContainer, scrollContainerNode]);
4925
5026
  useEffect(() => {
4926
- const container = readContainer(containerRef);
4927
- const target = container ?? window;
5027
+ const container = readActiveContainer();
4928
5028
  let rafId = 0;
4929
5029
  const onScroll = () => {
5030
+ if (isProgrammaticScroll()) return;
4930
5031
  if (rafId) return;
4931
5032
  rafId = requestAnimationFrame(() => {
4932
5033
  rafId = 0;
4933
5034
  setScrollMark(
4934
5035
  routeKey,
4935
- captureMark(readContainer(containerRef), anchorAttribute)
5036
+ captureMark(readActiveContainer(), anchorAttribute)
4936
5037
  );
4937
5038
  });
4938
5039
  };
4939
- target.addEventListener("scroll", onScroll, { passive: true });
5040
+ window.addEventListener("scroll", onScroll, { passive: true });
5041
+ container?.addEventListener("scroll", onScroll, { passive: true });
4940
5042
  return () => {
4941
- target.removeEventListener("scroll", onScroll);
5043
+ window.removeEventListener("scroll", onScroll);
5044
+ container?.removeEventListener("scroll", onScroll);
4942
5045
  if (rafId) cancelAnimationFrame(rafId);
4943
5046
  };
4944
- }, [routeKey, containerRef, anchorAttribute]);
5047
+ }, [routeKey, anchorAttribute, readActiveContainer, scrollContainerNode]);
4945
5048
  useLayoutEffect(() => {
4946
- const container = readContainer(containerRef);
5049
+ const container = readActiveContainer();
4947
5050
  const prevKey = prevRouteKeyRef.current;
4948
5051
  if (prevKey !== routeKey) {
4949
- setScrollMark(
4950
- prevKey,
4951
- captureMark(container, anchorAttributeRef.current)
4952
- );
5052
+ const fresh = captureMark(container, anchorAttributeRef.current);
5053
+ const existing = getScrollMark(prevKey);
5054
+ const paneUnmounted = existing?.port === "container" && fresh.port === "window" && fresh.top === 0 && container === null;
5055
+ if (!paneUnmounted) {
5056
+ setScrollMark(prevKey, fresh);
5057
+ }
4953
5058
  prevRouteKeyRef.current = routeKey;
4954
5059
  }
4955
5060
  const hasHash = typeof window !== "undefined" && window.location.hash.length > 1;
@@ -4957,51 +5062,58 @@ function ScrollRestorationProvider({
4957
5062
  consumePendingTraversal(routeKey);
4958
5063
  const mark = getScrollMark(routeKey);
4959
5064
  if (!mark) return void 0;
4960
- applyMark(container, mark, anchorAttribute);
4961
- return startStabilizationLoop(container, mark, anchorAttribute);
5065
+ restoreScrollports(container, mark, anchorAttribute);
5066
+ return startStabilizationLoop(
5067
+ () => readActiveContainer(),
5068
+ mark,
5069
+ anchorAttribute
5070
+ );
4962
5071
  }
4963
5072
  clearRoute(routeKey);
4964
- if (!hasHash) {
4965
- setScrollTop(container, 0);
4966
- }
4967
- return void 0;
4968
- }, [routeKey, isTraversal, containerRef, anchorAttribute]);
5073
+ if (hasHash) return void 0;
5074
+ return startFreshReset(readActiveContainer);
5075
+ }, [routeKey, isTraversal, anchorAttribute, readActiveContainer]);
4969
5076
  return /* @__PURE__ */ jsx(ScrollRestorationContext.Provider, { value, children });
4970
5077
  }
4971
- function startStabilizationLoop(container, mark, attribute) {
5078
+ function startFreshReset(readContainer2) {
5079
+ let cancelled = false;
5080
+ const apply = () => {
5081
+ if (cancelled) return;
5082
+ resetScrollports(readContainer2());
5083
+ };
5084
+ apply();
5085
+ let rafId = requestAnimationFrame(() => {
5086
+ rafId = 0;
5087
+ apply();
5088
+ });
5089
+ const stopIntent = listenForUserIntent(() => {
5090
+ cancelled = true;
5091
+ if (rafId) cancelAnimationFrame(rafId);
5092
+ rafId = 0;
5093
+ });
5094
+ return () => {
5095
+ cancelled = true;
5096
+ if (rafId) cancelAnimationFrame(rafId);
5097
+ stopIntent();
5098
+ };
5099
+ }
5100
+ function startStabilizationLoop(readContainer2, mark, attribute) {
5101
+ const portNode2 = () => (mark.port ?? "window") === "container" ? readContainer2() : null;
4972
5102
  const startedAt = performance.now();
4973
- let lastHeight = getScrollHeight(container);
5103
+ let lastHeight = getScrollHeight(portNode2());
4974
5104
  let rafId = 0;
4975
5105
  let aborted = false;
4976
5106
  const abort = () => {
4977
5107
  aborted = true;
4978
5108
  };
4979
- const onUserIntent = () => {
4980
- abort();
4981
- };
4982
- window.addEventListener("wheel", onUserIntent, {
4983
- passive: true,
4984
- once: true
4985
- });
4986
- window.addEventListener("touchstart", onUserIntent, {
4987
- passive: true,
4988
- once: true
4989
- });
4990
- window.addEventListener("keydown", onUserIntent, {
4991
- passive: true,
4992
- once: true
4993
- });
4994
- window.addEventListener("pointerdown", onUserIntent, {
4995
- passive: true,
4996
- once: true
4997
- });
5109
+ const stopIntent = listenForUserIntent(abort);
4998
5110
  const tick = () => {
4999
5111
  if (aborted) return;
5000
5112
  if (performance.now() - startedAt > STABILIZE_MS) return;
5001
- const height = getScrollHeight(container);
5113
+ const height = getScrollHeight(portNode2());
5002
5114
  if (height !== lastHeight) {
5003
5115
  lastHeight = height;
5004
- applyMark(container, mark, attribute);
5116
+ restoreScrollports(readContainer2(), mark, attribute);
5005
5117
  }
5006
5118
  rafId = requestAnimationFrame(tick);
5007
5119
  };
@@ -5009,10 +5121,7 @@ function startStabilizationLoop(container, mark, attribute) {
5009
5121
  return () => {
5010
5122
  abort();
5011
5123
  if (rafId) cancelAnimationFrame(rafId);
5012
- window.removeEventListener("wheel", onUserIntent);
5013
- window.removeEventListener("touchstart", onUserIntent);
5014
- window.removeEventListener("keydown", onUserIntent);
5015
- window.removeEventListener("pointerdown", onUserIntent);
5124
+ stopIntent();
5016
5125
  };
5017
5126
  }
5018
5127
 
@@ -8082,7 +8191,652 @@ function useRealtimeChannel({
8082
8191
  };
8083
8192
  }, [enabled, reconnectDelayMs]);
8084
8193
  }
8194
+ var badgeVariants = cva(
8195
+ "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3",
8196
+ {
8197
+ variants: {
8198
+ variant: {
8199
+ default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
8200
+ secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
8201
+ destructive: "bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90",
8202
+ outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
8203
+ ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
8204
+ link: "text-primary underline-offset-4 [a&]:hover:underline"
8205
+ }
8206
+ },
8207
+ defaultVariants: {
8208
+ variant: "default"
8209
+ }
8210
+ }
8211
+ );
8212
+ function Badge({
8213
+ className,
8214
+ variant = "default",
8215
+ asChild = false,
8216
+ ...props
8217
+ }) {
8218
+ const Comp = asChild ? Slot$1.Root : "span";
8219
+ return /* @__PURE__ */ jsx(
8220
+ Comp,
8221
+ {
8222
+ "data-slot": "badge",
8223
+ "data-variant": variant,
8224
+ className: cn(badgeVariants({ variant }), className),
8225
+ ...props
8226
+ }
8227
+ );
8228
+ }
8229
+ var INVITE_EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/i;
8230
+ var INVITE_STATUS_CLASS = {
8231
+ pending: "border-amber-500/40 bg-amber-500/15 font-medium text-amber-800 dark:text-amber-300",
8232
+ claimed: "border-emerald-500/40 bg-emerald-500/15 font-medium text-emerald-800 dark:text-emerald-300",
8233
+ failed: "border-destructive/40 bg-destructive/15 font-medium text-destructive",
8234
+ cancelled: "text-muted-foreground"
8235
+ };
8236
+ var INVITE_STATUS_LABELS = {
8237
+ es: {
8238
+ pending: "Pendiente",
8239
+ claimed: "Registrado",
8240
+ failed: "Con error",
8241
+ cancelled: "Cancelada"
8242
+ },
8243
+ en: {
8244
+ pending: "Pending",
8245
+ claimed: "Registered",
8246
+ failed: "Error",
8247
+ cancelled: "Cancelled"
8248
+ }
8249
+ };
8250
+ function inviteStatusLabel(status, language) {
8251
+ const labels = language.startsWith("en") ? INVITE_STATUS_LABELS.en : INVITE_STATUS_LABELS.es;
8252
+ switch (status) {
8253
+ case "pending":
8254
+ case "claimed":
8255
+ case "failed":
8256
+ case "cancelled":
8257
+ return labels[status];
8258
+ default:
8259
+ return status;
8260
+ }
8261
+ }
8262
+ function resendWaitMessage(waitSeconds) {
8263
+ const total = Math.max(0, Math.ceil(waitSeconds));
8264
+ if (total < 60) {
8265
+ const secondLabel2 = total === 1 ? "segundo" : "segundos";
8266
+ return `Espera ${total} ${secondLabel2} antes de reenviar`;
8267
+ }
8268
+ const minutes = Math.floor(total / 60);
8269
+ const seconds = total % 60;
8270
+ const minuteLabel = minutes === 1 ? "minuto" : "minutos";
8271
+ if (seconds === 0)
8272
+ return `Espera ${minutes} ${minuteLabel} antes de reenviar`;
8273
+ const secondLabel = seconds === 1 ? "segundo" : "segundos";
8274
+ return `Espera ${minutes} ${minuteLabel} y ${seconds} ${secondLabel} antes de reenviar`;
8275
+ }
8276
+ function isInviteEmail(value) {
8277
+ const email = value.trim().toLowerCase();
8278
+ return email.length > 0 && email.length <= 320 && INVITE_EMAIL_RE.test(email);
8279
+ }
8280
+ function mergeInviteEmails(current, raw) {
8281
+ const pills = [...current];
8282
+ const seen = new Set(pills);
8283
+ const invalid = [];
8284
+ for (const part of raw.split(/[\n,;]+/)) {
8285
+ const token = part.trim();
8286
+ if (!token) continue;
8287
+ const email = token.toLowerCase();
8288
+ if (!isInviteEmail(email)) {
8289
+ invalid.push(token);
8290
+ continue;
8291
+ }
8292
+ if (seen.has(email)) continue;
8293
+ seen.add(email);
8294
+ pills.push(email);
8295
+ }
8296
+ return { pills, invalid };
8297
+ }
8298
+ async function readJson(res) {
8299
+ return await res.json();
8300
+ }
8301
+ function MembershipInvitePanel({
8302
+ basePath,
8303
+ query,
8304
+ onQueryChange,
8305
+ onNotify,
8306
+ onConfigure
8307
+ }) {
8308
+ const language = useLanguageContext()?.language ?? "es";
8309
+ const [configured, setConfigured] = useState(null);
8310
+ const [types, setTypes] = useState([]);
8311
+ const [tab, setTab] = useState("emails");
8312
+ const [emailPills, setEmailPills] = useState([]);
8313
+ const [emailDraft, setEmailDraft] = useState("");
8314
+ const [csvText, setCsvText] = useState("");
8315
+ const [typeId, setTypeId] = useState("");
8316
+ const [paidUp, setPaidUp] = useState(null);
8317
+ const [unpaidPolicy, setUnpaidPolicy] = useState("lapsed_with_charge");
8318
+ const [graceDays, setGraceDays] = useState("30");
8319
+ const [sendInvites, setSendInvites] = useState(true);
8320
+ const [preview, setPreview] = useState(null);
8321
+ const [busy, setBusy] = useState(false);
8322
+ const [items, setItems] = useState([]);
8323
+ const [nextCursor, setNextCursor] = useState(null);
8324
+ const [listLoading, setListLoading] = useState(true);
8325
+ const [draftQ, setDraftQ] = useState(query.q);
8326
+ const [cancelId, setCancelId] = useState(null);
8327
+ const [refresh, setRefresh] = useState(0);
8328
+ useEffect(() => {
8329
+ let cancelled = false;
8330
+ void (async () => {
8331
+ const res = await fetch(`${basePath}/membership-invites/options`, {
8332
+ credentials: "include"
8333
+ });
8334
+ const body = await readJson(res);
8335
+ if (cancelled) return;
8336
+ const result = body.result;
8337
+ setConfigured(Boolean(result?.configured));
8338
+ const nextTypes = result?.types ?? [];
8339
+ setTypes(nextTypes);
8340
+ setTypeId((current) => current || nextTypes[0]?.id || "");
8341
+ })();
8342
+ return () => {
8343
+ cancelled = true;
8344
+ };
8345
+ }, [basePath]);
8346
+ useEffect(() => {
8347
+ const handle = setTimeout(() => {
8348
+ if (draftQ !== query.q)
8349
+ onQueryChange({ q: draftQ, status: query.status });
8350
+ }, 300);
8351
+ return () => clearTimeout(handle);
8352
+ }, [draftQ, onQueryChange, query.q, query.status]);
8353
+ useEffect(() => {
8354
+ let cancelled = false;
8355
+ setListLoading(true);
8356
+ const params = new URLSearchParams();
8357
+ if (query.q) params.set("q", query.q);
8358
+ if (query.status) params.set("status", query.status);
8359
+ params.set("limit", "20");
8360
+ void (async () => {
8361
+ const res = await fetch(
8362
+ `${basePath}/membership-invites?${params.toString()}`,
8363
+ { credentials: "include" }
8364
+ );
8365
+ const body = await readJson(res);
8366
+ if (cancelled) return;
8367
+ const result = body.result;
8368
+ setItems(result?.items ?? []);
8369
+ setNextCursor(result?.nextCursor ?? null);
8370
+ setListLoading(false);
8371
+ })();
8372
+ return () => {
8373
+ cancelled = true;
8374
+ };
8375
+ }, [basePath, query.q, query.status, refresh]);
8376
+ if (configured === null)
8377
+ return /* @__PURE__ */ jsx(LoadingState, { label: "Cargando invitaciones\u2026" });
8378
+ if (!configured) {
8379
+ return /* @__PURE__ */ jsx(
8380
+ EmptyState,
8381
+ {
8382
+ title: "Configura la membres\xEDa primero",
8383
+ description: "El colegio necesita un modo de suscripci\xF3n y al menos un tipo activo.",
8384
+ action: onConfigure ? /* @__PURE__ */ jsx(Button, { type: "button", onClick: onConfigure, children: "Ir a configuraci\xF3n" }) : void 0
8385
+ }
8386
+ );
8387
+ }
8388
+ function applyEmailDraft() {
8389
+ const next = mergeInviteEmails(emailPills, emailDraft);
8390
+ setEmailPills(next.pills);
8391
+ setEmailDraft(next.invalid.join("\n"));
8392
+ if (next.invalid.length > 0) onNotify?.("Correo no v\xE1lido", "error");
8393
+ return next;
8394
+ }
8395
+ function emailSourceText() {
8396
+ if (tab !== "emails") return "";
8397
+ const next = applyEmailDraft();
8398
+ return next.invalid.length > 0 ? null : next.pills.join("\n");
8399
+ }
8400
+ const payload = (emailText) => ({
8401
+ source: tab === "emails" ? { kind: "emails", text: emailText } : { kind: "csv", text: csvText },
8402
+ defaults: { defaultTypeId: typeId, defaultPaidUp: paidUp === true },
8403
+ options: {
8404
+ unpaidPolicy,
8405
+ unpaidGraceDays: unpaidPolicy === "active_with_charge" ? Number(graceDays) || 30 : void 0,
8406
+ sendInvites
8407
+ }
8408
+ });
8409
+ async function runPreview() {
8410
+ if (paidUp === null) {
8411
+ onNotify?.("Elige si est\xE1n al corriente", "error");
8412
+ return;
8413
+ }
8414
+ const emailText = emailSourceText();
8415
+ if (emailText === null) return;
8416
+ setBusy(true);
8417
+ try {
8418
+ const res = await fetch(`${basePath}/membership-invites/preview`, {
8419
+ method: "POST",
8420
+ credentials: "include",
8421
+ headers: { "content-type": "application/json" },
8422
+ body: JSON.stringify(payload(emailText))
8423
+ });
8424
+ const body = await readJson(res);
8425
+ if (!res.ok || !body.success) {
8426
+ onNotify?.(body.error ?? "No se pudo revisar", "error");
8427
+ return;
8428
+ }
8429
+ const result = body.result;
8430
+ setPreview(result.rows ?? []);
8431
+ } finally {
8432
+ setBusy(false);
8433
+ }
8434
+ }
8435
+ async function runCommit() {
8436
+ const emailText = emailSourceText();
8437
+ if (emailText === null) return;
8438
+ setBusy(true);
8439
+ try {
8440
+ const res = await fetch(`${basePath}/membership-invites`, {
8441
+ method: "POST",
8442
+ credentials: "include",
8443
+ headers: { "content-type": "application/json" },
8444
+ body: JSON.stringify(payload(emailText))
8445
+ });
8446
+ const body = await readJson(res);
8447
+ if (!res.ok || !body.success) {
8448
+ onNotify?.(body.error ?? "No se pudo guardar", "error");
8449
+ return;
8450
+ }
8451
+ onNotify?.("Invitaciones guardadas", "success");
8452
+ setPreview(null);
8453
+ setEmailPills([]);
8454
+ setEmailDraft("");
8455
+ setCsvText("");
8456
+ setRefresh((value) => value + 1);
8457
+ } finally {
8458
+ setBusy(false);
8459
+ }
8460
+ }
8461
+ async function downloadTemplate() {
8462
+ const res = await fetch(`${basePath}/membership-invites/template`, {
8463
+ credentials: "include"
8464
+ });
8465
+ const blob = await res.blob();
8466
+ const url = URL.createObjectURL(blob);
8467
+ const anchor = document.createElement("a");
8468
+ anchor.href = url;
8469
+ anchor.download = "membership-invites.csv";
8470
+ anchor.click();
8471
+ URL.revokeObjectURL(url);
8472
+ }
8473
+ async function loadMore() {
8474
+ if (!nextCursor) return;
8475
+ const params = new URLSearchParams();
8476
+ if (query.q) params.set("q", query.q);
8477
+ if (query.status) params.set("status", query.status);
8478
+ params.set("limit", "20");
8479
+ params.set("cursor", nextCursor);
8480
+ const res = await fetch(
8481
+ `${basePath}/membership-invites?${params.toString()}`,
8482
+ { credentials: "include" }
8483
+ );
8484
+ const body = await readJson(res);
8485
+ const result = body.result;
8486
+ setItems((current) => [...current, ...result?.items ?? []]);
8487
+ setNextCursor(result?.nextCursor ?? null);
8488
+ }
8489
+ async function sendOne(id) {
8490
+ const res = await fetch(`${basePath}/membership-invites/${id}/send`, {
8491
+ method: "POST",
8492
+ credentials: "include"
8493
+ });
8494
+ const body = await readJson(res);
8495
+ if (!res.ok) {
8496
+ onNotify?.(
8497
+ body.error === "throttled" ? typeof body.waitSeconds === "number" ? resendWaitMessage(body.waitSeconds) : "Espera unos minutos antes de reenviar" : body.error ?? "No se pudo enviar",
8498
+ "error"
8499
+ );
8500
+ return;
8501
+ }
8502
+ onNotify?.("Invitaci\xF3n enviada", "success");
8503
+ }
8504
+ async function confirmCancel() {
8505
+ if (!cancelId) return;
8506
+ const id = cancelId;
8507
+ setCancelId(null);
8508
+ const res = await fetch(`${basePath}/membership-invites/${id}/cancel`, {
8509
+ method: "POST",
8510
+ credentials: "include"
8511
+ });
8512
+ if (!res.ok) {
8513
+ onNotify?.("No se pudo cancelar", "error");
8514
+ return;
8515
+ }
8516
+ setItems(
8517
+ (current) => current.map(
8518
+ (row) => row.id === id ? { ...row, status: "cancelled" } : row
8519
+ )
8520
+ );
8521
+ onNotify?.("Invitaci\xF3n cancelada", "success");
8522
+ }
8523
+ const invalidPreview = preview?.some((row) => row.outcome === "invalid");
8524
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-8", children: [
8525
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8526
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", role: "tablist", children: [
8527
+ /* @__PURE__ */ jsx(
8528
+ Button,
8529
+ {
8530
+ type: "button",
8531
+ variant: tab === "emails" ? "default" : "outline",
8532
+ onClick: () => setTab("emails"),
8533
+ children: "Correos"
8534
+ }
8535
+ ),
8536
+ /* @__PURE__ */ jsx(
8537
+ Button,
8538
+ {
8539
+ type: "button",
8540
+ variant: tab === "csv" ? "default" : "outline",
8541
+ onClick: () => setTab("csv"),
8542
+ children: "CSV"
8543
+ }
8544
+ )
8545
+ ] }),
8546
+ tab === "emails" ? /* @__PURE__ */ jsxs("div", { className: "border-input bg-background focus-within:border-ring focus-within:ring-ring/50 flex min-h-28 w-full flex-wrap items-center gap-1.5 rounded-md border px-2 py-2 focus-within:ring-[3px]", children: [
8547
+ emailPills.map((email) => /* @__PURE__ */ jsxs(Badge, { variant: "secondary", children: [
8548
+ email,
8549
+ /* @__PURE__ */ jsx(
8550
+ Button,
8551
+ {
8552
+ type: "button",
8553
+ variant: "ghost",
8554
+ size: "icon-sm",
8555
+ className: "size-4",
8556
+ "aria-label": `Quitar ${email}`,
8557
+ onClick: () => setEmailPills(
8558
+ (current) => current.filter((item) => item !== email)
8559
+ ),
8560
+ children: /* @__PURE__ */ jsx(X, {})
8561
+ }
8562
+ )
8563
+ ] }, email)),
8564
+ /* @__PURE__ */ jsx(
8565
+ Input,
8566
+ {
8567
+ "aria-label": "Correos",
8568
+ className: "h-8 min-w-40 flex-1 border-0 bg-transparent px-1 shadow-none focus-visible:border-transparent focus-visible:ring-0 dark:bg-transparent",
8569
+ placeholder: emailPills.length === 0 ? "Escribe un correo y pulsa Enter" : "",
8570
+ value: emailDraft,
8571
+ onChange: (event) => setEmailDraft(event.target.value),
8572
+ onKeyDown: (event) => {
8573
+ if (event.key === "Enter" || event.key === ",") {
8574
+ event.preventDefault();
8575
+ applyEmailDraft();
8576
+ return;
8577
+ }
8578
+ if (event.key === "Backspace" && emailDraft.length === 0 && emailPills.length > 0) {
8579
+ event.preventDefault();
8580
+ setEmailPills((current) => current.slice(0, -1));
8581
+ }
8582
+ },
8583
+ onPaste: (event) => {
8584
+ const text = event.clipboardData.getData("text");
8585
+ if (!/[\n,;]/.test(text) && !isInviteEmail(text)) return;
8586
+ event.preventDefault();
8587
+ const next = mergeInviteEmails(
8588
+ emailPills,
8589
+ `${emailDraft}${text}`
8590
+ );
8591
+ setEmailPills(next.pills);
8592
+ setEmailDraft(next.invalid.join("\n"));
8593
+ if (next.invalid.length > 0)
8594
+ onNotify?.("Correo no v\xE1lido", "error");
8595
+ }
8596
+ }
8597
+ )
8598
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
8599
+ /* @__PURE__ */ jsx(
8600
+ Button,
8601
+ {
8602
+ type: "button",
8603
+ variant: "outline",
8604
+ onClick: () => void downloadTemplate(),
8605
+ children: "Descargar plantilla"
8606
+ }
8607
+ ),
8608
+ /* @__PURE__ */ jsx(
8609
+ Input,
8610
+ {
8611
+ "aria-label": "Archivo CSV",
8612
+ type: "file",
8613
+ accept: ".csv,text/csv",
8614
+ onChange: (event) => {
8615
+ const file = event.target.files?.[0];
8616
+ if (!file) return;
8617
+ void file.text().then(setCsvText);
8618
+ }
8619
+ }
8620
+ )
8621
+ ] }),
8622
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-sm", children: [
8623
+ /* @__PURE__ */ jsx("span", { children: "Tipo de membres\xEDa" }),
8624
+ /* @__PURE__ */ jsx(
8625
+ "select",
8626
+ {
8627
+ "aria-label": "Tipo de membres\xEDa",
8628
+ className: "border-input bg-background h-9 w-full rounded-md border px-2",
8629
+ value: typeId,
8630
+ onChange: (event) => setTypeId(event.target.value),
8631
+ children: types.map((type) => /* @__PURE__ */ jsx("option", { value: type.id, children: type.name }, type.id))
8632
+ }
8633
+ )
8634
+ ] }),
8635
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-sm", children: [
8636
+ /* @__PURE__ */ jsx("span", { children: "\xBFAl corriente?" }),
8637
+ /* @__PURE__ */ jsxs(
8638
+ "select",
8639
+ {
8640
+ "aria-label": "Al corriente",
8641
+ className: "border-input bg-background h-9 w-full rounded-md border px-2",
8642
+ value: paidUp === null ? "" : paidUp ? "yes" : "no",
8643
+ onChange: (event) => {
8644
+ if (event.target.value === "yes") setPaidUp(true);
8645
+ else if (event.target.value === "no") setPaidUp(false);
8646
+ else setPaidUp(null);
8647
+ },
8648
+ children: [
8649
+ /* @__PURE__ */ jsx("option", { value: "", children: "Elige una opci\xF3n" }),
8650
+ /* @__PURE__ */ jsx("option", { value: "yes", children: "S\xED, al corriente" }),
8651
+ /* @__PURE__ */ jsx("option", { value: "no", children: "No" })
8652
+ ]
8653
+ }
8654
+ )
8655
+ ] }),
8656
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-sm", children: [
8657
+ /* @__PURE__ */ jsx("span", { children: "Si no est\xE1n al corriente" }),
8658
+ /* @__PURE__ */ jsxs(
8659
+ "select",
8660
+ {
8661
+ "aria-label": "Pol\xEDtica de adeudo",
8662
+ className: "border-input bg-background h-9 w-full rounded-md border px-2",
8663
+ value: unpaidPolicy,
8664
+ onChange: (event) => setUnpaidPolicy(event.target.value),
8665
+ children: [
8666
+ /* @__PURE__ */ jsx("option", { value: "lapsed_with_charge", children: "Socio reconocido, sin acceso hasta que pague" }),
8667
+ /* @__PURE__ */ jsx("option", { value: "active_with_charge", children: "Con acceso por unos d\xEDas y un cargo abierto" }),
8668
+ /* @__PURE__ */ jsx("option", { value: "active_no_charge", children: "Activo sin cargo (no se registra el adeudo)" })
8669
+ ]
8670
+ }
8671
+ )
8672
+ ] }),
8673
+ unpaidPolicy === "active_with_charge" ? /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-sm", children: [
8674
+ /* @__PURE__ */ jsx("span", { children: "D\xEDas de acceso antes de vencer" }),
8675
+ /* @__PURE__ */ jsx(
8676
+ Input,
8677
+ {
8678
+ "aria-label": "D\xEDas de gracia",
8679
+ inputMode: "numeric",
8680
+ value: graceDays,
8681
+ onChange: (event) => setGraceDays(event.target.value)
8682
+ }
8683
+ )
8684
+ ] }) : null,
8685
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
8686
+ /* @__PURE__ */ jsx(
8687
+ "input",
8688
+ {
8689
+ type: "checkbox",
8690
+ checked: sendInvites,
8691
+ onChange: (event) => setSendInvites(event.target.checked)
8692
+ }
8693
+ ),
8694
+ "Enviar invitaciones al guardar"
8695
+ ] }),
8696
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
8697
+ /* @__PURE__ */ jsx(
8698
+ Button,
8699
+ {
8700
+ type: "button",
8701
+ variant: "outline",
8702
+ disabled: busy,
8703
+ onClick: () => void runPreview(),
8704
+ children: "Revisar"
8705
+ }
8706
+ ),
8707
+ /* @__PURE__ */ jsx(
8708
+ Button,
8709
+ {
8710
+ type: "button",
8711
+ disabled: busy || !preview || invalidPreview,
8712
+ onClick: () => void runCommit(),
8713
+ children: "Guardar"
8714
+ }
8715
+ )
8716
+ ] }),
8717
+ preview ? /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
8718
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
8719
+ /* @__PURE__ */ jsx("th", { className: "text-left", children: "Correo" }),
8720
+ /* @__PURE__ */ jsx("th", { className: "text-left", children: "Resultado" })
8721
+ ] }) }),
8722
+ /* @__PURE__ */ jsx("tbody", { children: preview.map((row) => /* @__PURE__ */ jsxs("tr", { children: [
8723
+ /* @__PURE__ */ jsx("td", { children: row.email }),
8724
+ /* @__PURE__ */ jsxs("td", { children: [
8725
+ row.outcome,
8726
+ row.errors.length > 0 ? ` (${row.errors.join(", ")})` : ""
8727
+ ] })
8728
+ ] }, `${row.line}-${row.email}`)) })
8729
+ ] }) : null
8730
+ ] }),
8731
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
8732
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-medium", children: "Invitaciones" }),
8733
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
8734
+ /* @__PURE__ */ jsx(
8735
+ Input,
8736
+ {
8737
+ "aria-label": "Buscar invitaciones",
8738
+ className: "min-w-0 flex-1",
8739
+ value: draftQ,
8740
+ onChange: (event) => setDraftQ(event.target.value),
8741
+ placeholder: "Correo o nombre"
8742
+ }
8743
+ ),
8744
+ /* @__PURE__ */ jsxs(
8745
+ "select",
8746
+ {
8747
+ "aria-label": "Estado",
8748
+ className: "border-input bg-background h-9 shrink-0 rounded-md border px-2",
8749
+ value: query.status,
8750
+ onChange: (event) => onQueryChange({ q: query.q, status: event.target.value }),
8751
+ children: [
8752
+ /* @__PURE__ */ jsx("option", { value: "", children: "Todos" }),
8753
+ /* @__PURE__ */ jsx("option", { value: "pending", children: "Pendientes" }),
8754
+ /* @__PURE__ */ jsx("option", { value: "claimed", children: "Registrados" }),
8755
+ /* @__PURE__ */ jsx("option", { value: "failed", children: "Con error" }),
8756
+ /* @__PURE__ */ jsx("option", { value: "cancelled", children: "Canceladas" })
8757
+ ]
8758
+ }
8759
+ )
8760
+ ] }),
8761
+ listLoading ? /* @__PURE__ */ jsx(LoadingState, { label: "Cargando lista\u2026" }) : null,
8762
+ !listLoading && items.length === 0 ? /* @__PURE__ */ jsx(
8763
+ EmptyState,
8764
+ {
8765
+ title: "No hay invitaciones",
8766
+ description: "Agrega correos o un CSV."
8767
+ }
8768
+ ) : null,
8769
+ /* @__PURE__ */ jsx("ul", { className: "divide-y", children: items.map((row) => /* @__PURE__ */ jsxs(
8770
+ "li",
8771
+ {
8772
+ className: "flex flex-col gap-2 py-3 sm:flex-row sm:items-center sm:justify-between",
8773
+ children: [
8774
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
8775
+ /* @__PURE__ */ jsx("p", { className: "break-all", children: row.email }),
8776
+ /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground mt-1 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-xs", children: [
8777
+ row.fullName ? /* @__PURE__ */ jsx("span", { children: row.fullName }) : null,
8778
+ /* @__PURE__ */ jsx(
8779
+ Badge,
8780
+ {
8781
+ variant: "outline",
8782
+ className: INVITE_STATUS_CLASS[row.status],
8783
+ children: inviteStatusLabel(row.status, language)
8784
+ }
8785
+ ),
8786
+ row.failureReason ? /* @__PURE__ */ jsx("span", { children: row.failureReason }) : null
8787
+ ] })
8788
+ ] }),
8789
+ row.status === "pending" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
8790
+ /* @__PURE__ */ jsx(
8791
+ Button,
8792
+ {
8793
+ type: "button",
8794
+ variant: "outline",
8795
+ onClick: () => void sendOne(row.id),
8796
+ children: "Enviar invitaci\xF3n"
8797
+ }
8798
+ ),
8799
+ /* @__PURE__ */ jsx(
8800
+ Button,
8801
+ {
8802
+ type: "button",
8803
+ variant: "ghost",
8804
+ onClick: () => setCancelId(row.id),
8805
+ children: "Cancelar"
8806
+ }
8807
+ )
8808
+ ] }) : null
8809
+ ]
8810
+ },
8811
+ row.id
8812
+ )) }),
8813
+ nextCursor ? /* @__PURE__ */ jsx(
8814
+ Button,
8815
+ {
8816
+ type: "button",
8817
+ variant: "outline",
8818
+ onClick: () => void loadMore(),
8819
+ children: "Cargar m\xE1s"
8820
+ }
8821
+ ) : null
8822
+ ] }),
8823
+ /* @__PURE__ */ jsx(
8824
+ ConfirmDestructiveDialog,
8825
+ {
8826
+ open: cancelId !== null,
8827
+ onOpenChange: (open) => {
8828
+ if (!open) setCancelId(null);
8829
+ },
8830
+ title: "Cancelar invitaci\xF3n",
8831
+ description: "Esta persona ya no quedar\xE1 registrada como socia al crear su cuenta.",
8832
+ confirmLabel: "Cancelar invitaci\xF3n",
8833
+ cancelLabel: "Volver",
8834
+ onConfirm: () => void confirmCancel()
8835
+ }
8836
+ )
8837
+ ] });
8838
+ }
8085
8839
 
8086
- export { AvatarEditor, AvatarEditorDialog, BrandX, Bubble, BubbleContent, BubbleGroup, BubbleReactions, ChatMessageList, ConfirmDestructiveDialog, DEFAULT_EDITABLE_SECTION_LABELS, DataList, DataListItem, DropdownMenuItem, DropdownMenuSeparator, EditableSection, EmojiInput, EmojiPicker, EmojiPickerPopover, EmojiTextarea, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, ErrorState, ExpandableText, FieldMessage, ImageLightbox, LanguageContext, LanguageSwitcher, LoadingState, MEXICO_STATES, MEXICO_STATE_PATHS, Marker, MarkerContent, MarkerIcon, MediaCarousel, MediaViewerDialog, Message, MessageAvatar, MessageComposer, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, MexicoMap, OrgSwitcher, PLATFORM_ACCOUNT_ORG_COLLAPSE_AT, PaymentIcon, PhoneInput, PlatformAccountMenu, PlatformNavbar, SafeImage, ScrollRestorationProvider, SearchCommand, SearchablePicker, SupportMessengerProvider, ThemeSwitcher, VerifiedProfessionalBadge, ZOOM_PAN_MAX_SCALE, ZOOM_PAN_MIN_SCALE, ZOOM_PAN_SWIPE_COMMIT_PX, ZOOM_PAN_SWIPE_SNAP_MS, avatarFallbackStyle, bubbleVariants, cn, createSupportChatClient, defaultLanguages, formatPaymentCardBrand, fuzzyMatch, getAvatarColors, getInitials, insertAtCaret, markerVariants, mergePlatformAccountOrgs, normalizeEmojiQuery, normalizePaymentCardBrand, paymentIconBrandFromStripe, paymentTypeFromStripeBrand, prefersReducedMotion, useDebouncedValue, useDebouncedValueStrict, useEditableSection, useLanguageContext, useMediaQuery2 as useMediaQuery, useRealtimeChannel, useRestorableState, useScrollFadeXEdges, useScrollRestorationContext, useSearchHotkey, useSupportConversation, useSupportMessenger, useSupportMessengerOptional, useZoomPanGestures, zoomToward };
8840
+ export { AvatarEditor, AvatarEditorDialog, BrandX, Bubble, BubbleContent, BubbleGroup, BubbleReactions, ChatMessageList, ConfirmDestructiveDialog, DEFAULT_EDITABLE_SECTION_LABELS, DataList, DataListItem, DropdownMenuItem, DropdownMenuSeparator, EditableSection, EmojiInput, EmojiPicker, EmojiPickerPopover, EmojiTextarea, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, ErrorState, ExpandableText, FieldMessage, ImageLightbox, LanguageContext, LanguageSwitcher, LoadingState, MEXICO_STATES, MEXICO_STATE_PATHS, Marker, MarkerContent, MarkerIcon, MediaCarousel, MediaViewerDialog, MembershipInvitePanel, Message, MessageAvatar, MessageComposer, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, MexicoMap, OrgSwitcher, PLATFORM_ACCOUNT_ORG_COLLAPSE_AT, PaymentIcon, PhoneInput, PlatformAccountMenu, PlatformNavbar, SafeImage, ScrollRestorationProvider, SearchCommand, SearchablePicker, SupportMessengerProvider, ThemeSwitcher, VerifiedProfessionalBadge, ZOOM_PAN_MAX_SCALE, ZOOM_PAN_MIN_SCALE, ZOOM_PAN_SWIPE_COMMIT_PX, ZOOM_PAN_SWIPE_SNAP_MS, avatarFallbackStyle, bubbleVariants, cn, createSupportChatClient, defaultLanguages, formatPaymentCardBrand, fuzzyMatch, getAvatarColors, getInitials, insertAtCaret, markerVariants, mergePlatformAccountOrgs, normalizeEmojiQuery, normalizePaymentCardBrand, paymentIconBrandFromStripe, paymentTypeFromStripeBrand, prefersReducedMotion, useDebouncedValue, useDebouncedValueStrict, useEditableSection, useLanguageContext, useMediaQuery2 as useMediaQuery, useRealtimeChannel, useRegisterScrollContainer, useRestorableState, useScrollFadeXEdges, useScrollRestorationContext, useSearchHotkey, useSupportConversation, useSupportMessenger, useSupportMessengerOptional, useZoomPanGestures, zoomToward };
8087
8841
  //# sourceMappingURL=index.js.map
8088
8842
  //# sourceMappingURL=index.js.map