@loafmarkets/ui 0.1.42 → 0.1.43
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.d.mts +63 -6
- package/dist/index.d.ts +63 -6
- package/dist/index.js +794 -354
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +677 -240
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React9 = require('react');
|
|
4
4
|
var reactSlot = require('@radix-ui/react-slot');
|
|
5
5
|
var classVarianceAuthority = require('class-variance-authority');
|
|
6
6
|
var clsx = require('clsx');
|
|
@@ -33,7 +33,7 @@ function _interopNamespace(e) {
|
|
|
33
33
|
return Object.freeze(n);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
var
|
|
36
|
+
var React9__namespace = /*#__PURE__*/_interopNamespace(React9);
|
|
37
37
|
var styled24__default = /*#__PURE__*/_interopDefault(styled24);
|
|
38
38
|
var LightweightCharts__namespace = /*#__PURE__*/_interopNamespace(LightweightCharts);
|
|
39
39
|
|
|
@@ -75,7 +75,7 @@ var buttonVariants = classVarianceAuthority.cva(
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
);
|
|
78
|
-
var Button =
|
|
78
|
+
var Button = React9__namespace.forwardRef(
|
|
79
79
|
({ className, variant, size, radius, asChild = false, ...props }, ref) => {
|
|
80
80
|
const Comp = asChild ? reactSlot.Slot : "button";
|
|
81
81
|
const coercedRadius = radius ?? (variant === "onboarding" || variant === "onboardingOutline" ? "square" : void 0);
|
|
@@ -114,11 +114,11 @@ var badgeVariants = classVarianceAuthority.cva(
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
);
|
|
117
|
-
var Badge =
|
|
117
|
+
var Badge = React9__namespace.forwardRef(
|
|
118
118
|
({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: cn(badgeVariants({ variant, size }), className), ...props })
|
|
119
119
|
);
|
|
120
120
|
Badge.displayName = "Badge";
|
|
121
|
-
var Card =
|
|
121
|
+
var Card = React9__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
122
122
|
"div",
|
|
123
123
|
{
|
|
124
124
|
ref,
|
|
@@ -130,11 +130,11 @@ var Card = React5__namespace.forwardRef(({ className, ...props }, ref) => /* @__
|
|
|
130
130
|
}
|
|
131
131
|
));
|
|
132
132
|
Card.displayName = "Card";
|
|
133
|
-
var CardHeader =
|
|
133
|
+
var CardHeader = React9__namespace.forwardRef(
|
|
134
134
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
|
|
135
135
|
);
|
|
136
136
|
CardHeader.displayName = "CardHeader";
|
|
137
|
-
var CardTitle =
|
|
137
|
+
var CardTitle = React9__namespace.forwardRef(
|
|
138
138
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
139
139
|
"h3",
|
|
140
140
|
{
|
|
@@ -145,15 +145,15 @@ var CardTitle = React5__namespace.forwardRef(
|
|
|
145
145
|
)
|
|
146
146
|
);
|
|
147
147
|
CardTitle.displayName = "CardTitle";
|
|
148
|
-
var CardDescription =
|
|
148
|
+
var CardDescription = React9__namespace.forwardRef(
|
|
149
149
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-slate-500", className), ...props })
|
|
150
150
|
);
|
|
151
151
|
CardDescription.displayName = "CardDescription";
|
|
152
|
-
var CardContent =
|
|
152
|
+
var CardContent = React9__namespace.forwardRef(
|
|
153
153
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("px-6 pb-6 pt-2 text-sm text-slate-600", className), ...props })
|
|
154
154
|
);
|
|
155
155
|
CardContent.displayName = "CardContent";
|
|
156
|
-
var CardFooter =
|
|
156
|
+
var CardFooter = React9__namespace.forwardRef(
|
|
157
157
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex items-center border-t border-slate-100 px-6 py-4", className), ...props })
|
|
158
158
|
);
|
|
159
159
|
CardFooter.displayName = "CardFooter";
|
|
@@ -171,7 +171,7 @@ var defaultFormatSignedCurrency = (value) => {
|
|
|
171
171
|
const sign = value >= 0 ? "+" : "-";
|
|
172
172
|
return `${sign}${defaultFormatCurrency(Math.abs(value))}`;
|
|
173
173
|
};
|
|
174
|
-
var PortfolioSummary =
|
|
174
|
+
var PortfolioSummary = React9__namespace.forwardRef(
|
|
175
175
|
({
|
|
176
176
|
availableCash,
|
|
177
177
|
portfolioValue,
|
|
@@ -321,23 +321,23 @@ function HousePositionSlider({
|
|
|
321
321
|
className,
|
|
322
322
|
...props
|
|
323
323
|
}) {
|
|
324
|
-
const [orderMode, setOrderMode] =
|
|
325
|
-
const [buyTrackingMode, setBuyTrackingMode] =
|
|
326
|
-
const [deltaDollars, setDeltaDollars] =
|
|
327
|
-
const [deltaTokensBuy, setDeltaTokensBuy] =
|
|
328
|
-
const [deltaTokensSell, setDeltaTokensSell] =
|
|
329
|
-
const [_isDragging, setIsDragging] =
|
|
330
|
-
const [visualTargetPct, setVisualTargetPct] =
|
|
331
|
-
const [orderType, setOrderType] =
|
|
332
|
-
const [limitPrice, setLimitPrice] =
|
|
333
|
-
const [limitPriceInput, setLimitPriceInput] =
|
|
334
|
-
const [limitPriceDirty, setLimitPriceDirty] =
|
|
335
|
-
const [ownershipInput, setOwnershipInput] =
|
|
336
|
-
const [tokenAmountInput, setTokenAmountInput] =
|
|
337
|
-
const houseRef =
|
|
324
|
+
const [orderMode, setOrderMode] = React9__namespace.useState("none");
|
|
325
|
+
const [buyTrackingMode, setBuyTrackingMode] = React9__namespace.useState("dollars");
|
|
326
|
+
const [deltaDollars, setDeltaDollars] = React9__namespace.useState(0);
|
|
327
|
+
const [deltaTokensBuy, setDeltaTokensBuy] = React9__namespace.useState(0);
|
|
328
|
+
const [deltaTokensSell, setDeltaTokensSell] = React9__namespace.useState(0);
|
|
329
|
+
const [_isDragging, setIsDragging] = React9__namespace.useState(false);
|
|
330
|
+
const [visualTargetPct, setVisualTargetPct] = React9__namespace.useState(null);
|
|
331
|
+
const [orderType, setOrderType] = React9__namespace.useState(defaultOrderType);
|
|
332
|
+
const [limitPrice, setLimitPrice] = React9__namespace.useState(currentPrice);
|
|
333
|
+
const [limitPriceInput, setLimitPriceInput] = React9__namespace.useState(currentPrice.toFixed(2));
|
|
334
|
+
const [limitPriceDirty, setLimitPriceDirty] = React9__namespace.useState(false);
|
|
335
|
+
const [ownershipInput, setOwnershipInput] = React9__namespace.useState("");
|
|
336
|
+
const [tokenAmountInput, setTokenAmountInput] = React9__namespace.useState("");
|
|
337
|
+
const houseRef = React9__namespace.useRef(null);
|
|
338
338
|
const asks = orderbook?.asks ?? [];
|
|
339
339
|
const bids = orderbook?.bids ?? [];
|
|
340
|
-
|
|
340
|
+
React9__namespace.useEffect(() => {
|
|
341
341
|
if (orderType !== "limit") return;
|
|
342
342
|
if (limitPriceDirty) return;
|
|
343
343
|
setLimitPrice(currentPrice);
|
|
@@ -412,7 +412,7 @@ function HousePositionSlider({
|
|
|
412
412
|
const impliedDisplayTargetOwnership = clamp(targetOwnership + ownershipShift, 0, 100);
|
|
413
413
|
const displayTargetOwnership = visualTargetPct ?? impliedDisplayTargetOwnership;
|
|
414
414
|
const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
|
|
415
|
-
const resetOrder =
|
|
415
|
+
const resetOrder = React9__namespace.useCallback(() => {
|
|
416
416
|
setOrderMode("none");
|
|
417
417
|
setBuyTrackingMode("dollars");
|
|
418
418
|
setDeltaDollars(0);
|
|
@@ -420,7 +420,7 @@ function HousePositionSlider({
|
|
|
420
420
|
setDeltaTokensSell(0);
|
|
421
421
|
setVisualTargetPct(null);
|
|
422
422
|
}, []);
|
|
423
|
-
const updateOrderFromTargetValue =
|
|
423
|
+
const updateOrderFromTargetValue = React9__namespace.useCallback(
|
|
424
424
|
(newTargetValue) => {
|
|
425
425
|
const newDeltaValue = newTargetValue - holdingsValue;
|
|
426
426
|
if (newDeltaValue > 0) {
|
|
@@ -444,7 +444,7 @@ function HousePositionSlider({
|
|
|
444
444
|
},
|
|
445
445
|
[effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, resetOrder, tokensHeld]
|
|
446
446
|
);
|
|
447
|
-
const updateOrderFromOwnership =
|
|
447
|
+
const updateOrderFromOwnership = React9__namespace.useCallback(
|
|
448
448
|
(newOwnershipPercent) => {
|
|
449
449
|
const nextOwnership = clamp(newOwnershipPercent, 0, 100);
|
|
450
450
|
const newTargetTokens = nextOwnership / 100 * totalTokens;
|
|
@@ -453,7 +453,7 @@ function HousePositionSlider({
|
|
|
453
453
|
},
|
|
454
454
|
[effectivePrice, totalTokens, updateOrderFromTargetValue]
|
|
455
455
|
);
|
|
456
|
-
const updateOrderFromTokenAmount =
|
|
456
|
+
const updateOrderFromTokenAmount = React9__namespace.useCallback(
|
|
457
457
|
(tokenAmountSigned) => {
|
|
458
458
|
if (tokenAmountSigned > 0) {
|
|
459
459
|
const maxTokens = effectiveAvailableCash / (effectivePrice || 1);
|
|
@@ -476,7 +476,7 @@ function HousePositionSlider({
|
|
|
476
476
|
},
|
|
477
477
|
[effectiveAvailableCash, effectivePrice, effectiveTokensHeld, resetOrder]
|
|
478
478
|
);
|
|
479
|
-
const updateOrderFromSlider =
|
|
479
|
+
const updateOrderFromSlider = React9__namespace.useCallback(
|
|
480
480
|
(pct) => {
|
|
481
481
|
const normalized = (pct - 50) / 50;
|
|
482
482
|
const magnitude = Math.min(Math.abs(normalized), 1);
|
|
@@ -520,7 +520,7 @@ function HousePositionSlider({
|
|
|
520
520
|
},
|
|
521
521
|
[effectiveAvailableCash, effectiveTokensHeld, resetOrder]
|
|
522
522
|
);
|
|
523
|
-
const handleDragAtClientY =
|
|
523
|
+
const handleDragAtClientY = React9__namespace.useCallback(
|
|
524
524
|
(clientY) => {
|
|
525
525
|
if (!houseRef.current) return;
|
|
526
526
|
const rect = houseRef.current.getBoundingClientRect();
|
|
@@ -1036,18 +1036,18 @@ function HousePositionSliderMobile({
|
|
|
1036
1036
|
className,
|
|
1037
1037
|
...props
|
|
1038
1038
|
}) {
|
|
1039
|
-
const [orderMode, setOrderMode] =
|
|
1040
|
-
const [deltaDollars, setDeltaDollars] =
|
|
1041
|
-
const [deltaTokensSell, setDeltaTokensSell] =
|
|
1042
|
-
const [deltaTokensBuy, setDeltaTokensBuy] =
|
|
1043
|
-
const [buyTrackingMode, setBuyTrackingMode] =
|
|
1044
|
-
const [orderType, setOrderType] =
|
|
1045
|
-
const [limitPrice, setLimitPrice] =
|
|
1046
|
-
const [limitPriceInput, setLimitPriceInput] =
|
|
1047
|
-
const [limitPriceDirty, setLimitPriceDirty] =
|
|
1048
|
-
const [tokenAmountInput, setTokenAmountInput] =
|
|
1049
|
-
const houseRef =
|
|
1050
|
-
|
|
1039
|
+
const [orderMode, setOrderMode] = React9__namespace.useState("none");
|
|
1040
|
+
const [deltaDollars, setDeltaDollars] = React9__namespace.useState(0);
|
|
1041
|
+
const [deltaTokensSell, setDeltaTokensSell] = React9__namespace.useState(0);
|
|
1042
|
+
const [deltaTokensBuy, setDeltaTokensBuy] = React9__namespace.useState(0);
|
|
1043
|
+
const [buyTrackingMode, setBuyTrackingMode] = React9__namespace.useState("dollars");
|
|
1044
|
+
const [orderType, setOrderType] = React9__namespace.useState(defaultOrderType);
|
|
1045
|
+
const [limitPrice, setLimitPrice] = React9__namespace.useState(currentPrice);
|
|
1046
|
+
const [limitPriceInput, setLimitPriceInput] = React9__namespace.useState(currentPrice.toFixed(2));
|
|
1047
|
+
const [limitPriceDirty, setLimitPriceDirty] = React9__namespace.useState(false);
|
|
1048
|
+
const [tokenAmountInput, setTokenAmountInput] = React9__namespace.useState("");
|
|
1049
|
+
const houseRef = React9__namespace.useRef(null);
|
|
1050
|
+
React9__namespace.useEffect(() => {
|
|
1051
1051
|
if (orderType !== "limit") return;
|
|
1052
1052
|
if (limitPriceDirty) return;
|
|
1053
1053
|
setLimitPrice(currentPrice);
|
|
@@ -1089,7 +1089,7 @@ function HousePositionSliderMobile({
|
|
|
1089
1089
|
const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
|
|
1090
1090
|
const targetOwnership = totalTokens > 0 ? targetTokens / totalTokens * 100 : 0;
|
|
1091
1091
|
const estFeeTokens = effectivePrice > 0 ? Math.abs(deltaValue) * 5e-3 / effectivePrice : 0;
|
|
1092
|
-
const updateOrderFromTargetValue =
|
|
1092
|
+
const updateOrderFromTargetValue = React9__namespace.useCallback(
|
|
1093
1093
|
(newTargetValue) => {
|
|
1094
1094
|
const newDeltaValue = newTargetValue - holdingsValue;
|
|
1095
1095
|
if (newDeltaValue > 0.01) {
|
|
@@ -1117,7 +1117,7 @@ function HousePositionSliderMobile({
|
|
|
1117
1117
|
},
|
|
1118
1118
|
[holdingsValue, availableCash, effectivePrice, tokensHeld]
|
|
1119
1119
|
);
|
|
1120
|
-
const updateOrderFromTokenAmount =
|
|
1120
|
+
const updateOrderFromTokenAmount = React9__namespace.useCallback(
|
|
1121
1121
|
(tokenAmount) => {
|
|
1122
1122
|
if (tokenAmount > 0) {
|
|
1123
1123
|
const maxTokens = effectivePrice > 0 ? availableCash / effectivePrice : 0;
|
|
@@ -1144,14 +1144,14 @@ function HousePositionSliderMobile({
|
|
|
1144
1144
|
},
|
|
1145
1145
|
[effectivePrice, availableCash, tokensHeld]
|
|
1146
1146
|
);
|
|
1147
|
-
const handleMarkerClick =
|
|
1147
|
+
const handleMarkerClick = React9__namespace.useCallback(
|
|
1148
1148
|
(pct) => {
|
|
1149
1149
|
const newTargetValue = pct / 100 * totalCapacity;
|
|
1150
1150
|
updateOrderFromTargetValue(newTargetValue);
|
|
1151
1151
|
},
|
|
1152
1152
|
[totalCapacity, updateOrderFromTargetValue]
|
|
1153
1153
|
);
|
|
1154
|
-
const onMouseDown =
|
|
1154
|
+
const onMouseDown = React9__namespace.useCallback(
|
|
1155
1155
|
(e) => {
|
|
1156
1156
|
e.preventDefault();
|
|
1157
1157
|
const move = (ev) => {
|
|
@@ -1171,7 +1171,7 @@ function HousePositionSliderMobile({
|
|
|
1171
1171
|
},
|
|
1172
1172
|
[totalCapacity, updateOrderFromTargetValue]
|
|
1173
1173
|
);
|
|
1174
|
-
const onTouchStart =
|
|
1174
|
+
const onTouchStart = React9__namespace.useCallback(
|
|
1175
1175
|
(e) => {
|
|
1176
1176
|
e.preventDefault();
|
|
1177
1177
|
e.stopPropagation();
|
|
@@ -1729,7 +1729,7 @@ var LiquidityText = styled24__default.default.span`
|
|
|
1729
1729
|
letter-spacing: 0.1px;
|
|
1730
1730
|
}
|
|
1731
1731
|
`;
|
|
1732
|
-
var LoafLiquidityBadge =
|
|
1732
|
+
var LoafLiquidityBadge = React9__namespace.forwardRef(
|
|
1733
1733
|
({ className, isGlowing, onClick, children, ...props }, ref) => {
|
|
1734
1734
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1735
1735
|
LogoContainer,
|
|
@@ -1757,9 +1757,34 @@ var LoafLiquidityBadge = React5__namespace.forwardRef(
|
|
|
1757
1757
|
}
|
|
1758
1758
|
);
|
|
1759
1759
|
LoafLiquidityBadge.displayName = "LoafLiquidityBadge";
|
|
1760
|
+
var toSize = (v, fallback) => v == null ? fallback : typeof v === "number" ? `${v}px` : v;
|
|
1761
|
+
var Skeleton = React9__namespace.forwardRef(
|
|
1762
|
+
({ width, height, radius, className, style, ...props }, ref) => {
|
|
1763
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1764
|
+
"div",
|
|
1765
|
+
{
|
|
1766
|
+
ref,
|
|
1767
|
+
"aria-busy": "true",
|
|
1768
|
+
"aria-live": "polite",
|
|
1769
|
+
className: cn(
|
|
1770
|
+
"inline-block align-middle bg-white/10 animate-pulse",
|
|
1771
|
+
className
|
|
1772
|
+
),
|
|
1773
|
+
style: {
|
|
1774
|
+
width: toSize(width, "100%"),
|
|
1775
|
+
height: toSize(height, "1em"),
|
|
1776
|
+
borderRadius: toSize(radius, "6px"),
|
|
1777
|
+
...style
|
|
1778
|
+
},
|
|
1779
|
+
...props
|
|
1780
|
+
}
|
|
1781
|
+
);
|
|
1782
|
+
}
|
|
1783
|
+
);
|
|
1784
|
+
Skeleton.displayName = "Skeleton";
|
|
1760
1785
|
function useViewportCompact(breakpoint) {
|
|
1761
|
-
const [isCompact, setIsCompact] =
|
|
1762
|
-
|
|
1786
|
+
const [isCompact, setIsCompact] = React9__namespace.useState(false);
|
|
1787
|
+
React9__namespace.useEffect(() => {
|
|
1763
1788
|
if (typeof window === "undefined") return;
|
|
1764
1789
|
const check = () => setIsCompact(window.innerWidth <= breakpoint);
|
|
1765
1790
|
check();
|
|
@@ -1769,16 +1794,119 @@ function useViewportCompact(breakpoint) {
|
|
|
1769
1794
|
return isCompact;
|
|
1770
1795
|
}
|
|
1771
1796
|
var formatNumber = (value, precision) => value.toFixed(precision);
|
|
1797
|
+
var FLASH_DURATION_MS = 450;
|
|
1798
|
+
var FLASH_UP_COLOR = "rgba(14, 203, 129, 0.35)";
|
|
1799
|
+
var FLASH_DOWN_COLOR = "rgba(246, 70, 93, 0.35)";
|
|
1800
|
+
function getTradeKey(trade, fallbackIndex) {
|
|
1801
|
+
if (trade.tradeId != null) return `id-${trade.tradeId}`;
|
|
1802
|
+
if (trade.time != null) return `t-${trade.time}-${trade.type}-${trade.price}-${trade.amount}`;
|
|
1803
|
+
return `idx-${fallbackIndex}-${trade.type}-${trade.price}-${trade.amount}`;
|
|
1804
|
+
}
|
|
1805
|
+
function useAmountChangeFlash(ref, amount) {
|
|
1806
|
+
const prevAmountRef = React9__namespace.useRef(amount);
|
|
1807
|
+
React9__namespace.useEffect(() => {
|
|
1808
|
+
const prev = prevAmountRef.current;
|
|
1809
|
+
const node = ref.current;
|
|
1810
|
+
if (prev !== amount && node && typeof node.animate === "function") {
|
|
1811
|
+
const color = amount > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
|
|
1812
|
+
node.animate(
|
|
1813
|
+
[{ backgroundColor: color }, { backgroundColor: "transparent" }],
|
|
1814
|
+
{ duration: FLASH_DURATION_MS, easing: "ease-out" }
|
|
1815
|
+
);
|
|
1816
|
+
}
|
|
1817
|
+
prevAmountRef.current = amount;
|
|
1818
|
+
}, [amount, ref]);
|
|
1819
|
+
}
|
|
1820
|
+
function useMidPriceFlash(ref, midPrice, restBgColor) {
|
|
1821
|
+
const prevMidRef = React9__namespace.useRef(midPrice);
|
|
1822
|
+
React9__namespace.useEffect(() => {
|
|
1823
|
+
const prev = prevMidRef.current;
|
|
1824
|
+
const node = ref.current;
|
|
1825
|
+
if (prev !== midPrice && prev > 0 && midPrice > 0 && node && typeof node.animate === "function") {
|
|
1826
|
+
const color = midPrice > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
|
|
1827
|
+
node.animate(
|
|
1828
|
+
[{ backgroundColor: color }, { backgroundColor: restBgColor }],
|
|
1829
|
+
{ duration: FLASH_DURATION_MS, easing: "ease-out" }
|
|
1830
|
+
);
|
|
1831
|
+
}
|
|
1832
|
+
prevMidRef.current = midPrice;
|
|
1833
|
+
}, [midPrice, ref, restBgColor]);
|
|
1834
|
+
}
|
|
1835
|
+
function TradeRow({
|
|
1836
|
+
trade,
|
|
1837
|
+
tradeKey,
|
|
1838
|
+
precision,
|
|
1839
|
+
amountPrecision,
|
|
1840
|
+
seenTradeKeysRef,
|
|
1841
|
+
compact
|
|
1842
|
+
}) {
|
|
1843
|
+
const rowRef = React9__namespace.useRef(null);
|
|
1844
|
+
const { type } = trade;
|
|
1845
|
+
React9__namespace.useEffect(() => {
|
|
1846
|
+
if (seenTradeKeysRef.current.has(tradeKey)) return;
|
|
1847
|
+
seenTradeKeysRef.current.add(tradeKey);
|
|
1848
|
+
const node = rowRef.current;
|
|
1849
|
+
if (!node || typeof node.animate !== "function") return;
|
|
1850
|
+
const color = type === "buy" ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
|
|
1851
|
+
node.animate(
|
|
1852
|
+
[{ backgroundColor: color }, { backgroundColor: "transparent" }],
|
|
1853
|
+
{ duration: FLASH_DURATION_MS, easing: "ease-out" }
|
|
1854
|
+
);
|
|
1855
|
+
}, [tradeKey, seenTradeKeysRef, type]);
|
|
1856
|
+
if (compact) {
|
|
1857
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1858
|
+
"div",
|
|
1859
|
+
{
|
|
1860
|
+
ref: rowRef,
|
|
1861
|
+
className: "grid",
|
|
1862
|
+
style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
|
|
1863
|
+
children: [
|
|
1864
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 }, children: [
|
|
1865
|
+
"$",
|
|
1866
|
+
formatNumber(trade.price, precision)
|
|
1867
|
+
] }),
|
|
1868
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
|
|
1869
|
+
]
|
|
1870
|
+
}
|
|
1871
|
+
);
|
|
1872
|
+
}
|
|
1873
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1874
|
+
"div",
|
|
1875
|
+
{
|
|
1876
|
+
ref: rowRef,
|
|
1877
|
+
className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
|
|
1878
|
+
children: [
|
|
1879
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1880
|
+
"div",
|
|
1881
|
+
{
|
|
1882
|
+
className: cn(
|
|
1883
|
+
"tabular-nums",
|
|
1884
|
+
trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
|
|
1885
|
+
),
|
|
1886
|
+
children: [
|
|
1887
|
+
"$",
|
|
1888
|
+
formatNumber(trade.price, precision)
|
|
1889
|
+
]
|
|
1890
|
+
}
|
|
1891
|
+
),
|
|
1892
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
|
|
1893
|
+
]
|
|
1894
|
+
}
|
|
1895
|
+
);
|
|
1896
|
+
}
|
|
1772
1897
|
function DepthRow({
|
|
1773
1898
|
side,
|
|
1774
1899
|
price,
|
|
1775
1900
|
amount,
|
|
1776
1901
|
depthPct,
|
|
1777
1902
|
precision,
|
|
1778
|
-
amountPrecision
|
|
1903
|
+
amountPrecision,
|
|
1904
|
+
hasUserOrder
|
|
1779
1905
|
}) {
|
|
1780
1906
|
const isAsk = side === "ask";
|
|
1781
|
-
|
|
1907
|
+
const rowRef = React9__namespace.useRef(null);
|
|
1908
|
+
useAmountChangeFlash(rowRef, amount);
|
|
1909
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rowRef, className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
|
|
1782
1910
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1783
1911
|
"div",
|
|
1784
1912
|
{
|
|
@@ -1786,9 +1914,16 @@ function DepthRow({
|
|
|
1786
1914
|
"absolute inset-y-0 right-0",
|
|
1787
1915
|
isAsk ? "bg-rose-900/30" : "bg-emerald-900/30"
|
|
1788
1916
|
),
|
|
1789
|
-
style: { width: `${clamp3(depthPct, 0, 100)}
|
|
1917
|
+
style: { width: `${clamp3(depthPct, 0, 100)}%`, transition: "width 300ms ease-out" }
|
|
1790
1918
|
}
|
|
1791
1919
|
),
|
|
1920
|
+
hasUserOrder ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1921
|
+
"span",
|
|
1922
|
+
{
|
|
1923
|
+
"aria-label": "Your order at this price",
|
|
1924
|
+
className: "absolute left-0 top-0 bottom-0 z-[2] w-[3px] rounded-r-sm bg-[#C9A227] shadow-[0_0_6px_rgba(201,162,39,0.6)]"
|
|
1925
|
+
}
|
|
1926
|
+
) : null,
|
|
1792
1927
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1793
1928
|
"div",
|
|
1794
1929
|
{
|
|
@@ -1808,7 +1943,7 @@ var DEPTH_ROW_HEIGHT_PX = 34;
|
|
|
1808
1943
|
var COMPACT_ROWS_VISIBLE = 5;
|
|
1809
1944
|
var COMPACT_ROW_HEIGHT_PX = 30;
|
|
1810
1945
|
var COMPACT_BREAKPOINT_PX = 1024;
|
|
1811
|
-
var Orderbook =
|
|
1946
|
+
var Orderbook = React9__namespace.forwardRef(
|
|
1812
1947
|
({
|
|
1813
1948
|
asks,
|
|
1814
1949
|
bids,
|
|
@@ -1823,13 +1958,44 @@ var Orderbook = React5__namespace.forwardRef(
|
|
|
1823
1958
|
onTabChange,
|
|
1824
1959
|
rightHeader = /* @__PURE__ */ jsxRuntime.jsx(LoafLiquidityBadge, { className: "text-[0.6rem]" }),
|
|
1825
1960
|
variant = "auto",
|
|
1961
|
+
userOrderPrices,
|
|
1962
|
+
isLoading = false,
|
|
1826
1963
|
className,
|
|
1827
1964
|
...props
|
|
1828
1965
|
}, ref) => {
|
|
1829
|
-
const [tab, setTab] =
|
|
1830
|
-
const [tradeFilter, setTradeFilter] =
|
|
1966
|
+
const [tab, setTab] = React9__namespace.useState(defaultTab);
|
|
1967
|
+
const [tradeFilter, setTradeFilter] = React9__namespace.useState("all");
|
|
1831
1968
|
const viewportCompact = useViewportCompact(COMPACT_BREAKPOINT_PX);
|
|
1832
|
-
|
|
1969
|
+
const { userAskPrices, userBidPrices } = React9__namespace.useMemo(() => {
|
|
1970
|
+
const ask = /* @__PURE__ */ new Set();
|
|
1971
|
+
const bid = /* @__PURE__ */ new Set();
|
|
1972
|
+
if (!userOrderPrices) return { userAskPrices: ask, userBidPrices: bid };
|
|
1973
|
+
for (const entry of userOrderPrices) {
|
|
1974
|
+
if (entry.side === "SELL") ask.add(entry.price);
|
|
1975
|
+
else bid.add(entry.price);
|
|
1976
|
+
}
|
|
1977
|
+
return { userAskPrices: ask, userBidPrices: bid };
|
|
1978
|
+
}, [userOrderPrices]);
|
|
1979
|
+
const seenTradeKeysRef = React9__namespace.useRef(/* @__PURE__ */ new Set());
|
|
1980
|
+
const initializedRef = React9__namespace.useRef(false);
|
|
1981
|
+
if (!initializedRef.current && trades.length > 0) {
|
|
1982
|
+
for (let i = 0; i < trades.length; i++) {
|
|
1983
|
+
seenTradeKeysRef.current.add(getTradeKey(trades[i], i));
|
|
1984
|
+
}
|
|
1985
|
+
initializedRef.current = true;
|
|
1986
|
+
}
|
|
1987
|
+
React9__namespace.useEffect(() => {
|
|
1988
|
+
if (!initializedRef.current) return;
|
|
1989
|
+
const live = /* @__PURE__ */ new Set();
|
|
1990
|
+
for (let i = 0; i < trades.length; i++) {
|
|
1991
|
+
live.add(getTradeKey(trades[i], i));
|
|
1992
|
+
}
|
|
1993
|
+
const seen = seenTradeKeysRef.current;
|
|
1994
|
+
for (const key of seen) {
|
|
1995
|
+
if (!live.has(key)) seen.delete(key);
|
|
1996
|
+
}
|
|
1997
|
+
}, [trades]);
|
|
1998
|
+
React9__namespace.useEffect(() => {
|
|
1833
1999
|
setTab(defaultTab);
|
|
1834
2000
|
}, [defaultTab]);
|
|
1835
2001
|
const handleTab = (next) => {
|
|
@@ -1860,7 +2026,11 @@ var Orderbook = React5__namespace.forwardRef(
|
|
|
1860
2026
|
midPrice,
|
|
1861
2027
|
midChangePercent,
|
|
1862
2028
|
midClass,
|
|
1863
|
-
sectionHeight
|
|
2029
|
+
sectionHeight,
|
|
2030
|
+
userAskPrices,
|
|
2031
|
+
userBidPrices,
|
|
2032
|
+
isLoading,
|
|
2033
|
+
seenTradeKeysRef
|
|
1864
2034
|
};
|
|
1865
2035
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1866
2036
|
Card,
|
|
@@ -1878,6 +2048,29 @@ var Orderbook = React5__namespace.forwardRef(
|
|
|
1878
2048
|
}
|
|
1879
2049
|
);
|
|
1880
2050
|
Orderbook.displayName = "Orderbook";
|
|
2051
|
+
function SkeletonRow({ compact }) {
|
|
2052
|
+
if (compact) {
|
|
2053
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2054
|
+
"div",
|
|
2055
|
+
{
|
|
2056
|
+
style: {
|
|
2057
|
+
display: "grid",
|
|
2058
|
+
gridTemplateColumns: "1.2fr 0.8fr",
|
|
2059
|
+
padding: "0.2rem 0",
|
|
2060
|
+
alignItems: "center"
|
|
2061
|
+
},
|
|
2062
|
+
children: [
|
|
2063
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "60%", height: 10 }) }),
|
|
2064
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "50%", height: 10 }) })
|
|
2065
|
+
]
|
|
2066
|
+
}
|
|
2067
|
+
);
|
|
2068
|
+
}
|
|
2069
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
|
|
2070
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "60%", height: 12 }),
|
|
2071
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "50%", height: 12 }) })
|
|
2072
|
+
] });
|
|
2073
|
+
}
|
|
1881
2074
|
function DesktopOrderbookLayout({
|
|
1882
2075
|
tab,
|
|
1883
2076
|
handleTab,
|
|
@@ -1896,8 +2089,14 @@ function DesktopOrderbookLayout({
|
|
|
1896
2089
|
midPrice,
|
|
1897
2090
|
midChangePercent,
|
|
1898
2091
|
midClass,
|
|
1899
|
-
sectionHeight
|
|
2092
|
+
sectionHeight,
|
|
2093
|
+
userAskPrices,
|
|
2094
|
+
userBidPrices,
|
|
2095
|
+
isLoading,
|
|
2096
|
+
seenTradeKeysRef
|
|
1900
2097
|
}) {
|
|
2098
|
+
const midRef = React9__namespace.useRef(null);
|
|
2099
|
+
useMidPriceFlash(midRef, midPrice, "#0b1a24");
|
|
1901
2100
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1902
2101
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 pt-4", children: [
|
|
1903
2102
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
|
|
@@ -1981,29 +2180,20 @@ function DesktopOrderbookLayout({
|
|
|
1981
2180
|
{
|
|
1982
2181
|
className: "max-h-[380px] overflow-y-auto overflow-x-hidden",
|
|
1983
2182
|
style: { scrollbarGutter: "stable" },
|
|
1984
|
-
children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) =>
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
formatNumber(trade.price, precision)
|
|
1999
|
-
]
|
|
2000
|
-
}
|
|
2001
|
-
),
|
|
2002
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
|
|
2003
|
-
]
|
|
2004
|
-
},
|
|
2005
|
-
`${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
|
|
2006
|
-
)) })
|
|
2183
|
+
children: isLoading && tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `trade-skel-${i}`)) }) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) => {
|
|
2184
|
+
const tradeKey = getTradeKey(trade, i);
|
|
2185
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2186
|
+
TradeRow,
|
|
2187
|
+
{
|
|
2188
|
+
trade,
|
|
2189
|
+
tradeKey,
|
|
2190
|
+
precision,
|
|
2191
|
+
amountPrecision,
|
|
2192
|
+
seenTradeKeysRef
|
|
2193
|
+
},
|
|
2194
|
+
tradeKey
|
|
2195
|
+
);
|
|
2196
|
+
}) })
|
|
2007
2197
|
}
|
|
2008
2198
|
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col min-h-0", children: [
|
|
2009
2199
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2011,7 +2201,7 @@ function DesktopOrderbookLayout({
|
|
|
2011
2201
|
{
|
|
2012
2202
|
className: "flex flex-col justify-end divide-y divide-white/5 overflow-y-auto",
|
|
2013
2203
|
style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
|
|
2014
|
-
children:
|
|
2204
|
+
children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `ask-skel-${i}`)) : asks.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2015
2205
|
DepthRow,
|
|
2016
2206
|
{
|
|
2017
2207
|
side: "ask",
|
|
@@ -2019,30 +2209,38 @@ function DesktopOrderbookLayout({
|
|
|
2019
2209
|
amount: l.amount,
|
|
2020
2210
|
depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
|
|
2021
2211
|
precision,
|
|
2022
|
-
amountPrecision
|
|
2212
|
+
amountPrecision,
|
|
2213
|
+
hasUserOrder: userAskPrices.has(l.price)
|
|
2023
2214
|
},
|
|
2024
|
-
`ask-${
|
|
2215
|
+
`ask-${l.price}`
|
|
2025
2216
|
))
|
|
2026
2217
|
}
|
|
2027
2218
|
),
|
|
2028
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2219
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2220
|
+
"div",
|
|
2221
|
+
{
|
|
2222
|
+
ref: midRef,
|
|
2223
|
+
className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2",
|
|
2224
|
+
children: [
|
|
2225
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 20 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2226
|
+
"$",
|
|
2227
|
+
formatNumber(midPrice, precision),
|
|
2228
|
+
midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
|
|
2229
|
+
midChangePercent >= 0 ? "+" : "",
|
|
2230
|
+
midChangePercent.toFixed(2),
|
|
2231
|
+
"%"
|
|
2232
|
+
] })
|
|
2233
|
+
] }) }),
|
|
2234
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", {})
|
|
2235
|
+
]
|
|
2236
|
+
}
|
|
2237
|
+
),
|
|
2040
2238
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2041
2239
|
"div",
|
|
2042
2240
|
{
|
|
2043
2241
|
className: "divide-y divide-white/5 overflow-y-auto",
|
|
2044
2242
|
style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
|
|
2045
|
-
children:
|
|
2243
|
+
children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `bid-skel-${i}`)) : bids.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2046
2244
|
DepthRow,
|
|
2047
2245
|
{
|
|
2048
2246
|
side: "bid",
|
|
@@ -2050,9 +2248,10 @@ function DesktopOrderbookLayout({
|
|
|
2050
2248
|
amount: l.amount,
|
|
2051
2249
|
depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
|
|
2052
2250
|
precision,
|
|
2053
|
-
amountPrecision
|
|
2251
|
+
amountPrecision,
|
|
2252
|
+
hasUserOrder: userBidPrices.has(l.price)
|
|
2054
2253
|
},
|
|
2055
|
-
`bid-${
|
|
2254
|
+
`bid-${l.price}`
|
|
2056
2255
|
))
|
|
2057
2256
|
}
|
|
2058
2257
|
)
|
|
@@ -2078,10 +2277,16 @@ function MobileOrderbookLayout({
|
|
|
2078
2277
|
midPrice,
|
|
2079
2278
|
midChangePercent,
|
|
2080
2279
|
midClass,
|
|
2081
|
-
sectionHeight: _sectionHeight
|
|
2280
|
+
sectionHeight: _sectionHeight,
|
|
2281
|
+
userAskPrices,
|
|
2282
|
+
userBidPrices,
|
|
2283
|
+
isLoading,
|
|
2284
|
+
seenTradeKeysRef
|
|
2082
2285
|
}) {
|
|
2083
|
-
const
|
|
2084
|
-
|
|
2286
|
+
const midRef = React9__namespace.useRef(null);
|
|
2287
|
+
useMidPriceFlash(midRef, midPrice, "transparent");
|
|
2288
|
+
const visibleAsks = React9__namespace.useMemo(() => asks.slice(0, COMPACT_ROWS_VISIBLE), [asks]);
|
|
2289
|
+
const visibleBids = React9__namespace.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
|
|
2085
2290
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2086
2291
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2087
2292
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -2150,7 +2355,7 @@ function MobileOrderbookLayout({
|
|
|
2150
2355
|
]
|
|
2151
2356
|
}
|
|
2152
2357
|
),
|
|
2153
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children:
|
|
2358
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-ask-skel-${i}`)) : visibleAsks.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2154
2359
|
MobileDepthRow,
|
|
2155
2360
|
{
|
|
2156
2361
|
side: "ask",
|
|
@@ -2158,13 +2363,15 @@ function MobileOrderbookLayout({
|
|
|
2158
2363
|
amount: l.amount,
|
|
2159
2364
|
depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
|
|
2160
2365
|
precision,
|
|
2161
|
-
amountPrecision
|
|
2366
|
+
amountPrecision,
|
|
2367
|
+
hasUserOrder: userAskPrices.has(l.price)
|
|
2162
2368
|
},
|
|
2163
|
-
`mobile-ask-${
|
|
2369
|
+
`mobile-ask-${l.price}`
|
|
2164
2370
|
)) }),
|
|
2165
2371
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2166
2372
|
"div",
|
|
2167
2373
|
{
|
|
2374
|
+
ref: midRef,
|
|
2168
2375
|
className: "grid",
|
|
2169
2376
|
style: {
|
|
2170
2377
|
gridTemplateColumns: "1.2fr 0.8fr",
|
|
@@ -2174,12 +2381,12 @@ function MobileOrderbookLayout({
|
|
|
2174
2381
|
borderBottom: "1px solid rgba(255,255,255,0.1)"
|
|
2175
2382
|
},
|
|
2176
2383
|
children: [
|
|
2177
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2384
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2178
2385
|
"div",
|
|
2179
2386
|
{
|
|
2180
2387
|
style: { fontWeight: "bold", display: "flex", alignItems: "center", gap: "8px" },
|
|
2181
2388
|
className: midClass,
|
|
2182
|
-
children: [
|
|
2389
|
+
children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 90, height: 16 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2183
2390
|
"$",
|
|
2184
2391
|
formatNumber(midPrice, precision),
|
|
2185
2392
|
midChangePercent != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-[0.75rem] font-semibold tabular-nums", midClass), children: [
|
|
@@ -2187,14 +2394,14 @@ function MobileOrderbookLayout({
|
|
|
2187
2394
|
midChangePercent.toFixed(2),
|
|
2188
2395
|
"%"
|
|
2189
2396
|
] })
|
|
2190
|
-
]
|
|
2397
|
+
] })
|
|
2191
2398
|
}
|
|
2192
2399
|
),
|
|
2193
2400
|
/* @__PURE__ */ jsxRuntime.jsx("div", {})
|
|
2194
2401
|
]
|
|
2195
2402
|
}
|
|
2196
2403
|
),
|
|
2197
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children:
|
|
2404
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-bid-skel-${i}`)) : visibleBids.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2198
2405
|
MobileDepthRow,
|
|
2199
2406
|
{
|
|
2200
2407
|
side: "bid",
|
|
@@ -2202,9 +2409,10 @@ function MobileOrderbookLayout({
|
|
|
2202
2409
|
amount: l.amount,
|
|
2203
2410
|
depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
|
|
2204
2411
|
precision,
|
|
2205
|
-
amountPrecision
|
|
2412
|
+
amountPrecision,
|
|
2413
|
+
hasUserOrder: userBidPrices.has(l.price)
|
|
2206
2414
|
},
|
|
2207
|
-
`mobile-bid-${
|
|
2415
|
+
`mobile-bid-${l.price}`
|
|
2208
2416
|
)) })
|
|
2209
2417
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden px-3 pb-2", children: [
|
|
2210
2418
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -2218,27 +2426,21 @@ function MobileOrderbookLayout({
|
|
|
2218
2426
|
]
|
|
2219
2427
|
}
|
|
2220
2428
|
),
|
|
2221
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) =>
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
),
|
|
2237
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
|
|
2238
|
-
]
|
|
2239
|
-
},
|
|
2240
|
-
`${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
|
|
2241
|
-
)) })
|
|
2429
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: isLoading && tradeFiltered.length === 0 ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-trade-skel-${i}`)) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) => {
|
|
2430
|
+
const tradeKey = getTradeKey(trade, i);
|
|
2431
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2432
|
+
TradeRow,
|
|
2433
|
+
{
|
|
2434
|
+
trade,
|
|
2435
|
+
tradeKey,
|
|
2436
|
+
precision,
|
|
2437
|
+
amountPrecision,
|
|
2438
|
+
seenTradeKeysRef,
|
|
2439
|
+
compact: true
|
|
2440
|
+
},
|
|
2441
|
+
tradeKey
|
|
2442
|
+
);
|
|
2443
|
+
}) })
|
|
2242
2444
|
] })
|
|
2243
2445
|
] });
|
|
2244
2446
|
}
|
|
@@ -2248,12 +2450,16 @@ function MobileDepthRow({
|
|
|
2248
2450
|
amount,
|
|
2249
2451
|
depthPct,
|
|
2250
2452
|
precision,
|
|
2251
|
-
amountPrecision
|
|
2453
|
+
amountPrecision,
|
|
2454
|
+
hasUserOrder
|
|
2252
2455
|
}) {
|
|
2253
2456
|
const isAsk = side === "ask";
|
|
2457
|
+
const rowRef = React9__namespace.useRef(null);
|
|
2458
|
+
useAmountChangeFlash(rowRef, amount);
|
|
2254
2459
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2255
2460
|
"div",
|
|
2256
2461
|
{
|
|
2462
|
+
ref: rowRef,
|
|
2257
2463
|
style: {
|
|
2258
2464
|
display: "grid",
|
|
2259
2465
|
gridTemplateColumns: "1.2fr 0.8fr",
|
|
@@ -2262,6 +2468,24 @@ function MobileDepthRow({
|
|
|
2262
2468
|
position: "relative"
|
|
2263
2469
|
},
|
|
2264
2470
|
children: [
|
|
2471
|
+
hasUserOrder ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2472
|
+
"span",
|
|
2473
|
+
{
|
|
2474
|
+
"aria-label": "Your order at this price",
|
|
2475
|
+
style: {
|
|
2476
|
+
position: "absolute",
|
|
2477
|
+
left: 0,
|
|
2478
|
+
top: 0,
|
|
2479
|
+
bottom: 0,
|
|
2480
|
+
width: "3px",
|
|
2481
|
+
backgroundColor: "#C9A227",
|
|
2482
|
+
boxShadow: "0 0 6px rgba(201,162,39,0.6)",
|
|
2483
|
+
borderTopRightRadius: "2px",
|
|
2484
|
+
borderBottomRightRadius: "2px",
|
|
2485
|
+
zIndex: 2
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
) : null,
|
|
2265
2489
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 1, color: isAsk ? "#f6465d" : "#0ecb81" }, children: [
|
|
2266
2490
|
"$",
|
|
2267
2491
|
formatNumber(price, precision)
|
|
@@ -2278,7 +2502,8 @@ function MobileDepthRow({
|
|
|
2278
2502
|
width: `${clamp3(depthPct, 0, 100)}%`,
|
|
2279
2503
|
backgroundColor: isAsk ? "#f6465d" : "#0ecb81",
|
|
2280
2504
|
opacity: 0.1,
|
|
2281
|
-
zIndex: 0
|
|
2505
|
+
zIndex: 0,
|
|
2506
|
+
transition: "width 300ms ease-out"
|
|
2282
2507
|
}
|
|
2283
2508
|
}
|
|
2284
2509
|
)
|
|
@@ -2286,7 +2511,7 @@ function MobileDepthRow({
|
|
|
2286
2511
|
}
|
|
2287
2512
|
);
|
|
2288
2513
|
}
|
|
2289
|
-
var PropertyTour =
|
|
2514
|
+
var PropertyTour = React9__namespace.forwardRef(
|
|
2290
2515
|
({
|
|
2291
2516
|
className,
|
|
2292
2517
|
title,
|
|
@@ -2299,8 +2524,8 @@ var PropertyTour = React5__namespace.forwardRef(
|
|
|
2299
2524
|
playsInline = true,
|
|
2300
2525
|
...props
|
|
2301
2526
|
}, ref) => {
|
|
2302
|
-
const videoRef =
|
|
2303
|
-
|
|
2527
|
+
const videoRef = React9__namespace.useRef(null);
|
|
2528
|
+
React9__namespace.useEffect(() => {
|
|
2304
2529
|
const video = videoRef.current;
|
|
2305
2530
|
if (!video) return;
|
|
2306
2531
|
const handleFullscreenChange = () => {
|
|
@@ -2432,7 +2657,7 @@ var formatTimeAgo = (timestamp) => {
|
|
|
2432
2657
|
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
|
|
2433
2658
|
return `${Math.floor(diff / 3600)}h ago`;
|
|
2434
2659
|
};
|
|
2435
|
-
var PropertyNewsUpdates =
|
|
2660
|
+
var PropertyNewsUpdates = React9__namespace.forwardRef(
|
|
2436
2661
|
({
|
|
2437
2662
|
className,
|
|
2438
2663
|
heading,
|
|
@@ -2449,15 +2674,15 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
|
|
|
2449
2674
|
const isPurchaseVariant = variant === "purchases";
|
|
2450
2675
|
const isHomeVariant = variant === "home";
|
|
2451
2676
|
const resolvedHeading = heading ?? (isPurchaseVariant ? "Live Purchases" : "Property News & Headlines");
|
|
2452
|
-
const [homeTab, setHomeTab] =
|
|
2677
|
+
const [homeTab, setHomeTab] = React9__namespace.useState("all");
|
|
2453
2678
|
const purchaseItems = purchasesProp ?? [];
|
|
2454
|
-
const [page, setPage] =
|
|
2455
|
-
|
|
2679
|
+
const [page, setPage] = React9__namespace.useState(0);
|
|
2680
|
+
React9__namespace.useEffect(() => {
|
|
2456
2681
|
ensureAnimationsInjected();
|
|
2457
2682
|
}, []);
|
|
2458
2683
|
const hasItems = Array.isArray(items) && items.length > 0;
|
|
2459
|
-
const totalPages =
|
|
2460
|
-
|
|
2684
|
+
const totalPages = React9__namespace.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
|
|
2685
|
+
React9__namespace.useEffect(() => {
|
|
2461
2686
|
setPage((prev) => Math.min(prev, totalPages - 1));
|
|
2462
2687
|
}, [totalPages]);
|
|
2463
2688
|
const paginatedItems = hasItems ? items.slice(page * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE + ITEMS_PER_PAGE) : [];
|
|
@@ -2765,7 +2990,7 @@ var defaultFormat = (value) => new Intl.NumberFormat("en-US", {
|
|
|
2765
2990
|
notation: value >= 1e5 ? "compact" : "standard",
|
|
2766
2991
|
maximumFractionDigits: value >= 1e3 ? 0 : 2
|
|
2767
2992
|
}).format(value);
|
|
2768
|
-
var TradingSlider =
|
|
2993
|
+
var TradingSlider = React9__namespace.forwardRef(
|
|
2769
2994
|
({
|
|
2770
2995
|
label = "Trade size",
|
|
2771
2996
|
helperText = "Drag to pick the desired notional.",
|
|
@@ -2783,7 +3008,7 @@ var TradingSlider = React5__namespace.forwardRef(
|
|
|
2783
3008
|
...rest
|
|
2784
3009
|
}, ref) => {
|
|
2785
3010
|
const isControlled = value !== void 0;
|
|
2786
|
-
const [internalValue, setInternalValue] =
|
|
3011
|
+
const [internalValue, setInternalValue] = React9__namespace.useState(
|
|
2787
3012
|
defaultValue ?? (typeof min === "number" ? min : 0)
|
|
2788
3013
|
);
|
|
2789
3014
|
const currentValue = isControlled ? Number(value) : internalValue;
|
|
@@ -2886,7 +3111,7 @@ var MobileToggleButton = styled24__default.default.button`
|
|
|
2886
3111
|
padding: 0.6rem 0.5rem;
|
|
2887
3112
|
}
|
|
2888
3113
|
`;
|
|
2889
|
-
var MobileTradeNav =
|
|
3114
|
+
var MobileTradeNav = React9__namespace.forwardRef(
|
|
2890
3115
|
({ className, items, activeId, onChange, ...props }, ref) => {
|
|
2891
3116
|
return /* @__PURE__ */ jsxRuntime.jsx(MobileToggleContainer, { ref, className: cn(className), ...props, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2892
3117
|
MobileToggleButton,
|
|
@@ -3537,7 +3762,7 @@ var formatPercent = (value, fractionDigits = 2) => {
|
|
|
3537
3762
|
if (value == null || Number.isNaN(value)) return "\u2014";
|
|
3538
3763
|
return `${value.toFixed(fractionDigits)}%`;
|
|
3539
3764
|
};
|
|
3540
|
-
var YourOrders =
|
|
3765
|
+
var YourOrders = React9__namespace.forwardRef(
|
|
3541
3766
|
({
|
|
3542
3767
|
className,
|
|
3543
3768
|
title,
|
|
@@ -3550,10 +3775,10 @@ var YourOrders = React5__namespace.forwardRef(
|
|
|
3550
3775
|
pageSize: pageSizeOverride,
|
|
3551
3776
|
...props
|
|
3552
3777
|
}, ref) => {
|
|
3553
|
-
const [internalActiveTab, setInternalActiveTab] =
|
|
3554
|
-
const [page, setPage] =
|
|
3778
|
+
const [internalActiveTab, setInternalActiveTab] = React9__namespace.useState(tabs?.[0]?.id ?? "portfolio");
|
|
3779
|
+
const [page, setPage] = React9__namespace.useState(0);
|
|
3555
3780
|
const effectiveActiveTabId = activeTabId ?? internalActiveTab;
|
|
3556
|
-
|
|
3781
|
+
React9__namespace.useEffect(() => {
|
|
3557
3782
|
setPage(0);
|
|
3558
3783
|
}, [effectiveActiveTabId]);
|
|
3559
3784
|
const handleTabChange = (tabId) => {
|
|
@@ -3935,7 +4160,7 @@ function createCandlestickSeries(chart, options) {
|
|
|
3935
4160
|
}
|
|
3936
4161
|
throw new Error("Candlestick series API is not available in the current lightweight-charts version.");
|
|
3937
4162
|
}
|
|
3938
|
-
var PriceChart =
|
|
4163
|
+
var PriceChart = React9__namespace.forwardRef(
|
|
3939
4164
|
({
|
|
3940
4165
|
className,
|
|
3941
4166
|
title = "Price Chart",
|
|
@@ -3949,18 +4174,18 @@ var PriceChart = React5__namespace.forwardRef(
|
|
|
3949
4174
|
height = 301.52,
|
|
3950
4175
|
...props
|
|
3951
4176
|
}, ref) => {
|
|
3952
|
-
const containerRef =
|
|
3953
|
-
const chartRef =
|
|
3954
|
-
const seriesRef =
|
|
3955
|
-
const priceLineRef =
|
|
3956
|
-
const [hoveredRange, setHoveredRange] =
|
|
3957
|
-
const [dropdownOpen, setDropdownOpen] =
|
|
3958
|
-
const dropdownRef =
|
|
3959
|
-
const isAutoScrollRef =
|
|
4177
|
+
const containerRef = React9__namespace.useRef(null);
|
|
4178
|
+
const chartRef = React9__namespace.useRef(null);
|
|
4179
|
+
const seriesRef = React9__namespace.useRef(null);
|
|
4180
|
+
const priceLineRef = React9__namespace.useRef(null);
|
|
4181
|
+
const [hoveredRange, setHoveredRange] = React9__namespace.useState(null);
|
|
4182
|
+
const [dropdownOpen, setDropdownOpen] = React9__namespace.useState(false);
|
|
4183
|
+
const dropdownRef = React9__namespace.useRef(null);
|
|
4184
|
+
const isAutoScrollRef = React9__namespace.useRef(true);
|
|
3960
4185
|
const visibleRanges = ranges.slice(0, VISIBLE_RANGE_COUNT);
|
|
3961
4186
|
const dropdownRanges = ranges.slice(VISIBLE_RANGE_COUNT);
|
|
3962
4187
|
const selectedInDropdown = dropdownRanges.includes(selectedRange);
|
|
3963
|
-
|
|
4188
|
+
React9__namespace.useEffect(() => {
|
|
3964
4189
|
const handleClickOutside = (e) => {
|
|
3965
4190
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
3966
4191
|
setDropdownOpen(false);
|
|
@@ -3969,25 +4194,25 @@ var PriceChart = React5__namespace.forwardRef(
|
|
|
3969
4194
|
document.addEventListener("mousedown", handleClickOutside);
|
|
3970
4195
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
3971
4196
|
}, []);
|
|
3972
|
-
const resolvedPrice =
|
|
4197
|
+
const resolvedPrice = React9__namespace.useMemo(() => {
|
|
3973
4198
|
if (price != null) return price;
|
|
3974
4199
|
const last = data.at(-1);
|
|
3975
4200
|
return last?.close;
|
|
3976
4201
|
}, [data, price]);
|
|
3977
|
-
const inferredChangePercent =
|
|
4202
|
+
const inferredChangePercent = React9__namespace.useMemo(() => {
|
|
3978
4203
|
if (changePercent != null) return changePercent;
|
|
3979
4204
|
const first = data[0]?.open;
|
|
3980
4205
|
const last = data.at(-1)?.close;
|
|
3981
4206
|
if (first == null || last == null || first === 0) return void 0;
|
|
3982
4207
|
return (last - first) / first * 100;
|
|
3983
4208
|
}, [changePercent, data]);
|
|
3984
|
-
const dollarChange =
|
|
4209
|
+
const dollarChange = React9__namespace.useMemo(() => {
|
|
3985
4210
|
const first = data[0]?.open;
|
|
3986
4211
|
const last = data.at(-1)?.close;
|
|
3987
4212
|
if (first == null || last == null) return void 0;
|
|
3988
4213
|
return last - first;
|
|
3989
4214
|
}, [data]);
|
|
3990
|
-
|
|
4215
|
+
React9__namespace.useEffect(() => {
|
|
3991
4216
|
const el = containerRef.current;
|
|
3992
4217
|
if (!el) return;
|
|
3993
4218
|
const chart = LightweightCharts__namespace.createChart(el, {
|
|
@@ -4032,7 +4257,7 @@ var PriceChart = React5__namespace.forwardRef(
|
|
|
4032
4257
|
chart.remove();
|
|
4033
4258
|
};
|
|
4034
4259
|
}, []);
|
|
4035
|
-
|
|
4260
|
+
React9__namespace.useEffect(() => {
|
|
4036
4261
|
const chart = chartRef.current;
|
|
4037
4262
|
if (!chart) return;
|
|
4038
4263
|
const effectiveRange = selectedRange ?? ranges?.[0] ?? "1D";
|
|
@@ -4040,7 +4265,7 @@ var PriceChart = React5__namespace.forwardRef(
|
|
|
4040
4265
|
timeScale: getTimeScaleOptions(effectiveRange)
|
|
4041
4266
|
});
|
|
4042
4267
|
}, [selectedRange, ranges]);
|
|
4043
|
-
|
|
4268
|
+
React9__namespace.useEffect(() => {
|
|
4044
4269
|
const chart = chartRef.current;
|
|
4045
4270
|
const series = seriesRef.current;
|
|
4046
4271
|
if (!chart || !series) return;
|
|
@@ -4245,7 +4470,7 @@ var formatPrice3 = (value, currencySymbol) => {
|
|
|
4245
4470
|
maximumFractionDigits: 3
|
|
4246
4471
|
})}`;
|
|
4247
4472
|
};
|
|
4248
|
-
var PropertyHeroHeader =
|
|
4473
|
+
var PropertyHeroHeader = React9__namespace.forwardRef(
|
|
4249
4474
|
({
|
|
4250
4475
|
className,
|
|
4251
4476
|
imageUrl,
|
|
@@ -4266,14 +4491,15 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
4266
4491
|
makeOfferDisabled = false,
|
|
4267
4492
|
hideMakeOfferButton = false,
|
|
4268
4493
|
statusBadge,
|
|
4494
|
+
isLoading = false,
|
|
4269
4495
|
...props
|
|
4270
4496
|
}, ref) => {
|
|
4271
4497
|
const isPositive = changePercent == null ? void 0 : changePercent >= 0;
|
|
4272
4498
|
const accentColor = "#e6c87e";
|
|
4273
4499
|
const tradeHoverColor = "#f5dd9a";
|
|
4274
|
-
const [isTradeInteracting, setIsTradeInteracting] =
|
|
4275
|
-
const [isOfferInteracting, setIsOfferInteracting] =
|
|
4276
|
-
const hasAmenities = beds != null || baths != null || cars != null || propertyTypeLabel != null;
|
|
4500
|
+
const [isTradeInteracting, setIsTradeInteracting] = React9__namespace.useState(false);
|
|
4501
|
+
const [isOfferInteracting, setIsOfferInteracting] = React9__namespace.useState(false);
|
|
4502
|
+
const hasAmenities = isLoading || beds != null || baths != null || cars != null || propertyTypeLabel != null;
|
|
4277
4503
|
const isTradeDisabled = !onTrade;
|
|
4278
4504
|
const isMakeOfferButtonDisabled = makeOfferDisabled || !onMakeOffer;
|
|
4279
4505
|
const showMakeOfferButton = !hideMakeOfferButton;
|
|
@@ -4313,7 +4539,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
4313
4539
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { style: headingStyle, className: "break-words", children: name }),
|
|
4314
4540
|
/* @__PURE__ */ jsxRuntime.jsxs(InfoRow, { className: "mb-3 max-[768px]:mb-[0.6rem] max-[480px]:mb-[0.5rem]", children: [
|
|
4315
4541
|
/* @__PURE__ */ jsxRuntime.jsx(LocationText, { children: location }),
|
|
4316
|
-
price == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(PriceBlock, { children: [
|
|
4542
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx(PriceBlock, { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 18 }) }) : price == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(PriceBlock, { children: [
|
|
4317
4543
|
formatPrice3(price, currencySymbol),
|
|
4318
4544
|
changePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4319
4545
|
"span",
|
|
@@ -4343,7 +4569,21 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
4343
4569
|
] })
|
|
4344
4570
|
] })
|
|
4345
4571
|
] }),
|
|
4346
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4572
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4573
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
4574
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
|
|
4575
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 52, height: 14 })
|
|
4576
|
+
] }),
|
|
4577
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
4578
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bath, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
|
|
4579
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 56, height: 14 })
|
|
4580
|
+
] }),
|
|
4581
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
4582
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CarFront, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
|
|
4583
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 50, height: 14 })
|
|
4584
|
+
] }),
|
|
4585
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 60, height: 14 })
|
|
4586
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4347
4587
|
beds == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
4348
4588
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "mr-2 h-[18px] w-[18px]" }),
|
|
4349
4589
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
@@ -4366,7 +4606,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
4366
4606
|
] })
|
|
4367
4607
|
] }),
|
|
4368
4608
|
propertyTypeLabel == null ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { children: propertyTypeLabel })
|
|
4369
|
-
] })
|
|
4609
|
+
] }) })
|
|
4370
4610
|
] }),
|
|
4371
4611
|
/* @__PURE__ */ jsxRuntime.jsxs(ActionButtons, { children: [
|
|
4372
4612
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4428,7 +4668,21 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
4428
4668
|
] })
|
|
4429
4669
|
] }) })
|
|
4430
4670
|
] }),
|
|
4431
|
-
hasAmenities ? /* @__PURE__ */ jsxRuntime.
|
|
4671
|
+
hasAmenities ? /* @__PURE__ */ jsxRuntime.jsx(MobileAmenities, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4672
|
+
/* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
|
|
4673
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "h-4 w-4 opacity-60" }),
|
|
4674
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 40, height: 12 })
|
|
4675
|
+
] }),
|
|
4676
|
+
/* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
|
|
4677
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bath, { className: "h-4 w-4 opacity-60" }),
|
|
4678
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 44, height: 12 })
|
|
4679
|
+
] }),
|
|
4680
|
+
/* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
|
|
4681
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CarFront, { className: "h-4 w-4 opacity-60" }),
|
|
4682
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 42, height: 12 })
|
|
4683
|
+
] }),
|
|
4684
|
+
/* @__PURE__ */ jsxRuntime.jsx(MobileAmenity, { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 52, height: 12 }) })
|
|
4685
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4432
4686
|
beds == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
|
|
4433
4687
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "h-4 w-4" }),
|
|
4434
4688
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
@@ -4451,7 +4705,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
4451
4705
|
] })
|
|
4452
4706
|
] }),
|
|
4453
4707
|
propertyTypeLabel == null ? null : /* @__PURE__ */ jsxRuntime.jsx(MobileAmenity, { children: propertyTypeLabel })
|
|
4454
|
-
] }) : null
|
|
4708
|
+
] }) }) : null
|
|
4455
4709
|
] });
|
|
4456
4710
|
}
|
|
4457
4711
|
);
|
|
@@ -4688,12 +4942,21 @@ var Header = ({
|
|
|
4688
4942
|
onWalletNavigate: _onWalletNavigate,
|
|
4689
4943
|
showTradeTab = true
|
|
4690
4944
|
}) => {
|
|
4691
|
-
const [isUserMenuOpen, setIsUserMenuOpen] =
|
|
4692
|
-
const [isMobileMenuOpen, setIsMobileMenuOpen] =
|
|
4693
|
-
const [isMoreMenuOpen, setIsMoreMenuOpen] =
|
|
4694
|
-
const [showLoginPopup, setShowLoginPopup] =
|
|
4695
|
-
const [loginPopupInitialView, setLoginPopupInitialView] =
|
|
4696
|
-
|
|
4945
|
+
const [isUserMenuOpen, setIsUserMenuOpen] = React9.useState(false);
|
|
4946
|
+
const [isMobileMenuOpen, setIsMobileMenuOpen] = React9.useState(false);
|
|
4947
|
+
const [isMoreMenuOpen, setIsMoreMenuOpen] = React9.useState(false);
|
|
4948
|
+
const [showLoginPopup, setShowLoginPopup] = React9.useState(false);
|
|
4949
|
+
const [loginPopupInitialView, setLoginPopupInitialView] = React9.useState(void 0);
|
|
4950
|
+
React9.useEffect(() => {
|
|
4951
|
+
if (typeof window === "undefined") return;
|
|
4952
|
+
const ua = navigator.userAgent;
|
|
4953
|
+
const isTelegram = /Telegram/i.test(ua);
|
|
4954
|
+
const isIOS = /iPhone|iPad|iPod/.test(ua);
|
|
4955
|
+
if (isTelegram && isIOS) {
|
|
4956
|
+
document.documentElement.style.setProperty("--telegram-safe-top", "59px");
|
|
4957
|
+
}
|
|
4958
|
+
}, []);
|
|
4959
|
+
React9.useEffect(() => {
|
|
4697
4960
|
const handleClickOutside = (event) => {
|
|
4698
4961
|
const target = event.target;
|
|
4699
4962
|
if (!target) return;
|
|
@@ -4713,7 +4976,7 @@ var Header = ({
|
|
|
4713
4976
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
4714
4977
|
};
|
|
4715
4978
|
}, [isUserMenuOpen, isMobileMenuOpen, isMoreMenuOpen]);
|
|
4716
|
-
|
|
4979
|
+
React9.useEffect(() => {
|
|
4717
4980
|
if (typeof window === "undefined") return;
|
|
4718
4981
|
const handleExternalLoginPopup = (event) => {
|
|
4719
4982
|
const customEvent = event;
|
|
@@ -4843,7 +5106,7 @@ var Header = ({
|
|
|
4843
5106
|
setShowLoginPopup(true);
|
|
4844
5107
|
}
|
|
4845
5108
|
};
|
|
4846
|
-
const handleLoginPopupClose =
|
|
5109
|
+
const handleLoginPopupClose = React9__namespace.default.useCallback(() => {
|
|
4847
5110
|
setShowLoginPopup(false);
|
|
4848
5111
|
setLoginPopupInitialView(void 0);
|
|
4849
5112
|
}, []);
|
|
@@ -5131,8 +5394,8 @@ var SafeAreaCover = styled24__default.default.div`
|
|
|
5131
5394
|
top: 0;
|
|
5132
5395
|
left: 0;
|
|
5133
5396
|
right: 0;
|
|
5134
|
-
height: env(safe-area-inset-top, 0px);
|
|
5135
|
-
min-height: env(safe-area-inset-top, 0px);
|
|
5397
|
+
height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5398
|
+
min-height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5136
5399
|
background-color: #0d1117;
|
|
5137
5400
|
z-index: 1001;
|
|
5138
5401
|
pointer-events: none;
|
|
@@ -5186,7 +5449,7 @@ var HeaderContainer = styled24__default.default.header`
|
|
|
5186
5449
|
/* Split padding so browsers that don't support env() inside shorthand
|
|
5187
5450
|
still get the horizontal padding — only the top falls back to 0 */
|
|
5188
5451
|
padding: 0 2rem;
|
|
5189
|
-
padding-top: env(safe-area-inset-top, 0px);
|
|
5452
|
+
padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5190
5453
|
background-color: #0d1117;
|
|
5191
5454
|
border-bottom: 1px solid #232a32;
|
|
5192
5455
|
position: fixed;
|
|
@@ -5197,18 +5460,18 @@ var HeaderContainer = styled24__default.default.header`
|
|
|
5197
5460
|
width: 100%;
|
|
5198
5461
|
/* Fallback min-height for browsers that can't evaluate calc+env */
|
|
5199
5462
|
min-height: 56px;
|
|
5200
|
-
min-height: calc(56px + env(safe-area-inset-top, 0px));
|
|
5463
|
+
min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5201
5464
|
box-sizing: border-box;
|
|
5202
5465
|
|
|
5203
5466
|
@media (max-width: 768px) {
|
|
5204
5467
|
padding: 0 1rem;
|
|
5205
|
-
padding-top: env(safe-area-inset-top, 0px);
|
|
5468
|
+
padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5206
5469
|
}
|
|
5207
5470
|
`;
|
|
5208
5471
|
var HeaderSpacer = styled24__default.default.div`
|
|
5209
5472
|
width: 100%;
|
|
5210
5473
|
min-height: 56px;
|
|
5211
|
-
min-height: calc(56px + env(safe-area-inset-top, 0px));
|
|
5474
|
+
min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5212
5475
|
flex-shrink: 0;
|
|
5213
5476
|
`;
|
|
5214
5477
|
var Logo = styled24__default.default.div`
|
|
@@ -5263,12 +5526,12 @@ var Nav = styled24__default.default.nav`
|
|
|
5263
5526
|
@media (max-width: 1300px) {
|
|
5264
5527
|
position: fixed;
|
|
5265
5528
|
top: 56px;
|
|
5266
|
-
top: calc(56px + env(safe-area-inset-top, 0px));
|
|
5529
|
+
top: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5267
5530
|
right: ${(props) => props.$isOpen ? "0" : "-100%"} ;
|
|
5268
5531
|
width: 280px;
|
|
5269
5532
|
max-width: 280px;
|
|
5270
5533
|
height: calc(100vh - 56px);
|
|
5271
|
-
height: calc(100vh - 56px - env(safe-area-inset-top, 0px));
|
|
5534
|
+
height: calc(100vh - 56px - max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5272
5535
|
background: linear-gradient(180deg, #0f1419 0%, #0a0e13 100%);
|
|
5273
5536
|
z-index: 1000;
|
|
5274
5537
|
transition: right 0.3s ease;
|
|
@@ -5541,10 +5804,10 @@ var MobileNavItem = styled24__default.default.div`
|
|
|
5541
5804
|
padding-left: 24px;
|
|
5542
5805
|
}
|
|
5543
5806
|
`;
|
|
5544
|
-
var PropertySubheader =
|
|
5807
|
+
var PropertySubheader = React9__namespace.forwardRef(
|
|
5545
5808
|
({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
|
|
5546
|
-
const tabsContainerRef =
|
|
5547
|
-
|
|
5809
|
+
const tabsContainerRef = React9__namespace.useRef(null);
|
|
5810
|
+
React9__namespace.useEffect(() => {
|
|
5548
5811
|
const container = tabsContainerRef.current;
|
|
5549
5812
|
if (!container) return;
|
|
5550
5813
|
const isMobile = window.innerWidth <= 768;
|
|
@@ -5686,27 +5949,27 @@ var LoginPopup = ({
|
|
|
5686
5949
|
onFundWallet,
|
|
5687
5950
|
initialView
|
|
5688
5951
|
}) => {
|
|
5689
|
-
const [view, setView] =
|
|
5690
|
-
const [email, setEmail] =
|
|
5691
|
-
const [handle, setHandle] =
|
|
5692
|
-
const [otp, setOtp] =
|
|
5693
|
-
const [error, setError] =
|
|
5694
|
-
const [loading, setLoading] =
|
|
5695
|
-
const [isSignUp, setIsSignUp] =
|
|
5696
|
-
const [fundingAmount] =
|
|
5697
|
-
const [kycLoading, setKycLoading] =
|
|
5698
|
-
const [showKycWidget, setShowKycWidget] =
|
|
5699
|
-
const [cryptoFundingLoading, setCryptoFundingLoading] =
|
|
5700
|
-
const [fiatFundingLoading, setFiatFundingLoading] =
|
|
5701
|
-
const [fundingError, setFundingError] =
|
|
5702
|
-
const [transakWidgetUrl, setTransakWidgetUrl] =
|
|
5703
|
-
const suppressAutoCloseRef =
|
|
5704
|
-
|
|
5952
|
+
const [view, setView] = React9.useState(() => initialView ?? "main");
|
|
5953
|
+
const [email, setEmail] = React9.useState("");
|
|
5954
|
+
const [handle, setHandle] = React9.useState("");
|
|
5955
|
+
const [otp, setOtp] = React9.useState(Array(OTP_INPUT_LENGTH).fill(""));
|
|
5956
|
+
const [error, setError] = React9.useState("");
|
|
5957
|
+
const [loading, setLoading] = React9.useState(false);
|
|
5958
|
+
const [isSignUp, setIsSignUp] = React9.useState(false);
|
|
5959
|
+
const [fundingAmount] = React9.useState("");
|
|
5960
|
+
const [kycLoading, setKycLoading] = React9.useState(false);
|
|
5961
|
+
const [showKycWidget, setShowKycWidget] = React9.useState(false);
|
|
5962
|
+
const [cryptoFundingLoading, setCryptoFundingLoading] = React9.useState(false);
|
|
5963
|
+
const [fiatFundingLoading, setFiatFundingLoading] = React9.useState(false);
|
|
5964
|
+
const [fundingError, setFundingError] = React9.useState("");
|
|
5965
|
+
const [transakWidgetUrl, setTransakWidgetUrl] = React9.useState(null);
|
|
5966
|
+
const suppressAutoCloseRef = React9__namespace.default.useRef(false);
|
|
5967
|
+
React9.useEffect(() => {
|
|
5705
5968
|
if (typeof initialView === "string") {
|
|
5706
5969
|
setView(initialView);
|
|
5707
5970
|
}
|
|
5708
5971
|
}, [initialView]);
|
|
5709
|
-
|
|
5972
|
+
React9.useEffect(() => {
|
|
5710
5973
|
if (!transakWidgetUrl) return;
|
|
5711
5974
|
const handleTransakMessage = (event) => {
|
|
5712
5975
|
if (!event.origin.includes("transak.com") && !event.origin.includes("global.transak.com")) {
|
|
@@ -5731,7 +5994,7 @@ var LoginPopup = ({
|
|
|
5731
5994
|
window.addEventListener("message", handleTransakMessage);
|
|
5732
5995
|
return () => window.removeEventListener("message", handleTransakMessage);
|
|
5733
5996
|
}, [transakWidgetUrl, onClose]);
|
|
5734
|
-
|
|
5997
|
+
React9.useEffect(() => {
|
|
5735
5998
|
if (!autoCloseOnAuth) {
|
|
5736
5999
|
return;
|
|
5737
6000
|
}
|
|
@@ -6703,8 +6966,8 @@ var TransakIframe = styled24__default.default.iframe`
|
|
|
6703
6966
|
border-radius: var(--border-radius, 12px);
|
|
6704
6967
|
`;
|
|
6705
6968
|
var MiniLiveFeed = () => {
|
|
6706
|
-
const [purchases, setPurchases] =
|
|
6707
|
-
|
|
6969
|
+
const [purchases, setPurchases] = React9.useState([]);
|
|
6970
|
+
React9.useEffect(() => {
|
|
6708
6971
|
const handles = [
|
|
6709
6972
|
"Landlord",
|
|
6710
6973
|
"PropertyKing",
|
|
@@ -6880,7 +7143,7 @@ var MiniLiveFeed = () => {
|
|
|
6880
7143
|
);
|
|
6881
7144
|
};
|
|
6882
7145
|
LoginPopup.displayName = "LoginPopup";
|
|
6883
|
-
var PropertyCompareBar =
|
|
7146
|
+
var PropertyCompareBar = React9__namespace.forwardRef(
|
|
6884
7147
|
({
|
|
6885
7148
|
className,
|
|
6886
7149
|
addresses,
|
|
@@ -6891,7 +7154,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
6891
7154
|
price,
|
|
6892
7155
|
...props
|
|
6893
7156
|
}, ref) => {
|
|
6894
|
-
const normalizedAddresses =
|
|
7157
|
+
const normalizedAddresses = React9__namespace.useMemo(() => {
|
|
6895
7158
|
return addresses.map(
|
|
6896
7159
|
(option) => typeof option === "string" ? { id: option, label: option } : option
|
|
6897
7160
|
);
|
|
@@ -6899,11 +7162,11 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
6899
7162
|
const hasAddresses = normalizedAddresses.length > 0;
|
|
6900
7163
|
const firstAddressId = normalizedAddresses[0]?.id;
|
|
6901
7164
|
const isControlled = selectedAddressId !== void 0;
|
|
6902
|
-
const [internalSelectedId, setInternalSelectedId] =
|
|
7165
|
+
const [internalSelectedId, setInternalSelectedId] = React9__namespace.useState(
|
|
6903
7166
|
() => isControlled ? void 0 : firstAddressId
|
|
6904
7167
|
);
|
|
6905
7168
|
const resolvedSelectedId = isControlled ? selectedAddressId : internalSelectedId;
|
|
6906
|
-
|
|
7169
|
+
React9__namespace.useEffect(() => {
|
|
6907
7170
|
if (!isControlled) {
|
|
6908
7171
|
setInternalSelectedId((current) => {
|
|
6909
7172
|
if (current != null && normalizedAddresses.some((option) => option.id === current)) {
|
|
@@ -6914,9 +7177,9 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
6914
7177
|
}
|
|
6915
7178
|
}, [firstAddressId, isControlled, normalizedAddresses]);
|
|
6916
7179
|
const selectedOption = normalizedAddresses.find((option) => option.id === resolvedSelectedId) ?? normalizedAddresses[0];
|
|
6917
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
6918
|
-
const dropdownRef =
|
|
6919
|
-
|
|
7180
|
+
const [isDropdownOpen, setIsDropdownOpen] = React9__namespace.useState(false);
|
|
7181
|
+
const dropdownRef = React9__namespace.useRef(null);
|
|
7182
|
+
React9__namespace.useEffect(() => {
|
|
6920
7183
|
if (!isDropdownOpen) return;
|
|
6921
7184
|
const handleClick = (event) => {
|
|
6922
7185
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
@@ -7319,11 +7582,11 @@ function GalleryMapSection({
|
|
|
7319
7582
|
autoPlay = true,
|
|
7320
7583
|
autoPlayInterval = 4e3
|
|
7321
7584
|
}) {
|
|
7322
|
-
const [carouselIndex, setCarouselIndex] =
|
|
7323
|
-
const [showVideo, setShowVideo] =
|
|
7324
|
-
const [autoPlaying, setAutoPlaying] =
|
|
7585
|
+
const [carouselIndex, setCarouselIndex] = React9.useState(0);
|
|
7586
|
+
const [showVideo, setShowVideo] = React9.useState(false);
|
|
7587
|
+
const [autoPlaying, setAutoPlaying] = React9.useState(autoPlay);
|
|
7325
7588
|
const resolvedMapUrl = mapUrl ?? (tokenName ? `/map/${tokenName}?embed=true&zoom=14&hideOthers=true` : "about:blank");
|
|
7326
|
-
|
|
7589
|
+
React9.useEffect(() => {
|
|
7327
7590
|
if (!autoPlaying || images.length <= 1) return;
|
|
7328
7591
|
const interval = setInterval(() => {
|
|
7329
7592
|
setCarouselIndex((p) => (p + 1) % images.length);
|
|
@@ -7639,9 +7902,10 @@ function PropertyOverview({
|
|
|
7639
7902
|
bathrooms,
|
|
7640
7903
|
carSpaces,
|
|
7641
7904
|
propertyTypeLabel,
|
|
7642
|
-
tokensIssued: tokensIssuedProp
|
|
7905
|
+
tokensIssued: tokensIssuedProp,
|
|
7906
|
+
isLoading = false
|
|
7643
7907
|
}) {
|
|
7644
|
-
const [isDescExpanded, setDescExpanded] =
|
|
7908
|
+
const [isDescExpanded, setDescExpanded] = React9.useState(false);
|
|
7645
7909
|
const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
|
|
7646
7910
|
const landSize = landProp ?? overviewData?.landSizeSqm ?? null;
|
|
7647
7911
|
const buildingSize = buildingProp ?? overviewData?.buildingSizeSqm ?? null;
|
|
@@ -7677,13 +7941,14 @@ function PropertyOverview({
|
|
|
7677
7941
|
const weeklyRent = overviewData?.weeklyRent ?? 0;
|
|
7678
7942
|
const annualRent = weeklyRent * 52;
|
|
7679
7943
|
const dividendYield = resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
|
|
7944
|
+
const loadingSkeleton = /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 90, height: 18 });
|
|
7680
7945
|
const financialItems = financialItemsProp ?? [
|
|
7681
|
-
{ label: "Token Price", value: tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
|
|
7682
|
-
{ label: "Property Value", value: resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
|
|
7683
|
-
{ label: "Weekly Rent", value: weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
|
|
7684
|
-
{ label: "Dividend Yield", value: dividendYield ? `${dividendYield}%` : "N/A" },
|
|
7685
|
-
{ label: "Total Tokens", value: resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
|
|
7686
|
-
{ label: "Indicative Listing", value: overviewData?.indicativeListing ?? "N/A" }
|
|
7946
|
+
{ label: "Token Price", value: isLoading && tokenPriceValue == null ? loadingSkeleton : tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
|
|
7947
|
+
{ label: "Property Value", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
|
|
7948
|
+
{ label: "Weekly Rent", value: isLoading && !overviewData ? loadingSkeleton : weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
|
|
7949
|
+
{ label: "Dividend Yield", value: isLoading && dividendYield == null && resolvedValuation == null ? loadingSkeleton : dividendYield ? `${dividendYield}%` : "N/A" },
|
|
7950
|
+
{ label: "Total Tokens", value: isLoading && resolvedTokensIssued == null ? loadingSkeleton : resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
|
|
7951
|
+
{ label: "Indicative Listing", value: isLoading && !overviewData ? loadingSkeleton : overviewData?.indicativeListing ?? "N/A" }
|
|
7687
7952
|
];
|
|
7688
7953
|
const galleryImages = images ?? [];
|
|
7689
7954
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
@@ -7987,8 +8252,8 @@ var OfferPricePulse = styled24__default.default.span`
|
|
|
7987
8252
|
`;
|
|
7988
8253
|
var eventTypes = ["Leased", "Renovated", "Extended", "Rebuilt", "Rezoned", "DA Approval"];
|
|
7989
8254
|
function PropertyHistory() {
|
|
7990
|
-
const [historyFilter, setHistoryFilter] =
|
|
7991
|
-
const pastSales =
|
|
8255
|
+
const [historyFilter, setHistoryFilter] = React9.useState("all");
|
|
8256
|
+
const pastSales = React9.useMemo(() => generateMockPastSales(), []);
|
|
7992
8257
|
const loafListing = pastSales.find((sale) => sale.type === "Listed");
|
|
7993
8258
|
const loafEvents = pastSales.filter(
|
|
7994
8259
|
(sale) => sale.ownershipPeriod === "current" && sale.type !== "Listed" && (sale.id === "leased-current" || sale.id === "da-approval")
|
|
@@ -8125,7 +8390,7 @@ function PropertyHistory() {
|
|
|
8125
8390
|
] });
|
|
8126
8391
|
}
|
|
8127
8392
|
function EventDetails({ event }) {
|
|
8128
|
-
const [expanded, setExpanded] =
|
|
8393
|
+
const [expanded, setExpanded] = React9.useState(false);
|
|
8129
8394
|
const toggleExpand = () => {
|
|
8130
8395
|
setExpanded((prev) => !prev);
|
|
8131
8396
|
};
|
|
@@ -8913,7 +9178,7 @@ function AssetSelectorBar({
|
|
|
8913
9178
|
selectorItems,
|
|
8914
9179
|
onSelect
|
|
8915
9180
|
}) {
|
|
8916
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
9181
|
+
const [isDropdownOpen, setIsDropdownOpen] = React9.useState(false);
|
|
8917
9182
|
const hasItems = selectorItems && selectorItems.length > 0;
|
|
8918
9183
|
const metrics = metricsProp ?? [
|
|
8919
9184
|
...tokenPrice != null ? [{ label: "Unit Price", value: `$${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, accent: true }] : [],
|
|
@@ -9182,15 +9447,15 @@ function OfferingProgressCard({
|
|
|
9182
9447
|
targetAmount,
|
|
9183
9448
|
isPrivateClient = false
|
|
9184
9449
|
}) {
|
|
9185
|
-
const [currentTime, setCurrentTime] =
|
|
9186
|
-
const [countdown, setCountdown] =
|
|
9450
|
+
const [currentTime, setCurrentTime] = React9.useState(/* @__PURE__ */ new Date());
|
|
9451
|
+
const [countdown, setCountdown] = React9.useState(null);
|
|
9187
9452
|
const computedRaised = raisedAmount ?? totalSold * tokenPrice;
|
|
9188
9453
|
const computedTarget = targetAmount ?? supplyToSell * tokenPrice;
|
|
9189
|
-
|
|
9454
|
+
React9.useEffect(() => {
|
|
9190
9455
|
const timer = setInterval(() => setCurrentTime(/* @__PURE__ */ new Date()), 1e3);
|
|
9191
9456
|
return () => clearInterval(timer);
|
|
9192
9457
|
}, []);
|
|
9193
|
-
|
|
9458
|
+
React9.useEffect(() => {
|
|
9194
9459
|
if (!opensAt) {
|
|
9195
9460
|
setCountdown(null);
|
|
9196
9461
|
return;
|
|
@@ -9527,14 +9792,19 @@ var formatTimeAgo2 = (timestamp) => {
|
|
|
9527
9792
|
};
|
|
9528
9793
|
function VideoActivitySection({
|
|
9529
9794
|
ipoStarted,
|
|
9795
|
+
ipoEnded = false,
|
|
9796
|
+
isLoading = false,
|
|
9530
9797
|
recentOrders = [],
|
|
9531
9798
|
ordersAllocated = 0,
|
|
9532
9799
|
tokenPrice = 0
|
|
9533
9800
|
}) {
|
|
9534
|
-
const sortedOrders =
|
|
9801
|
+
const sortedOrders = React9.useMemo(
|
|
9535
9802
|
() => [...recentOrders].sort((a, b) => b.timestamp - a.timestamp).slice(0, 7),
|
|
9536
9803
|
[recentOrders]
|
|
9537
9804
|
);
|
|
9805
|
+
const headerStatusText = ipoEnded ? `Sale ended${ordersAllocated > 0 ? ` \xB7 ${ordersAllocated.toLocaleString()} orders` : ""}` : ipoStarted ? isLoading && sortedOrders.length === 0 ? "Loading orders\u2026" : `Active orders: ${ordersAllocated.toLocaleString()}` : "Waiting for Offer to Open";
|
|
9806
|
+
const showSkeletonFeed = ipoStarted && isLoading && sortedOrders.length === 0;
|
|
9807
|
+
const showOrderFeed = !showSkeletonFeed && (ipoStarted || ipoEnded && sortedOrders.length > 0);
|
|
9538
9808
|
return /* @__PURE__ */ jsxRuntime.jsxs(Section3, { children: [
|
|
9539
9809
|
/* @__PURE__ */ jsxRuntime.jsxs(VideoPanel, { children: [
|
|
9540
9810
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "section-header", children: /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Musgrave" }) }),
|
|
@@ -9546,31 +9816,40 @@ function VideoActivitySection({
|
|
|
9546
9816
|
/* @__PURE__ */ jsxRuntime.jsxs(ActivityPanel, { children: [
|
|
9547
9817
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "section-header", children: [
|
|
9548
9818
|
/* @__PURE__ */ jsxRuntime.jsxs("h3", { children: [
|
|
9549
|
-
/* @__PURE__ */ jsxRuntime.jsx(LiveIndicatorDot, { $active: ipoStarted }),
|
|
9819
|
+
/* @__PURE__ */ jsxRuntime.jsx(LiveIndicatorDot, { $active: ipoStarted && !ipoEnded }),
|
|
9550
9820
|
"Recent Order Activity"
|
|
9551
9821
|
] }),
|
|
9552
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
9822
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: headerStatusText })
|
|
9553
9823
|
] }),
|
|
9554
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-content", children:
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
|
|
9824
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-content", children: showSkeletonFeed ? /* @__PURE__ */ jsxRuntime.jsx(FeedList, { children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs(SkeletonFeedRow, { children: [
|
|
9825
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "info-col", children: [
|
|
9826
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 14 }),
|
|
9827
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 56, height: 10 })
|
|
9828
|
+
] }),
|
|
9829
|
+
/* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 70, height: 14 })
|
|
9830
|
+
] }, `feed-skel-${i}`)) }) : showOrderFeed ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9831
|
+
ipoEnded && /* @__PURE__ */ jsxRuntime.jsx(EndedBanner, { children: "Sale ended \u2014 final allocations" }),
|
|
9832
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedList, { children: sortedOrders.map((order, index) => {
|
|
9833
|
+
const amount = tokenPrice * order.quantity;
|
|
9834
|
+
const barPercent = Math.min(85, Math.max(15, amount / MAX_DISPLAY_AMOUNT * 100));
|
|
9835
|
+
const isAlternate = index % 2 === 1;
|
|
9836
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9837
|
+
PurchaseItem,
|
|
9838
|
+
{
|
|
9839
|
+
$barWidth: `${barPercent}%`,
|
|
9840
|
+
$isAlternate: isAlternate,
|
|
9841
|
+
children: [
|
|
9842
|
+
/* @__PURE__ */ jsxRuntime.jsxs(PurchaseInfo, { children: [
|
|
9843
|
+
/* @__PURE__ */ jsxRuntime.jsx(PurchaseName, { children: order.buyerHandle || `${order.buyerAddress.slice(0, 6)}...${order.buyerAddress.slice(-4)}` }),
|
|
9844
|
+
/* @__PURE__ */ jsxRuntime.jsx(PurchaseTime, { children: formatTimeAgo2(order.timestamp) })
|
|
9845
|
+
] }),
|
|
9846
|
+
/* @__PURE__ */ jsxRuntime.jsx(PurchaseAmount, { children: formatCurrency4(amount) })
|
|
9847
|
+
]
|
|
9848
|
+
},
|
|
9849
|
+
order.txHash
|
|
9850
|
+
);
|
|
9851
|
+
}) })
|
|
9852
|
+
] }) : ipoEnded ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-empty", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Sale ended \u2014 no orders were placed." }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "activity-empty", children: [
|
|
9574
9853
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner" }),
|
|
9575
9854
|
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Activity will appear once the Offering opens" })
|
|
9576
9855
|
] }) })
|
|
@@ -9711,6 +9990,43 @@ var ActivityPanel = styled24__default.default.div`
|
|
|
9711
9990
|
to { transform: rotate(360deg); }
|
|
9712
9991
|
}
|
|
9713
9992
|
`;
|
|
9993
|
+
var SkeletonFeedRow = styled24__default.default.div`
|
|
9994
|
+
padding: 0.625rem 0.75rem;
|
|
9995
|
+
border-bottom: 1px solid rgba(255,255,255,0.04);
|
|
9996
|
+
display: flex;
|
|
9997
|
+
justify-content: space-between;
|
|
9998
|
+
align-items: center;
|
|
9999
|
+
gap: 1rem;
|
|
10000
|
+
|
|
10001
|
+
&:last-child {
|
|
10002
|
+
border-bottom: none;
|
|
10003
|
+
}
|
|
10004
|
+
|
|
10005
|
+
.info-col {
|
|
10006
|
+
display: flex;
|
|
10007
|
+
flex-direction: column;
|
|
10008
|
+
gap: 0.3rem;
|
|
10009
|
+
min-width: 0;
|
|
10010
|
+
flex: 1;
|
|
10011
|
+
}
|
|
10012
|
+
|
|
10013
|
+
@media (max-width: 768px) {
|
|
10014
|
+
padding: 0.4rem 0.6rem;
|
|
10015
|
+
}
|
|
10016
|
+
`;
|
|
10017
|
+
var EndedBanner = styled24__default.default.div`
|
|
10018
|
+
font-size: 0.7rem;
|
|
10019
|
+
font-weight: 600;
|
|
10020
|
+
letter-spacing: 0.04em;
|
|
10021
|
+
text-transform: uppercase;
|
|
10022
|
+
color: rgba(255, 255, 255, 0.55);
|
|
10023
|
+
background: rgba(255, 255, 255, 0.04);
|
|
10024
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
10025
|
+
border-radius: 6px;
|
|
10026
|
+
padding: 0.4rem 0.6rem;
|
|
10027
|
+
margin-bottom: 0.5rem;
|
|
10028
|
+
text-align: center;
|
|
10029
|
+
`;
|
|
9714
10030
|
var FeedList = styled24__default.default.div`
|
|
9715
10031
|
width: 100%;
|
|
9716
10032
|
overflow-y: auto;
|
|
@@ -9828,10 +10144,10 @@ function OrderPanel({
|
|
|
9828
10144
|
tokenDisplayName,
|
|
9829
10145
|
tokenSymbol
|
|
9830
10146
|
}) {
|
|
9831
|
-
const [payInputValue, setPayInputValue] =
|
|
9832
|
-
const [receiveInputValue, setReceiveInputValue] =
|
|
9833
|
-
const [isPayInputFocused, setIsPayInputFocused] =
|
|
9834
|
-
const [isReceiveInputFocused, setIsReceiveInputFocused] =
|
|
10147
|
+
const [payInputValue, setPayInputValue] = React9.useState("");
|
|
10148
|
+
const [receiveInputValue, setReceiveInputValue] = React9.useState("");
|
|
10149
|
+
const [isPayInputFocused, setIsPayInputFocused] = React9.useState(false);
|
|
10150
|
+
const [isReceiveInputFocused, setIsReceiveInputFocused] = React9.useState(false);
|
|
9835
10151
|
const handlePayBlur = () => {
|
|
9836
10152
|
setIsPayInputFocused(false);
|
|
9837
10153
|
const parsed = parseInt(payInputValue.replace(/[^0-9]/g, ""), 10) || 0;
|
|
@@ -10677,9 +10993,9 @@ function PortfolioActivityPanel({
|
|
|
10677
10993
|
style
|
|
10678
10994
|
}) {
|
|
10679
10995
|
const resolvedDefaultTab = defaultTab ?? (showPositionsTab ? "positions" : "subscriptions");
|
|
10680
|
-
const [activeTab, setActiveTab] =
|
|
10681
|
-
const [activityPage, setActivityPage] =
|
|
10682
|
-
const activeTabTotal =
|
|
10996
|
+
const [activeTab, setActiveTab] = React9.useState(resolvedDefaultTab);
|
|
10997
|
+
const [activityPage, setActivityPage] = React9.useState(0);
|
|
10998
|
+
const activeTabTotal = React9.useMemo(() => {
|
|
10683
10999
|
switch (activeTab) {
|
|
10684
11000
|
case "positions":
|
|
10685
11001
|
return positions.length;
|
|
@@ -10697,6 +11013,22 @@ function PortfolioActivityPanel({
|
|
|
10697
11013
|
return 0;
|
|
10698
11014
|
}
|
|
10699
11015
|
}, [activeTab, positions.length, offeringOrders.length, openOrders.length, orderHistory.length, tradeHistory.length, transfers.length]);
|
|
11016
|
+
const positionsCount = positions.length;
|
|
11017
|
+
const openOrdersCount = React9.useMemo(
|
|
11018
|
+
() => openOrders.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
|
|
11019
|
+
[openOrders]
|
|
11020
|
+
);
|
|
11021
|
+
const pendingHistoryCount = React9.useMemo(
|
|
11022
|
+
() => orderHistory.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
|
|
11023
|
+
[orderHistory]
|
|
11024
|
+
);
|
|
11025
|
+
const pendingOfferingsCount = React9.useMemo(
|
|
11026
|
+
() => offeringOrders.filter((o) => {
|
|
11027
|
+
const s = o.status.toUpperCase();
|
|
11028
|
+
return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
|
|
11029
|
+
}).length,
|
|
11030
|
+
[offeringOrders]
|
|
11031
|
+
);
|
|
10700
11032
|
const activityTotalPages = Math.ceil(activeTabTotal / pageSize);
|
|
10701
11033
|
const pageSlice = (arr) => arr.slice(activityPage * pageSize, (activityPage + 1) * pageSize);
|
|
10702
11034
|
const handleTabChange = (tab) => {
|
|
@@ -10706,10 +11038,38 @@ function PortfolioActivityPanel({
|
|
|
10706
11038
|
return /* @__PURE__ */ jsxRuntime.jsxs(Container2, { className, style, children: [
|
|
10707
11039
|
/* @__PURE__ */ jsxRuntime.jsx(PanelTitle, { children: "Activity" }),
|
|
10708
11040
|
/* @__PURE__ */ jsxRuntime.jsxs(TabContainer, { children: [
|
|
10709
|
-
showPositionsTab && /* @__PURE__ */ jsxRuntime.
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
11041
|
+
showPositionsTab && /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "positions", onClick: () => handleTabChange("positions"), children: [
|
|
11042
|
+
"Positions",
|
|
11043
|
+
positionsCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
|
|
11044
|
+
" (",
|
|
11045
|
+
positionsCount,
|
|
11046
|
+
")"
|
|
11047
|
+
] })
|
|
11048
|
+
] }),
|
|
11049
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "subscriptions", onClick: () => handleTabChange("subscriptions"), children: [
|
|
11050
|
+
"Initial Offerings",
|
|
11051
|
+
pendingOfferingsCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
|
|
11052
|
+
" (",
|
|
11053
|
+
pendingOfferingsCount,
|
|
11054
|
+
")"
|
|
11055
|
+
] })
|
|
11056
|
+
] }),
|
|
11057
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "open-orders", onClick: () => handleTabChange("open-orders"), children: [
|
|
11058
|
+
"Open Orders",
|
|
11059
|
+
openOrdersCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
|
|
11060
|
+
" (",
|
|
11061
|
+
openOrdersCount,
|
|
11062
|
+
")"
|
|
11063
|
+
] })
|
|
11064
|
+
] }),
|
|
11065
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "orders", onClick: () => handleTabChange("orders"), children: [
|
|
11066
|
+
"Order History",
|
|
11067
|
+
pendingHistoryCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
|
|
11068
|
+
" (",
|
|
11069
|
+
pendingHistoryCount,
|
|
11070
|
+
")"
|
|
11071
|
+
] })
|
|
11072
|
+
] }),
|
|
10713
11073
|
/* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "trades", onClick: () => handleTabChange("trades"), children: "Trade History" }),
|
|
10714
11074
|
/* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "transfers", onClick: () => handleTabChange("transfers"), children: "Transfers" })
|
|
10715
11075
|
] }),
|
|
@@ -10794,8 +11154,10 @@ function PortfolioActivityPanel({
|
|
|
10794
11154
|
openOrders.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: "Open orders will appear here while they are working in the market." }),
|
|
10795
11155
|
pageSlice(openOrders).map((order) => {
|
|
10796
11156
|
const meta = getOrderStatusMeta(order.status);
|
|
10797
|
-
const
|
|
10798
|
-
const
|
|
11157
|
+
const isMarket = order.type === "MARKET";
|
|
11158
|
+
const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
|
|
11159
|
+
const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
|
|
11160
|
+
const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
|
|
10799
11161
|
const isCancelling = cancellingOrderId === order.id;
|
|
10800
11162
|
return /* @__PURE__ */ jsxRuntime.jsxs(ActivityRow, { children: [
|
|
10801
11163
|
/* @__PURE__ */ jsxRuntime.jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
|
|
@@ -10805,9 +11167,10 @@ function PortfolioActivityPanel({
|
|
|
10805
11167
|
formatNumber2(order.quantity),
|
|
10806
11168
|
" tokens \xB7 ",
|
|
10807
11169
|
prettyLabel(order.type),
|
|
11170
|
+
priceSegment,
|
|
10808
11171
|
" \xB7 ",
|
|
10809
|
-
|
|
10810
|
-
" \xB7 ",
|
|
11172
|
+
filledPercent,
|
|
11173
|
+
"% filled \xB7 ",
|
|
10811
11174
|
formatTimestamp(order.createdAt)
|
|
10812
11175
|
] })
|
|
10813
11176
|
] }),
|
|
@@ -10834,8 +11197,10 @@ function PortfolioActivityPanel({
|
|
|
10834
11197
|
orderHistory.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: "No orders yet. Place a trade to see it appear here." }),
|
|
10835
11198
|
pageSlice(orderHistory).map((order) => {
|
|
10836
11199
|
const meta = getOrderStatusMeta(order.status);
|
|
10837
|
-
const
|
|
10838
|
-
const
|
|
11200
|
+
const isMarket = order.type === "MARKET";
|
|
11201
|
+
const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
|
|
11202
|
+
const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
|
|
11203
|
+
const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
|
|
10839
11204
|
return /* @__PURE__ */ jsxRuntime.jsxs(ActivityRow, { children: [
|
|
10840
11205
|
/* @__PURE__ */ jsxRuntime.jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
|
|
10841
11206
|
/* @__PURE__ */ jsxRuntime.jsxs(ActivityInfo, { children: [
|
|
@@ -10844,9 +11209,10 @@ function PortfolioActivityPanel({
|
|
|
10844
11209
|
formatNumber2(order.quantity),
|
|
10845
11210
|
" tokens \xB7 ",
|
|
10846
11211
|
prettyLabel(order.type),
|
|
11212
|
+
priceSegment,
|
|
10847
11213
|
" \xB7 ",
|
|
10848
|
-
|
|
10849
|
-
" \xB7 ",
|
|
11214
|
+
filledPercent,
|
|
11215
|
+
"% filled \xB7 ",
|
|
10850
11216
|
formatTimestamp(order.createdAt)
|
|
10851
11217
|
] })
|
|
10852
11218
|
] }),
|
|
@@ -10988,6 +11354,12 @@ var Tab = styled24__default.default.button`
|
|
|
10988
11354
|
color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.65)"};
|
|
10989
11355
|
}
|
|
10990
11356
|
`;
|
|
11357
|
+
var TabCount = styled24__default.default.span`
|
|
11358
|
+
color: inherit;
|
|
11359
|
+
opacity: 0.7;
|
|
11360
|
+
font-weight: 500;
|
|
11361
|
+
margin-left: 2px;
|
|
11362
|
+
`;
|
|
10991
11363
|
var ActivityRow = styled24__default.default.div`
|
|
10992
11364
|
display: grid;
|
|
10993
11365
|
grid-template-columns: auto 1fr auto auto;
|
|
@@ -11631,23 +12003,24 @@ function PropertyBuy({
|
|
|
11631
12003
|
recentOrders = [],
|
|
11632
12004
|
ordersAllocated = 0,
|
|
11633
12005
|
subscribers = 0,
|
|
12006
|
+
isLoadingActivity = false,
|
|
11634
12007
|
selectorItems,
|
|
11635
12008
|
onSelectorSelect,
|
|
11636
12009
|
portfolioActivity
|
|
11637
12010
|
}) {
|
|
11638
|
-
const [sliderValue, setSliderValue] =
|
|
11639
|
-
const [availableBalance, setAvailableBalance] =
|
|
11640
|
-
const [manualOrderAmount, setManualOrderAmount] =
|
|
11641
|
-
const [ownedTokens, setOwnedTokens] =
|
|
11642
|
-
const [displayedOwnedTokens, setDisplayedOwnedTokens] =
|
|
11643
|
-
const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] =
|
|
11644
|
-
const [lastOrderQuantity, setLastOrderQuantity] =
|
|
11645
|
-
const [orderPendingAllocation, setOrderPendingAllocation] =
|
|
11646
|
-
const [orderPlacedSuccess, setOrderPlacedSuccess] =
|
|
11647
|
-
const [lastOrderDetails, setLastOrderDetails] =
|
|
11648
|
-
const [showOrderConfirmModal, setShowOrderConfirmModal] =
|
|
11649
|
-
const [, setLiveNewsIndex] =
|
|
11650
|
-
const [newsItems, setNewsItems] =
|
|
12011
|
+
const [sliderValue, setSliderValue] = React9.useState(0);
|
|
12012
|
+
const [availableBalance, setAvailableBalance] = React9.useState(walletUsdcBalance ?? 0);
|
|
12013
|
+
const [manualOrderAmount, setManualOrderAmount] = React9.useState(null);
|
|
12014
|
+
const [ownedTokens, setOwnedTokens] = React9.useState(0);
|
|
12015
|
+
const [displayedOwnedTokens, setDisplayedOwnedTokens] = React9.useState(0);
|
|
12016
|
+
const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React9.useState(false);
|
|
12017
|
+
const [lastOrderQuantity, setLastOrderQuantity] = React9.useState(0);
|
|
12018
|
+
const [orderPendingAllocation, setOrderPendingAllocation] = React9.useState(false);
|
|
12019
|
+
const [orderPlacedSuccess, setOrderPlacedSuccess] = React9.useState(false);
|
|
12020
|
+
const [lastOrderDetails, setLastOrderDetails] = React9.useState(null);
|
|
12021
|
+
const [showOrderConfirmModal, setShowOrderConfirmModal] = React9.useState(false);
|
|
12022
|
+
const [, setLiveNewsIndex] = React9.useState(0);
|
|
12023
|
+
const [newsItems, setNewsItems] = React9.useState(
|
|
11651
12024
|
() => allNewsItems.slice(0, 4).map((item, index) => ({
|
|
11652
12025
|
...item,
|
|
11653
12026
|
displayId: `${item.id}-initial-${index}`,
|
|
@@ -11663,6 +12036,7 @@ function PropertyBuy({
|
|
|
11663
12036
|
const offeringValuation = saleData?.offeringValuation ?? tokenPrice * supplyToSell;
|
|
11664
12037
|
const ipoStatus = saleData?.status ?? "PENDING";
|
|
11665
12038
|
const ipoStarted = ipoStatus === "LIVE" || isPrivateClient && ipoStatus === "PENDING";
|
|
12039
|
+
const ipoEnded = ipoStatus === "CLOSED" || ipoStatus === "CANCELLED";
|
|
11666
12040
|
const statusLabel = ipoStatus;
|
|
11667
12041
|
const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
|
|
11668
12042
|
const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
|
|
@@ -11673,12 +12047,12 @@ function PropertyBuy({
|
|
|
11673
12047
|
const orderTotal = tokenQuantity * tokenPrice + feeInUsd;
|
|
11674
12048
|
const estExposure = (tokenQuantity / supplyToSell * 100).toFixed(4);
|
|
11675
12049
|
const hasInsufficientFunds = orderTotal > availableBalance;
|
|
11676
|
-
|
|
12050
|
+
React9.useEffect(() => {
|
|
11677
12051
|
if (walletUsdcBalance != null) {
|
|
11678
12052
|
setAvailableBalance(walletUsdcBalance);
|
|
11679
12053
|
}
|
|
11680
12054
|
}, [walletUsdcBalance]);
|
|
11681
|
-
|
|
12055
|
+
React9.useEffect(() => {
|
|
11682
12056
|
if (walletPropertyTokenBalance != null) {
|
|
11683
12057
|
setOwnedTokens(walletPropertyTokenBalance);
|
|
11684
12058
|
setDisplayedOwnedTokens(walletPropertyTokenBalance);
|
|
@@ -11690,13 +12064,13 @@ function PropertyBuy({
|
|
|
11690
12064
|
}
|
|
11691
12065
|
setShowOrderConfirmModal(true);
|
|
11692
12066
|
};
|
|
11693
|
-
|
|
12067
|
+
React9.useEffect(() => {
|
|
11694
12068
|
if (purchaseStatus === "success" && orderPendingAllocation) {
|
|
11695
12069
|
setOrderPendingAllocation(false);
|
|
11696
12070
|
setOrderPlacedSuccess(true);
|
|
11697
12071
|
}
|
|
11698
12072
|
}, [purchaseStatus, orderPendingAllocation]);
|
|
11699
|
-
const handlePlaceAnotherOrder =
|
|
12073
|
+
const handlePlaceAnotherOrder = React9.useCallback(() => {
|
|
11700
12074
|
setOrderPlacedSuccess(false);
|
|
11701
12075
|
setOrderPendingAllocation(false);
|
|
11702
12076
|
}, []);
|
|
@@ -11753,7 +12127,7 @@ function PropertyBuy({
|
|
|
11753
12127
|
setSliderValue(0);
|
|
11754
12128
|
setManualOrderAmount(null);
|
|
11755
12129
|
};
|
|
11756
|
-
|
|
12130
|
+
React9.useEffect(() => {
|
|
11757
12131
|
const newsInterval = setInterval(() => {
|
|
11758
12132
|
setLiveNewsIndex((prev) => {
|
|
11759
12133
|
const nextIndex = (prev + 1) % allNewsItems.length;
|
|
@@ -11813,6 +12187,8 @@ function PropertyBuy({
|
|
|
11813
12187
|
VideoActivitySection,
|
|
11814
12188
|
{
|
|
11815
12189
|
ipoStarted,
|
|
12190
|
+
ipoEnded,
|
|
12191
|
+
isLoading: isLoadingActivity,
|
|
11816
12192
|
recentOrders,
|
|
11817
12193
|
ordersAllocated,
|
|
11818
12194
|
tokenPrice
|
|
@@ -12047,7 +12423,7 @@ function PaymentPopup({
|
|
|
12047
12423
|
userTokenHoldings,
|
|
12048
12424
|
propertyName
|
|
12049
12425
|
}) {
|
|
12050
|
-
const [selectedPaymentMethod, setSelectedPaymentMethod] =
|
|
12426
|
+
const [selectedPaymentMethod, setSelectedPaymentMethod] = React9.useState(
|
|
12051
12427
|
"tokens"
|
|
12052
12428
|
);
|
|
12053
12429
|
if (!isOpen) return null;
|
|
@@ -12226,20 +12602,20 @@ function PaymentPopup({
|
|
|
12226
12602
|
var payment_popup_default = PaymentPopup;
|
|
12227
12603
|
var SUMMER_MONTHS = /* @__PURE__ */ new Set([11, 0, 1]);
|
|
12228
12604
|
var OwnerBooking = ({ propertyName, token }) => {
|
|
12229
|
-
const today =
|
|
12605
|
+
const today = React9.useMemo(() => {
|
|
12230
12606
|
const base = /* @__PURE__ */ new Date();
|
|
12231
12607
|
base.setHours(0, 0, 0, 0);
|
|
12232
12608
|
return base;
|
|
12233
12609
|
}, []);
|
|
12234
|
-
const [currentYear, setCurrentYear] =
|
|
12235
|
-
const [currentMonth, setCurrentMonth] =
|
|
12236
|
-
const [dateRanges, setDateRanges] =
|
|
12237
|
-
const [selectedDates, setSelectedDates] =
|
|
12238
|
-
const [hoverDate, setHoverDate] =
|
|
12239
|
-
const [isDateSelectorOpen, setIsDateSelectorOpen] =
|
|
12240
|
-
const [selectorYear, setSelectorYear] =
|
|
12241
|
-
const [isPaymentPopupOpen, setIsPaymentPopupOpen] =
|
|
12242
|
-
const dateSelectorRef =
|
|
12610
|
+
const [currentYear, setCurrentYear] = React9.useState(today.getFullYear());
|
|
12611
|
+
const [currentMonth, setCurrentMonth] = React9.useState(today.getMonth());
|
|
12612
|
+
const [dateRanges, setDateRanges] = React9.useState([]);
|
|
12613
|
+
const [selectedDates, setSelectedDates] = React9.useState([]);
|
|
12614
|
+
const [hoverDate, setHoverDate] = React9.useState(null);
|
|
12615
|
+
const [isDateSelectorOpen, setIsDateSelectorOpen] = React9.useState(false);
|
|
12616
|
+
const [selectorYear, setSelectorYear] = React9.useState(today.getFullYear());
|
|
12617
|
+
const [isPaymentPopupOpen, setIsPaymentPopupOpen] = React9.useState(false);
|
|
12618
|
+
const dateSelectorRef = React9.useRef(null);
|
|
12243
12619
|
const tokenPrice = token.price ?? 700;
|
|
12244
12620
|
const userTokenHoldings = 2.2;
|
|
12245
12621
|
const MIN_NIGHTS = 3;
|
|
@@ -12249,25 +12625,25 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12249
12625
|
{ bg: "rgba(230, 126, 34, 0.25)", border: "rgba(230, 126, 34, 0.6)" },
|
|
12250
12626
|
{ bg: "rgba(46, 204, 113, 0.25)", border: "rgba(46, 204, 113, 0.6)" }
|
|
12251
12627
|
];
|
|
12252
|
-
const calculateTokensPerDayOwner =
|
|
12628
|
+
const calculateTokensPerDayOwner = React9.useCallback(() => {
|
|
12253
12629
|
if (tokenPrice <= 0) return 0;
|
|
12254
12630
|
const target = 650;
|
|
12255
12631
|
const raw = target / tokenPrice;
|
|
12256
12632
|
return Math.ceil(raw * 1e4) / 1e4;
|
|
12257
12633
|
}, [tokenPrice]);
|
|
12258
|
-
const calculateTokensPerDayMarket =
|
|
12634
|
+
const calculateTokensPerDayMarket = React9.useCallback(() => {
|
|
12259
12635
|
if (tokenPrice <= 0) return 0;
|
|
12260
12636
|
const target = 900;
|
|
12261
12637
|
const raw = target / tokenPrice;
|
|
12262
12638
|
return Math.ceil(raw * 1e4) / 1e4;
|
|
12263
12639
|
}, [tokenPrice]);
|
|
12264
12640
|
const qualifiesForOwnerRate = userTokenHoldings >= 0.1;
|
|
12265
|
-
const getTokensPerDay =
|
|
12641
|
+
const getTokensPerDay = React9.useCallback(
|
|
12266
12642
|
() => calculateTokensPerDayOwner() ,
|
|
12267
12643
|
[qualifiesForOwnerRate, calculateTokensPerDayOwner, calculateTokensPerDayMarket]
|
|
12268
12644
|
);
|
|
12269
12645
|
const getRateLabel = () => "Owner's Rate" ;
|
|
12270
|
-
const selectionStats =
|
|
12646
|
+
const selectionStats = React9.useMemo(() => {
|
|
12271
12647
|
if (selectedDates.length !== 2) return null;
|
|
12272
12648
|
const [a, b] = selectedDates;
|
|
12273
12649
|
const start = a < b ? a : b;
|
|
@@ -12278,10 +12654,10 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12278
12654
|
const usd = tokens * tokenPrice;
|
|
12279
12655
|
return { nights, tokensPerDay, tokens, usd, start, end };
|
|
12280
12656
|
}, [selectedDates, getTokensPerDay, tokenPrice]);
|
|
12281
|
-
const totalNights =
|
|
12282
|
-
const totalTokens =
|
|
12657
|
+
const totalNights = React9.useMemo(() => dateRanges.reduce((sum, r) => sum + r.nights, 0), [dateRanges]);
|
|
12658
|
+
const totalTokens = React9.useMemo(() => dateRanges.reduce((sum, r) => sum + r.tokens, 0), [dateRanges]);
|
|
12283
12659
|
const totalUSD = totalTokens * tokenPrice;
|
|
12284
|
-
const generateCalendarDays =
|
|
12660
|
+
const generateCalendarDays = React9.useCallback(
|
|
12285
12661
|
(year, month) => {
|
|
12286
12662
|
const first = new Date(year, month, 1);
|
|
12287
12663
|
const last = new Date(year, month + 1, 0);
|
|
@@ -12310,11 +12686,11 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12310
12686
|
},
|
|
12311
12687
|
[today]
|
|
12312
12688
|
);
|
|
12313
|
-
const calendarDays =
|
|
12689
|
+
const calendarDays = React9.useMemo(
|
|
12314
12690
|
() => generateCalendarDays(currentYear, currentMonth),
|
|
12315
12691
|
[currentYear, currentMonth, generateCalendarDays]
|
|
12316
12692
|
);
|
|
12317
|
-
const isDateReserved =
|
|
12693
|
+
const isDateReserved = React9.useCallback(
|
|
12318
12694
|
(date) => dateRanges.some((r) => date >= r.arrival && date <= r.departure),
|
|
12319
12695
|
[dateRanges]
|
|
12320
12696
|
);
|
|
@@ -12408,14 +12784,14 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12408
12784
|
"December"
|
|
12409
12785
|
];
|
|
12410
12786
|
const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
12411
|
-
const setMonthYear =
|
|
12787
|
+
const setMonthYear = React9.useCallback(
|
|
12412
12788
|
(month, year) => {
|
|
12413
12789
|
setCurrentMonth(month);
|
|
12414
12790
|
setCurrentYear(year);
|
|
12415
12791
|
},
|
|
12416
12792
|
[setCurrentMonth, setCurrentYear]
|
|
12417
12793
|
);
|
|
12418
|
-
const shiftMonth =
|
|
12794
|
+
const shiftMonth = React9.useCallback(
|
|
12419
12795
|
(direction) => {
|
|
12420
12796
|
const delta = direction === "prev" ? -1 : 1;
|
|
12421
12797
|
let newMonth = currentMonth + delta;
|
|
@@ -12432,7 +12808,7 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12432
12808
|
},
|
|
12433
12809
|
[currentMonth, currentYear, setMonthYear]
|
|
12434
12810
|
);
|
|
12435
|
-
const jumpToNextAvailable =
|
|
12811
|
+
const jumpToNextAvailable = React9.useCallback(() => {
|
|
12436
12812
|
for (let offset = 1; offset <= 12; offset++) {
|
|
12437
12813
|
const candidateMonth = (currentMonth + offset) % 12;
|
|
12438
12814
|
if (!SUMMER_MONTHS.has(candidateMonth)) continue;
|
|
@@ -12449,7 +12825,7 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12449
12825
|
setMonthYear(month, selectorYear);
|
|
12450
12826
|
setIsDateSelectorOpen(false);
|
|
12451
12827
|
};
|
|
12452
|
-
|
|
12828
|
+
React9.useEffect(() => {
|
|
12453
12829
|
const handleClickOutside = (event) => {
|
|
12454
12830
|
if (dateSelectorRef.current && !dateSelectorRef.current.contains(event.target)) {
|
|
12455
12831
|
setIsDateSelectorOpen(false);
|
|
@@ -12893,21 +13269,21 @@ function PropertyValuation({
|
|
|
12893
13269
|
loading = false,
|
|
12894
13270
|
error = null
|
|
12895
13271
|
}) {
|
|
12896
|
-
const now =
|
|
12897
|
-
const lastPrice =
|
|
13272
|
+
const now = React9.useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
13273
|
+
const lastPrice = React9.useMemo(() => {
|
|
12898
13274
|
const fallback = Number.isFinite(tokenPrice) && tokenPrice > 0 ? tokenPrice : 0;
|
|
12899
13275
|
if (!summary?.lastPrice || summary.lastPrice <= 0) {
|
|
12900
13276
|
return fallback;
|
|
12901
13277
|
}
|
|
12902
13278
|
return summary.lastPrice;
|
|
12903
13279
|
}, [summary, tokenPrice]);
|
|
12904
|
-
const fairValue =
|
|
13280
|
+
const fairValue = React9.useMemo(() => {
|
|
12905
13281
|
if (summary?.fairValue && summary.fairValue > 0) {
|
|
12906
13282
|
return summary.fairValue;
|
|
12907
13283
|
}
|
|
12908
13284
|
return lastPrice || 1;
|
|
12909
13285
|
}, [summary, lastPrice]);
|
|
12910
|
-
const tokensOutstanding =
|
|
13286
|
+
const tokensOutstanding = React9.useMemo(() => {
|
|
12911
13287
|
if (summary?.totalTokens && summary.totalTokens > 0) {
|
|
12912
13288
|
return summary.totalTokens;
|
|
12913
13289
|
}
|
|
@@ -12922,8 +13298,8 @@ function PropertyValuation({
|
|
|
12922
13298
|
const valuationStatus = summary?.valuationStatus ?? (lastPrice < fairValue ? "Undervalued" : lastPrice > fairValue ? "Overvalued" : "Fair Value");
|
|
12923
13299
|
const valuationDelta = summary?.valuationDeltaPercent ?? (lastPrice - fairValue) / fairValue * 100;
|
|
12924
13300
|
const valuationDeltaFormatted = `${valuationDelta >= 0 ? "+" : ""}${valuationDelta.toFixed(1)}%`;
|
|
12925
|
-
const { valuationPath, fairValuePath, axisLabels } =
|
|
12926
|
-
const recentSales =
|
|
13301
|
+
const { valuationPath, fairValuePath, axisLabels } = React9.useMemo(() => buildChartPaths(history, fairValue), [history, fairValue]);
|
|
13302
|
+
const recentSales = React9.useMemo(() => {
|
|
12927
13303
|
if (summary?.recentSales?.length) {
|
|
12928
13304
|
return summary.recentSales;
|
|
12929
13305
|
}
|
|
@@ -14075,19 +14451,19 @@ function PropertyPhotoGallery({
|
|
|
14075
14451
|
);
|
|
14076
14452
|
}
|
|
14077
14453
|
function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose }) {
|
|
14078
|
-
const [currentIndex, setCurrentIndex] =
|
|
14079
|
-
const [activeHotspotId, setActiveHotspotId] =
|
|
14080
|
-
const sliderRef =
|
|
14081
|
-
const [isDragging, setIsDragging] =
|
|
14082
|
-
const wasDraggingRef =
|
|
14083
|
-
const touchStartX =
|
|
14084
|
-
const touchStartY =
|
|
14085
|
-
const isSwiping =
|
|
14086
|
-
const progress =
|
|
14454
|
+
const [currentIndex, setCurrentIndex] = React9.useState(() => clampIndex(startIndex, galleryImages.length));
|
|
14455
|
+
const [activeHotspotId, setActiveHotspotId] = React9.useState(null);
|
|
14456
|
+
const sliderRef = React9.useRef(null);
|
|
14457
|
+
const [isDragging, setIsDragging] = React9.useState(false);
|
|
14458
|
+
const wasDraggingRef = React9.useRef(false);
|
|
14459
|
+
const touchStartX = React9.useRef(null);
|
|
14460
|
+
const touchStartY = React9.useRef(null);
|
|
14461
|
+
const isSwiping = React9.useRef(false);
|
|
14462
|
+
const progress = React9.useMemo(() => {
|
|
14087
14463
|
if (galleryImages.length <= 1) return 0;
|
|
14088
14464
|
return currentIndex / (galleryImages.length - 1) * 100;
|
|
14089
14465
|
}, [currentIndex, galleryImages.length]);
|
|
14090
|
-
|
|
14466
|
+
React9.useEffect(() => {
|
|
14091
14467
|
document.body.style.overflow = "hidden";
|
|
14092
14468
|
document.body.style.touchAction = "none";
|
|
14093
14469
|
return () => {
|
|
@@ -14095,7 +14471,7 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
|
|
|
14095
14471
|
document.body.style.touchAction = "";
|
|
14096
14472
|
};
|
|
14097
14473
|
}, []);
|
|
14098
|
-
|
|
14474
|
+
React9.useEffect(() => {
|
|
14099
14475
|
const handleKey = (event) => {
|
|
14100
14476
|
if (event.key === "Escape") onClose();
|
|
14101
14477
|
if (event.key === "ArrowLeft") setCurrentIndex((i) => i === 0 ? galleryImages.length - 1 : i - 1);
|
|
@@ -14368,13 +14744,13 @@ function truncateHash(hash) {
|
|
|
14368
14744
|
return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
|
|
14369
14745
|
}
|
|
14370
14746
|
function ToastItem({ toast, onDismiss }) {
|
|
14371
|
-
const [exiting, setExiting] =
|
|
14372
|
-
const timerRef =
|
|
14373
|
-
const dismiss =
|
|
14747
|
+
const [exiting, setExiting] = React9.useState(false);
|
|
14748
|
+
const timerRef = React9.useRef(null);
|
|
14749
|
+
const dismiss = React9.useCallback(() => {
|
|
14374
14750
|
setExiting(true);
|
|
14375
14751
|
setTimeout(() => onDismiss(toast.id), 280);
|
|
14376
14752
|
}, [onDismiss, toast.id]);
|
|
14377
|
-
|
|
14753
|
+
React9.useEffect(() => {
|
|
14378
14754
|
const duration2 = toast.duration ?? 6e3;
|
|
14379
14755
|
if (duration2 > 0) {
|
|
14380
14756
|
timerRef.current = setTimeout(dismiss, duration2);
|
|
@@ -14403,15 +14779,15 @@ function ToastItem({ toast, onDismiss }) {
|
|
|
14403
14779
|
duration > 0 && /* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { $color: accent, $duration: duration })
|
|
14404
14780
|
] });
|
|
14405
14781
|
}
|
|
14406
|
-
var ToastContext =
|
|
14782
|
+
var ToastContext = React9.createContext(null);
|
|
14407
14783
|
function ToastProvider({ children }) {
|
|
14408
|
-
const [toasts, setToasts] =
|
|
14409
|
-
const addToast =
|
|
14784
|
+
const [toasts, setToasts] = React9.useState([]);
|
|
14785
|
+
const addToast = React9.useCallback((data) => {
|
|
14410
14786
|
const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
14411
14787
|
setToasts((prev) => [...prev, { ...data, id }]);
|
|
14412
14788
|
return id;
|
|
14413
14789
|
}, []);
|
|
14414
|
-
const dismiss =
|
|
14790
|
+
const dismiss = React9.useCallback((id) => {
|
|
14415
14791
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
14416
14792
|
}, []);
|
|
14417
14793
|
return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
|
|
@@ -14420,10 +14796,71 @@ function ToastProvider({ children }) {
|
|
|
14420
14796
|
] });
|
|
14421
14797
|
}
|
|
14422
14798
|
function useToast() {
|
|
14423
|
-
const ctx =
|
|
14799
|
+
const ctx = React9.useContext(ToastContext);
|
|
14424
14800
|
if (!ctx) throw new Error("useToast must be used within a ToastProvider");
|
|
14425
14801
|
return ctx;
|
|
14426
14802
|
}
|
|
14803
|
+
var INTERVALS = [1e3, 2e3, 4e3, 5e3, 7e3, 1e4, 12e3];
|
|
14804
|
+
function useAdaptivePolling({ enabled, onPoll }) {
|
|
14805
|
+
const onPollRef = React9.useRef(onPoll);
|
|
14806
|
+
onPollRef.current = onPoll;
|
|
14807
|
+
React9.useEffect(() => {
|
|
14808
|
+
if (!enabled) return;
|
|
14809
|
+
let cancelled = false;
|
|
14810
|
+
let timeoutId = null;
|
|
14811
|
+
let step = 0;
|
|
14812
|
+
const clear = () => {
|
|
14813
|
+
if (timeoutId) {
|
|
14814
|
+
clearTimeout(timeoutId);
|
|
14815
|
+
timeoutId = null;
|
|
14816
|
+
}
|
|
14817
|
+
};
|
|
14818
|
+
const isHidden = () => typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
14819
|
+
const tick = async () => {
|
|
14820
|
+
if (cancelled) return;
|
|
14821
|
+
if (isHidden()) {
|
|
14822
|
+
return;
|
|
14823
|
+
}
|
|
14824
|
+
try {
|
|
14825
|
+
await onPollRef.current();
|
|
14826
|
+
} catch {
|
|
14827
|
+
}
|
|
14828
|
+
if (cancelled) return;
|
|
14829
|
+
step = Math.min(step + 1, INTERVALS.length - 1);
|
|
14830
|
+
timeoutId = setTimeout(tick, INTERVALS[step]);
|
|
14831
|
+
};
|
|
14832
|
+
const onVisibility = () => {
|
|
14833
|
+
if (document.visibilityState === "visible") {
|
|
14834
|
+
step = 0;
|
|
14835
|
+
clear();
|
|
14836
|
+
timeoutId = setTimeout(tick, 0);
|
|
14837
|
+
}
|
|
14838
|
+
};
|
|
14839
|
+
if (typeof document !== "undefined") {
|
|
14840
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
14841
|
+
}
|
|
14842
|
+
timeoutId = setTimeout(tick, INTERVALS[0]);
|
|
14843
|
+
return () => {
|
|
14844
|
+
cancelled = true;
|
|
14845
|
+
clear();
|
|
14846
|
+
if (typeof document !== "undefined") {
|
|
14847
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
14848
|
+
}
|
|
14849
|
+
};
|
|
14850
|
+
}, [enabled]);
|
|
14851
|
+
}
|
|
14852
|
+
function hasPendingActivity(data) {
|
|
14853
|
+
if (!data) return false;
|
|
14854
|
+
const openPending = data.openOrders?.some((o) => {
|
|
14855
|
+
const s = o.status.toUpperCase();
|
|
14856
|
+
return s === "OPEN" || s === "PARTIALLY_FILLED";
|
|
14857
|
+
}) ?? false;
|
|
14858
|
+
if (openPending) return true;
|
|
14859
|
+
return data.offeringOrders?.some((o) => {
|
|
14860
|
+
const s = o.status.toUpperCase();
|
|
14861
|
+
return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
|
|
14862
|
+
}) ?? false;
|
|
14863
|
+
}
|
|
14427
14864
|
|
|
14428
14865
|
exports.AssetSelectorBar = AssetSelectorBar;
|
|
14429
14866
|
exports.Badge = Badge;
|
|
@@ -14460,12 +14897,15 @@ exports.PropertyPhotoGallery = PropertyPhotoGallery;
|
|
|
14460
14897
|
exports.PropertySubheader = PropertySubheader;
|
|
14461
14898
|
exports.PropertyTour = PropertyTour;
|
|
14462
14899
|
exports.PropertyValuation = PropertyValuation;
|
|
14900
|
+
exports.Skeleton = Skeleton;
|
|
14463
14901
|
exports.ToastProvider = ToastProvider;
|
|
14464
14902
|
exports.TradeConfirmationModal = TradeConfirmationModal;
|
|
14465
14903
|
exports.TradingSlider = TradingSlider;
|
|
14466
14904
|
exports.YourOrders = YourOrders;
|
|
14467
14905
|
exports.badgeVariants = badgeVariants;
|
|
14468
14906
|
exports.buttonVariants = buttonVariants;
|
|
14907
|
+
exports.hasPendingActivity = hasPendingActivity;
|
|
14908
|
+
exports.useAdaptivePolling = useAdaptivePolling;
|
|
14469
14909
|
exports.useToast = useToast;
|
|
14470
14910
|
//# sourceMappingURL=index.js.map
|
|
14471
14911
|
//# sourceMappingURL=index.js.map
|