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