@loafmarkets/ui 0.1.41 → 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 +804 -353
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +687 -239
- 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
|
}, []);
|
|
@@ -4877,7 +5140,7 @@ var Header = ({
|
|
|
4877
5140
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4878
5141
|
/* @__PURE__ */ jsxRuntime.jsx(SafeAreaCover, {}),
|
|
4879
5142
|
/* @__PURE__ */ jsxRuntime.jsx(Overlay, { $isOpen: isMobileMenuOpen, onClick: () => setIsMobileMenuOpen(false) }),
|
|
4880
|
-
/* @__PURE__ */ jsxRuntime.jsxs(HeaderContainer, { children: [
|
|
5143
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HeaderContainer, { id: "loaf-header", children: [
|
|
4881
5144
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
|
|
4882
5145
|
/* @__PURE__ */ jsxRuntime.jsxs(Logo, { children: [
|
|
4883
5146
|
/* @__PURE__ */ jsxRuntime.jsx(LogoLink, { href: logoHref ?? resolvedHomePath, onClick: handleLogoNavigation, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: Loaf_logo_Banner_default, alt: "LOAF Logo" }) }),
|
|
@@ -5115,6 +5378,7 @@ var Header = ({
|
|
|
5115
5378
|
)
|
|
5116
5379
|
] })
|
|
5117
5380
|
] }),
|
|
5381
|
+
/* @__PURE__ */ jsxRuntime.jsx(HeaderSpacer, {}),
|
|
5118
5382
|
LoginPopupComponent && showLoginPopup && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5119
5383
|
LoginPopupComponent,
|
|
5120
5384
|
{
|
|
@@ -5130,8 +5394,8 @@ var SafeAreaCover = styled24__default.default.div`
|
|
|
5130
5394
|
top: 0;
|
|
5131
5395
|
left: 0;
|
|
5132
5396
|
right: 0;
|
|
5133
|
-
height: env(safe-area-inset-top, 0px);
|
|
5134
|
-
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));
|
|
5135
5399
|
background-color: #0d1117;
|
|
5136
5400
|
z-index: 1001;
|
|
5137
5401
|
pointer-events: none;
|
|
@@ -5185,23 +5449,31 @@ var HeaderContainer = styled24__default.default.header`
|
|
|
5185
5449
|
/* Split padding so browsers that don't support env() inside shorthand
|
|
5186
5450
|
still get the horizontal padding — only the top falls back to 0 */
|
|
5187
5451
|
padding: 0 2rem;
|
|
5188
|
-
padding-top: env(safe-area-inset-top, 0px);
|
|
5452
|
+
padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5189
5453
|
background-color: #0d1117;
|
|
5190
5454
|
border-bottom: 1px solid #232a32;
|
|
5191
|
-
position:
|
|
5455
|
+
position: fixed;
|
|
5192
5456
|
top: 0;
|
|
5457
|
+
left: 0;
|
|
5458
|
+
right: 0;
|
|
5193
5459
|
z-index: 1000;
|
|
5194
5460
|
width: 100%;
|
|
5195
5461
|
/* Fallback min-height for browsers that can't evaluate calc+env */
|
|
5196
5462
|
min-height: 56px;
|
|
5197
|
-
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)));
|
|
5198
5464
|
box-sizing: border-box;
|
|
5199
5465
|
|
|
5200
5466
|
@media (max-width: 768px) {
|
|
5201
5467
|
padding: 0 1rem;
|
|
5202
|
-
padding-top: env(safe-area-inset-top, 0px);
|
|
5468
|
+
padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5203
5469
|
}
|
|
5204
5470
|
`;
|
|
5471
|
+
var HeaderSpacer = styled24__default.default.div`
|
|
5472
|
+
width: 100%;
|
|
5473
|
+
min-height: 56px;
|
|
5474
|
+
min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5475
|
+
flex-shrink: 0;
|
|
5476
|
+
`;
|
|
5205
5477
|
var Logo = styled24__default.default.div`
|
|
5206
5478
|
display: flex;
|
|
5207
5479
|
align-items: center;
|
|
@@ -5254,10 +5526,12 @@ var Nav = styled24__default.default.nav`
|
|
|
5254
5526
|
@media (max-width: 1300px) {
|
|
5255
5527
|
position: fixed;
|
|
5256
5528
|
top: 56px;
|
|
5529
|
+
top: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5257
5530
|
right: ${(props) => props.$isOpen ? "0" : "-100%"} ;
|
|
5258
5531
|
width: 280px;
|
|
5259
5532
|
max-width: 280px;
|
|
5260
5533
|
height: calc(100vh - 56px);
|
|
5534
|
+
height: calc(100vh - 56px - max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5261
5535
|
background: linear-gradient(180deg, #0f1419 0%, #0a0e13 100%);
|
|
5262
5536
|
z-index: 1000;
|
|
5263
5537
|
transition: right 0.3s ease;
|
|
@@ -5530,10 +5804,10 @@ var MobileNavItem = styled24__default.default.div`
|
|
|
5530
5804
|
padding-left: 24px;
|
|
5531
5805
|
}
|
|
5532
5806
|
`;
|
|
5533
|
-
var PropertySubheader =
|
|
5807
|
+
var PropertySubheader = React9__namespace.forwardRef(
|
|
5534
5808
|
({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
|
|
5535
|
-
const tabsContainerRef =
|
|
5536
|
-
|
|
5809
|
+
const tabsContainerRef = React9__namespace.useRef(null);
|
|
5810
|
+
React9__namespace.useEffect(() => {
|
|
5537
5811
|
const container = tabsContainerRef.current;
|
|
5538
5812
|
if (!container) return;
|
|
5539
5813
|
const isMobile = window.innerWidth <= 768;
|
|
@@ -5675,27 +5949,27 @@ var LoginPopup = ({
|
|
|
5675
5949
|
onFundWallet,
|
|
5676
5950
|
initialView
|
|
5677
5951
|
}) => {
|
|
5678
|
-
const [view, setView] =
|
|
5679
|
-
const [email, setEmail] =
|
|
5680
|
-
const [handle, setHandle] =
|
|
5681
|
-
const [otp, setOtp] =
|
|
5682
|
-
const [error, setError] =
|
|
5683
|
-
const [loading, setLoading] =
|
|
5684
|
-
const [isSignUp, setIsSignUp] =
|
|
5685
|
-
const [fundingAmount] =
|
|
5686
|
-
const [kycLoading, setKycLoading] =
|
|
5687
|
-
const [showKycWidget, setShowKycWidget] =
|
|
5688
|
-
const [cryptoFundingLoading, setCryptoFundingLoading] =
|
|
5689
|
-
const [fiatFundingLoading, setFiatFundingLoading] =
|
|
5690
|
-
const [fundingError, setFundingError] =
|
|
5691
|
-
const [transakWidgetUrl, setTransakWidgetUrl] =
|
|
5692
|
-
const suppressAutoCloseRef =
|
|
5693
|
-
|
|
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(() => {
|
|
5694
5968
|
if (typeof initialView === "string") {
|
|
5695
5969
|
setView(initialView);
|
|
5696
5970
|
}
|
|
5697
5971
|
}, [initialView]);
|
|
5698
|
-
|
|
5972
|
+
React9.useEffect(() => {
|
|
5699
5973
|
if (!transakWidgetUrl) return;
|
|
5700
5974
|
const handleTransakMessage = (event) => {
|
|
5701
5975
|
if (!event.origin.includes("transak.com") && !event.origin.includes("global.transak.com")) {
|
|
@@ -5720,7 +5994,7 @@ var LoginPopup = ({
|
|
|
5720
5994
|
window.addEventListener("message", handleTransakMessage);
|
|
5721
5995
|
return () => window.removeEventListener("message", handleTransakMessage);
|
|
5722
5996
|
}, [transakWidgetUrl, onClose]);
|
|
5723
|
-
|
|
5997
|
+
React9.useEffect(() => {
|
|
5724
5998
|
if (!autoCloseOnAuth) {
|
|
5725
5999
|
return;
|
|
5726
6000
|
}
|
|
@@ -6692,8 +6966,8 @@ var TransakIframe = styled24__default.default.iframe`
|
|
|
6692
6966
|
border-radius: var(--border-radius, 12px);
|
|
6693
6967
|
`;
|
|
6694
6968
|
var MiniLiveFeed = () => {
|
|
6695
|
-
const [purchases, setPurchases] =
|
|
6696
|
-
|
|
6969
|
+
const [purchases, setPurchases] = React9.useState([]);
|
|
6970
|
+
React9.useEffect(() => {
|
|
6697
6971
|
const handles = [
|
|
6698
6972
|
"Landlord",
|
|
6699
6973
|
"PropertyKing",
|
|
@@ -6869,7 +7143,7 @@ var MiniLiveFeed = () => {
|
|
|
6869
7143
|
);
|
|
6870
7144
|
};
|
|
6871
7145
|
LoginPopup.displayName = "LoginPopup";
|
|
6872
|
-
var PropertyCompareBar =
|
|
7146
|
+
var PropertyCompareBar = React9__namespace.forwardRef(
|
|
6873
7147
|
({
|
|
6874
7148
|
className,
|
|
6875
7149
|
addresses,
|
|
@@ -6880,7 +7154,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
6880
7154
|
price,
|
|
6881
7155
|
...props
|
|
6882
7156
|
}, ref) => {
|
|
6883
|
-
const normalizedAddresses =
|
|
7157
|
+
const normalizedAddresses = React9__namespace.useMemo(() => {
|
|
6884
7158
|
return addresses.map(
|
|
6885
7159
|
(option) => typeof option === "string" ? { id: option, label: option } : option
|
|
6886
7160
|
);
|
|
@@ -6888,11 +7162,11 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
6888
7162
|
const hasAddresses = normalizedAddresses.length > 0;
|
|
6889
7163
|
const firstAddressId = normalizedAddresses[0]?.id;
|
|
6890
7164
|
const isControlled = selectedAddressId !== void 0;
|
|
6891
|
-
const [internalSelectedId, setInternalSelectedId] =
|
|
7165
|
+
const [internalSelectedId, setInternalSelectedId] = React9__namespace.useState(
|
|
6892
7166
|
() => isControlled ? void 0 : firstAddressId
|
|
6893
7167
|
);
|
|
6894
7168
|
const resolvedSelectedId = isControlled ? selectedAddressId : internalSelectedId;
|
|
6895
|
-
|
|
7169
|
+
React9__namespace.useEffect(() => {
|
|
6896
7170
|
if (!isControlled) {
|
|
6897
7171
|
setInternalSelectedId((current) => {
|
|
6898
7172
|
if (current != null && normalizedAddresses.some((option) => option.id === current)) {
|
|
@@ -6903,9 +7177,9 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
6903
7177
|
}
|
|
6904
7178
|
}, [firstAddressId, isControlled, normalizedAddresses]);
|
|
6905
7179
|
const selectedOption = normalizedAddresses.find((option) => option.id === resolvedSelectedId) ?? normalizedAddresses[0];
|
|
6906
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
6907
|
-
const dropdownRef =
|
|
6908
|
-
|
|
7180
|
+
const [isDropdownOpen, setIsDropdownOpen] = React9__namespace.useState(false);
|
|
7181
|
+
const dropdownRef = React9__namespace.useRef(null);
|
|
7182
|
+
React9__namespace.useEffect(() => {
|
|
6909
7183
|
if (!isDropdownOpen) return;
|
|
6910
7184
|
const handleClick = (event) => {
|
|
6911
7185
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
@@ -7308,11 +7582,11 @@ function GalleryMapSection({
|
|
|
7308
7582
|
autoPlay = true,
|
|
7309
7583
|
autoPlayInterval = 4e3
|
|
7310
7584
|
}) {
|
|
7311
|
-
const [carouselIndex, setCarouselIndex] =
|
|
7312
|
-
const [showVideo, setShowVideo] =
|
|
7313
|
-
const [autoPlaying, setAutoPlaying] =
|
|
7585
|
+
const [carouselIndex, setCarouselIndex] = React9.useState(0);
|
|
7586
|
+
const [showVideo, setShowVideo] = React9.useState(false);
|
|
7587
|
+
const [autoPlaying, setAutoPlaying] = React9.useState(autoPlay);
|
|
7314
7588
|
const resolvedMapUrl = mapUrl ?? (tokenName ? `/map/${tokenName}?embed=true&zoom=14&hideOthers=true` : "about:blank");
|
|
7315
|
-
|
|
7589
|
+
React9.useEffect(() => {
|
|
7316
7590
|
if (!autoPlaying || images.length <= 1) return;
|
|
7317
7591
|
const interval = setInterval(() => {
|
|
7318
7592
|
setCarouselIndex((p) => (p + 1) % images.length);
|
|
@@ -7628,9 +7902,10 @@ function PropertyOverview({
|
|
|
7628
7902
|
bathrooms,
|
|
7629
7903
|
carSpaces,
|
|
7630
7904
|
propertyTypeLabel,
|
|
7631
|
-
tokensIssued: tokensIssuedProp
|
|
7905
|
+
tokensIssued: tokensIssuedProp,
|
|
7906
|
+
isLoading = false
|
|
7632
7907
|
}) {
|
|
7633
|
-
const [isDescExpanded, setDescExpanded] =
|
|
7908
|
+
const [isDescExpanded, setDescExpanded] = React9.useState(false);
|
|
7634
7909
|
const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
|
|
7635
7910
|
const landSize = landProp ?? overviewData?.landSizeSqm ?? null;
|
|
7636
7911
|
const buildingSize = buildingProp ?? overviewData?.buildingSizeSqm ?? null;
|
|
@@ -7666,13 +7941,14 @@ function PropertyOverview({
|
|
|
7666
7941
|
const weeklyRent = overviewData?.weeklyRent ?? 0;
|
|
7667
7942
|
const annualRent = weeklyRent * 52;
|
|
7668
7943
|
const dividendYield = resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
|
|
7944
|
+
const loadingSkeleton = /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 90, height: 18 });
|
|
7669
7945
|
const financialItems = financialItemsProp ?? [
|
|
7670
|
-
{ label: "Token Price", value: tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
|
|
7671
|
-
{ label: "Property Value", value: resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
|
|
7672
|
-
{ label: "Weekly Rent", value: weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
|
|
7673
|
-
{ label: "Dividend Yield", value: dividendYield ? `${dividendYield}%` : "N/A" },
|
|
7674
|
-
{ label: "Total Tokens", value: resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
|
|
7675
|
-
{ 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" }
|
|
7676
7952
|
];
|
|
7677
7953
|
const galleryImages = images ?? [];
|
|
7678
7954
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
@@ -7976,8 +8252,8 @@ var OfferPricePulse = styled24__default.default.span`
|
|
|
7976
8252
|
`;
|
|
7977
8253
|
var eventTypes = ["Leased", "Renovated", "Extended", "Rebuilt", "Rezoned", "DA Approval"];
|
|
7978
8254
|
function PropertyHistory() {
|
|
7979
|
-
const [historyFilter, setHistoryFilter] =
|
|
7980
|
-
const pastSales =
|
|
8255
|
+
const [historyFilter, setHistoryFilter] = React9.useState("all");
|
|
8256
|
+
const pastSales = React9.useMemo(() => generateMockPastSales(), []);
|
|
7981
8257
|
const loafListing = pastSales.find((sale) => sale.type === "Listed");
|
|
7982
8258
|
const loafEvents = pastSales.filter(
|
|
7983
8259
|
(sale) => sale.ownershipPeriod === "current" && sale.type !== "Listed" && (sale.id === "leased-current" || sale.id === "da-approval")
|
|
@@ -8114,7 +8390,7 @@ function PropertyHistory() {
|
|
|
8114
8390
|
] });
|
|
8115
8391
|
}
|
|
8116
8392
|
function EventDetails({ event }) {
|
|
8117
|
-
const [expanded, setExpanded] =
|
|
8393
|
+
const [expanded, setExpanded] = React9.useState(false);
|
|
8118
8394
|
const toggleExpand = () => {
|
|
8119
8395
|
setExpanded((prev) => !prev);
|
|
8120
8396
|
};
|
|
@@ -8902,7 +9178,7 @@ function AssetSelectorBar({
|
|
|
8902
9178
|
selectorItems,
|
|
8903
9179
|
onSelect
|
|
8904
9180
|
}) {
|
|
8905
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
9181
|
+
const [isDropdownOpen, setIsDropdownOpen] = React9.useState(false);
|
|
8906
9182
|
const hasItems = selectorItems && selectorItems.length > 0;
|
|
8907
9183
|
const metrics = metricsProp ?? [
|
|
8908
9184
|
...tokenPrice != null ? [{ label: "Unit Price", value: `$${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, accent: true }] : [],
|
|
@@ -9171,15 +9447,15 @@ function OfferingProgressCard({
|
|
|
9171
9447
|
targetAmount,
|
|
9172
9448
|
isPrivateClient = false
|
|
9173
9449
|
}) {
|
|
9174
|
-
const [currentTime, setCurrentTime] =
|
|
9175
|
-
const [countdown, setCountdown] =
|
|
9450
|
+
const [currentTime, setCurrentTime] = React9.useState(/* @__PURE__ */ new Date());
|
|
9451
|
+
const [countdown, setCountdown] = React9.useState(null);
|
|
9176
9452
|
const computedRaised = raisedAmount ?? totalSold * tokenPrice;
|
|
9177
9453
|
const computedTarget = targetAmount ?? supplyToSell * tokenPrice;
|
|
9178
|
-
|
|
9454
|
+
React9.useEffect(() => {
|
|
9179
9455
|
const timer = setInterval(() => setCurrentTime(/* @__PURE__ */ new Date()), 1e3);
|
|
9180
9456
|
return () => clearInterval(timer);
|
|
9181
9457
|
}, []);
|
|
9182
|
-
|
|
9458
|
+
React9.useEffect(() => {
|
|
9183
9459
|
if (!opensAt) {
|
|
9184
9460
|
setCountdown(null);
|
|
9185
9461
|
return;
|
|
@@ -9516,14 +9792,19 @@ var formatTimeAgo2 = (timestamp) => {
|
|
|
9516
9792
|
};
|
|
9517
9793
|
function VideoActivitySection({
|
|
9518
9794
|
ipoStarted,
|
|
9795
|
+
ipoEnded = false,
|
|
9796
|
+
isLoading = false,
|
|
9519
9797
|
recentOrders = [],
|
|
9520
9798
|
ordersAllocated = 0,
|
|
9521
9799
|
tokenPrice = 0
|
|
9522
9800
|
}) {
|
|
9523
|
-
const sortedOrders =
|
|
9801
|
+
const sortedOrders = React9.useMemo(
|
|
9524
9802
|
() => [...recentOrders].sort((a, b) => b.timestamp - a.timestamp).slice(0, 7),
|
|
9525
9803
|
[recentOrders]
|
|
9526
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);
|
|
9527
9808
|
return /* @__PURE__ */ jsxRuntime.jsxs(Section3, { children: [
|
|
9528
9809
|
/* @__PURE__ */ jsxRuntime.jsxs(VideoPanel, { children: [
|
|
9529
9810
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "section-header", children: /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Musgrave" }) }),
|
|
@@ -9535,31 +9816,40 @@ function VideoActivitySection({
|
|
|
9535
9816
|
/* @__PURE__ */ jsxRuntime.jsxs(ActivityPanel, { children: [
|
|
9536
9817
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "section-header", children: [
|
|
9537
9818
|
/* @__PURE__ */ jsxRuntime.jsxs("h3", { children: [
|
|
9538
|
-
/* @__PURE__ */ jsxRuntime.jsx(LiveIndicatorDot, { $active: ipoStarted }),
|
|
9819
|
+
/* @__PURE__ */ jsxRuntime.jsx(LiveIndicatorDot, { $active: ipoStarted && !ipoEnded }),
|
|
9539
9820
|
"Recent Order Activity"
|
|
9540
9821
|
] }),
|
|
9541
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
9822
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: headerStatusText })
|
|
9542
9823
|
] }),
|
|
9543
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-content", children:
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
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: [
|
|
9563
9853
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner" }),
|
|
9564
9854
|
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Activity will appear once the Offering opens" })
|
|
9565
9855
|
] }) })
|
|
@@ -9700,6 +9990,43 @@ var ActivityPanel = styled24__default.default.div`
|
|
|
9700
9990
|
to { transform: rotate(360deg); }
|
|
9701
9991
|
}
|
|
9702
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
|
+
`;
|
|
9703
10030
|
var FeedList = styled24__default.default.div`
|
|
9704
10031
|
width: 100%;
|
|
9705
10032
|
overflow-y: auto;
|
|
@@ -9817,10 +10144,10 @@ function OrderPanel({
|
|
|
9817
10144
|
tokenDisplayName,
|
|
9818
10145
|
tokenSymbol
|
|
9819
10146
|
}) {
|
|
9820
|
-
const [payInputValue, setPayInputValue] =
|
|
9821
|
-
const [receiveInputValue, setReceiveInputValue] =
|
|
9822
|
-
const [isPayInputFocused, setIsPayInputFocused] =
|
|
9823
|
-
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);
|
|
9824
10151
|
const handlePayBlur = () => {
|
|
9825
10152
|
setIsPayInputFocused(false);
|
|
9826
10153
|
const parsed = parseInt(payInputValue.replace(/[^0-9]/g, ""), 10) || 0;
|
|
@@ -10666,9 +10993,9 @@ function PortfolioActivityPanel({
|
|
|
10666
10993
|
style
|
|
10667
10994
|
}) {
|
|
10668
10995
|
const resolvedDefaultTab = defaultTab ?? (showPositionsTab ? "positions" : "subscriptions");
|
|
10669
|
-
const [activeTab, setActiveTab] =
|
|
10670
|
-
const [activityPage, setActivityPage] =
|
|
10671
|
-
const activeTabTotal =
|
|
10996
|
+
const [activeTab, setActiveTab] = React9.useState(resolvedDefaultTab);
|
|
10997
|
+
const [activityPage, setActivityPage] = React9.useState(0);
|
|
10998
|
+
const activeTabTotal = React9.useMemo(() => {
|
|
10672
10999
|
switch (activeTab) {
|
|
10673
11000
|
case "positions":
|
|
10674
11001
|
return positions.length;
|
|
@@ -10686,6 +11013,22 @@ function PortfolioActivityPanel({
|
|
|
10686
11013
|
return 0;
|
|
10687
11014
|
}
|
|
10688
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
|
+
);
|
|
10689
11032
|
const activityTotalPages = Math.ceil(activeTabTotal / pageSize);
|
|
10690
11033
|
const pageSlice = (arr) => arr.slice(activityPage * pageSize, (activityPage + 1) * pageSize);
|
|
10691
11034
|
const handleTabChange = (tab) => {
|
|
@@ -10695,10 +11038,38 @@ function PortfolioActivityPanel({
|
|
|
10695
11038
|
return /* @__PURE__ */ jsxRuntime.jsxs(Container2, { className, style, children: [
|
|
10696
11039
|
/* @__PURE__ */ jsxRuntime.jsx(PanelTitle, { children: "Activity" }),
|
|
10697
11040
|
/* @__PURE__ */ jsxRuntime.jsxs(TabContainer, { children: [
|
|
10698
|
-
showPositionsTab && /* @__PURE__ */ jsxRuntime.
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
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
|
+
] }),
|
|
10702
11073
|
/* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "trades", onClick: () => handleTabChange("trades"), children: "Trade History" }),
|
|
10703
11074
|
/* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "transfers", onClick: () => handleTabChange("transfers"), children: "Transfers" })
|
|
10704
11075
|
] }),
|
|
@@ -10783,8 +11154,10 @@ function PortfolioActivityPanel({
|
|
|
10783
11154
|
openOrders.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: "Open orders will appear here while they are working in the market." }),
|
|
10784
11155
|
pageSlice(openOrders).map((order) => {
|
|
10785
11156
|
const meta = getOrderStatusMeta(order.status);
|
|
10786
|
-
const
|
|
10787
|
-
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";
|
|
10788
11161
|
const isCancelling = cancellingOrderId === order.id;
|
|
10789
11162
|
return /* @__PURE__ */ jsxRuntime.jsxs(ActivityRow, { children: [
|
|
10790
11163
|
/* @__PURE__ */ jsxRuntime.jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
|
|
@@ -10794,9 +11167,10 @@ function PortfolioActivityPanel({
|
|
|
10794
11167
|
formatNumber2(order.quantity),
|
|
10795
11168
|
" tokens \xB7 ",
|
|
10796
11169
|
prettyLabel(order.type),
|
|
11170
|
+
priceSegment,
|
|
10797
11171
|
" \xB7 ",
|
|
10798
|
-
|
|
10799
|
-
" \xB7 ",
|
|
11172
|
+
filledPercent,
|
|
11173
|
+
"% filled \xB7 ",
|
|
10800
11174
|
formatTimestamp(order.createdAt)
|
|
10801
11175
|
] })
|
|
10802
11176
|
] }),
|
|
@@ -10823,8 +11197,10 @@ function PortfolioActivityPanel({
|
|
|
10823
11197
|
orderHistory.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: "No orders yet. Place a trade to see it appear here." }),
|
|
10824
11198
|
pageSlice(orderHistory).map((order) => {
|
|
10825
11199
|
const meta = getOrderStatusMeta(order.status);
|
|
10826
|
-
const
|
|
10827
|
-
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";
|
|
10828
11204
|
return /* @__PURE__ */ jsxRuntime.jsxs(ActivityRow, { children: [
|
|
10829
11205
|
/* @__PURE__ */ jsxRuntime.jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
|
|
10830
11206
|
/* @__PURE__ */ jsxRuntime.jsxs(ActivityInfo, { children: [
|
|
@@ -10833,9 +11209,10 @@ function PortfolioActivityPanel({
|
|
|
10833
11209
|
formatNumber2(order.quantity),
|
|
10834
11210
|
" tokens \xB7 ",
|
|
10835
11211
|
prettyLabel(order.type),
|
|
11212
|
+
priceSegment,
|
|
10836
11213
|
" \xB7 ",
|
|
10837
|
-
|
|
10838
|
-
" \xB7 ",
|
|
11214
|
+
filledPercent,
|
|
11215
|
+
"% filled \xB7 ",
|
|
10839
11216
|
formatTimestamp(order.createdAt)
|
|
10840
11217
|
] })
|
|
10841
11218
|
] }),
|
|
@@ -10977,6 +11354,12 @@ var Tab = styled24__default.default.button`
|
|
|
10977
11354
|
color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.65)"};
|
|
10978
11355
|
}
|
|
10979
11356
|
`;
|
|
11357
|
+
var TabCount = styled24__default.default.span`
|
|
11358
|
+
color: inherit;
|
|
11359
|
+
opacity: 0.7;
|
|
11360
|
+
font-weight: 500;
|
|
11361
|
+
margin-left: 2px;
|
|
11362
|
+
`;
|
|
10980
11363
|
var ActivityRow = styled24__default.default.div`
|
|
10981
11364
|
display: grid;
|
|
10982
11365
|
grid-template-columns: auto 1fr auto auto;
|
|
@@ -11620,23 +12003,24 @@ function PropertyBuy({
|
|
|
11620
12003
|
recentOrders = [],
|
|
11621
12004
|
ordersAllocated = 0,
|
|
11622
12005
|
subscribers = 0,
|
|
12006
|
+
isLoadingActivity = false,
|
|
11623
12007
|
selectorItems,
|
|
11624
12008
|
onSelectorSelect,
|
|
11625
12009
|
portfolioActivity
|
|
11626
12010
|
}) {
|
|
11627
|
-
const [sliderValue, setSliderValue] =
|
|
11628
|
-
const [availableBalance, setAvailableBalance] =
|
|
11629
|
-
const [manualOrderAmount, setManualOrderAmount] =
|
|
11630
|
-
const [ownedTokens, setOwnedTokens] =
|
|
11631
|
-
const [displayedOwnedTokens, setDisplayedOwnedTokens] =
|
|
11632
|
-
const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] =
|
|
11633
|
-
const [lastOrderQuantity, setLastOrderQuantity] =
|
|
11634
|
-
const [orderPendingAllocation, setOrderPendingAllocation] =
|
|
11635
|
-
const [orderPlacedSuccess, setOrderPlacedSuccess] =
|
|
11636
|
-
const [lastOrderDetails, setLastOrderDetails] =
|
|
11637
|
-
const [showOrderConfirmModal, setShowOrderConfirmModal] =
|
|
11638
|
-
const [, setLiveNewsIndex] =
|
|
11639
|
-
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(
|
|
11640
12024
|
() => allNewsItems.slice(0, 4).map((item, index) => ({
|
|
11641
12025
|
...item,
|
|
11642
12026
|
displayId: `${item.id}-initial-${index}`,
|
|
@@ -11652,6 +12036,7 @@ function PropertyBuy({
|
|
|
11652
12036
|
const offeringValuation = saleData?.offeringValuation ?? tokenPrice * supplyToSell;
|
|
11653
12037
|
const ipoStatus = saleData?.status ?? "PENDING";
|
|
11654
12038
|
const ipoStarted = ipoStatus === "LIVE" || isPrivateClient && ipoStatus === "PENDING";
|
|
12039
|
+
const ipoEnded = ipoStatus === "CLOSED" || ipoStatus === "CANCELLED";
|
|
11655
12040
|
const statusLabel = ipoStatus;
|
|
11656
12041
|
const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
|
|
11657
12042
|
const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
|
|
@@ -11662,12 +12047,12 @@ function PropertyBuy({
|
|
|
11662
12047
|
const orderTotal = tokenQuantity * tokenPrice + feeInUsd;
|
|
11663
12048
|
const estExposure = (tokenQuantity / supplyToSell * 100).toFixed(4);
|
|
11664
12049
|
const hasInsufficientFunds = orderTotal > availableBalance;
|
|
11665
|
-
|
|
12050
|
+
React9.useEffect(() => {
|
|
11666
12051
|
if (walletUsdcBalance != null) {
|
|
11667
12052
|
setAvailableBalance(walletUsdcBalance);
|
|
11668
12053
|
}
|
|
11669
12054
|
}, [walletUsdcBalance]);
|
|
11670
|
-
|
|
12055
|
+
React9.useEffect(() => {
|
|
11671
12056
|
if (walletPropertyTokenBalance != null) {
|
|
11672
12057
|
setOwnedTokens(walletPropertyTokenBalance);
|
|
11673
12058
|
setDisplayedOwnedTokens(walletPropertyTokenBalance);
|
|
@@ -11679,13 +12064,13 @@ function PropertyBuy({
|
|
|
11679
12064
|
}
|
|
11680
12065
|
setShowOrderConfirmModal(true);
|
|
11681
12066
|
};
|
|
11682
|
-
|
|
12067
|
+
React9.useEffect(() => {
|
|
11683
12068
|
if (purchaseStatus === "success" && orderPendingAllocation) {
|
|
11684
12069
|
setOrderPendingAllocation(false);
|
|
11685
12070
|
setOrderPlacedSuccess(true);
|
|
11686
12071
|
}
|
|
11687
12072
|
}, [purchaseStatus, orderPendingAllocation]);
|
|
11688
|
-
const handlePlaceAnotherOrder =
|
|
12073
|
+
const handlePlaceAnotherOrder = React9.useCallback(() => {
|
|
11689
12074
|
setOrderPlacedSuccess(false);
|
|
11690
12075
|
setOrderPendingAllocation(false);
|
|
11691
12076
|
}, []);
|
|
@@ -11742,7 +12127,7 @@ function PropertyBuy({
|
|
|
11742
12127
|
setSliderValue(0);
|
|
11743
12128
|
setManualOrderAmount(null);
|
|
11744
12129
|
};
|
|
11745
|
-
|
|
12130
|
+
React9.useEffect(() => {
|
|
11746
12131
|
const newsInterval = setInterval(() => {
|
|
11747
12132
|
setLiveNewsIndex((prev) => {
|
|
11748
12133
|
const nextIndex = (prev + 1) % allNewsItems.length;
|
|
@@ -11802,6 +12187,8 @@ function PropertyBuy({
|
|
|
11802
12187
|
VideoActivitySection,
|
|
11803
12188
|
{
|
|
11804
12189
|
ipoStarted,
|
|
12190
|
+
ipoEnded,
|
|
12191
|
+
isLoading: isLoadingActivity,
|
|
11805
12192
|
recentOrders,
|
|
11806
12193
|
ordersAllocated,
|
|
11807
12194
|
tokenPrice
|
|
@@ -12036,7 +12423,7 @@ function PaymentPopup({
|
|
|
12036
12423
|
userTokenHoldings,
|
|
12037
12424
|
propertyName
|
|
12038
12425
|
}) {
|
|
12039
|
-
const [selectedPaymentMethod, setSelectedPaymentMethod] =
|
|
12426
|
+
const [selectedPaymentMethod, setSelectedPaymentMethod] = React9.useState(
|
|
12040
12427
|
"tokens"
|
|
12041
12428
|
);
|
|
12042
12429
|
if (!isOpen) return null;
|
|
@@ -12215,20 +12602,20 @@ function PaymentPopup({
|
|
|
12215
12602
|
var payment_popup_default = PaymentPopup;
|
|
12216
12603
|
var SUMMER_MONTHS = /* @__PURE__ */ new Set([11, 0, 1]);
|
|
12217
12604
|
var OwnerBooking = ({ propertyName, token }) => {
|
|
12218
|
-
const today =
|
|
12605
|
+
const today = React9.useMemo(() => {
|
|
12219
12606
|
const base = /* @__PURE__ */ new Date();
|
|
12220
12607
|
base.setHours(0, 0, 0, 0);
|
|
12221
12608
|
return base;
|
|
12222
12609
|
}, []);
|
|
12223
|
-
const [currentYear, setCurrentYear] =
|
|
12224
|
-
const [currentMonth, setCurrentMonth] =
|
|
12225
|
-
const [dateRanges, setDateRanges] =
|
|
12226
|
-
const [selectedDates, setSelectedDates] =
|
|
12227
|
-
const [hoverDate, setHoverDate] =
|
|
12228
|
-
const [isDateSelectorOpen, setIsDateSelectorOpen] =
|
|
12229
|
-
const [selectorYear, setSelectorYear] =
|
|
12230
|
-
const [isPaymentPopupOpen, setIsPaymentPopupOpen] =
|
|
12231
|
-
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);
|
|
12232
12619
|
const tokenPrice = token.price ?? 700;
|
|
12233
12620
|
const userTokenHoldings = 2.2;
|
|
12234
12621
|
const MIN_NIGHTS = 3;
|
|
@@ -12238,25 +12625,25 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12238
12625
|
{ bg: "rgba(230, 126, 34, 0.25)", border: "rgba(230, 126, 34, 0.6)" },
|
|
12239
12626
|
{ bg: "rgba(46, 204, 113, 0.25)", border: "rgba(46, 204, 113, 0.6)" }
|
|
12240
12627
|
];
|
|
12241
|
-
const calculateTokensPerDayOwner =
|
|
12628
|
+
const calculateTokensPerDayOwner = React9.useCallback(() => {
|
|
12242
12629
|
if (tokenPrice <= 0) return 0;
|
|
12243
12630
|
const target = 650;
|
|
12244
12631
|
const raw = target / tokenPrice;
|
|
12245
12632
|
return Math.ceil(raw * 1e4) / 1e4;
|
|
12246
12633
|
}, [tokenPrice]);
|
|
12247
|
-
const calculateTokensPerDayMarket =
|
|
12634
|
+
const calculateTokensPerDayMarket = React9.useCallback(() => {
|
|
12248
12635
|
if (tokenPrice <= 0) return 0;
|
|
12249
12636
|
const target = 900;
|
|
12250
12637
|
const raw = target / tokenPrice;
|
|
12251
12638
|
return Math.ceil(raw * 1e4) / 1e4;
|
|
12252
12639
|
}, [tokenPrice]);
|
|
12253
12640
|
const qualifiesForOwnerRate = userTokenHoldings >= 0.1;
|
|
12254
|
-
const getTokensPerDay =
|
|
12641
|
+
const getTokensPerDay = React9.useCallback(
|
|
12255
12642
|
() => calculateTokensPerDayOwner() ,
|
|
12256
12643
|
[qualifiesForOwnerRate, calculateTokensPerDayOwner, calculateTokensPerDayMarket]
|
|
12257
12644
|
);
|
|
12258
12645
|
const getRateLabel = () => "Owner's Rate" ;
|
|
12259
|
-
const selectionStats =
|
|
12646
|
+
const selectionStats = React9.useMemo(() => {
|
|
12260
12647
|
if (selectedDates.length !== 2) return null;
|
|
12261
12648
|
const [a, b] = selectedDates;
|
|
12262
12649
|
const start = a < b ? a : b;
|
|
@@ -12267,10 +12654,10 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12267
12654
|
const usd = tokens * tokenPrice;
|
|
12268
12655
|
return { nights, tokensPerDay, tokens, usd, start, end };
|
|
12269
12656
|
}, [selectedDates, getTokensPerDay, tokenPrice]);
|
|
12270
|
-
const totalNights =
|
|
12271
|
-
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]);
|
|
12272
12659
|
const totalUSD = totalTokens * tokenPrice;
|
|
12273
|
-
const generateCalendarDays =
|
|
12660
|
+
const generateCalendarDays = React9.useCallback(
|
|
12274
12661
|
(year, month) => {
|
|
12275
12662
|
const first = new Date(year, month, 1);
|
|
12276
12663
|
const last = new Date(year, month + 1, 0);
|
|
@@ -12299,11 +12686,11 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12299
12686
|
},
|
|
12300
12687
|
[today]
|
|
12301
12688
|
);
|
|
12302
|
-
const calendarDays =
|
|
12689
|
+
const calendarDays = React9.useMemo(
|
|
12303
12690
|
() => generateCalendarDays(currentYear, currentMonth),
|
|
12304
12691
|
[currentYear, currentMonth, generateCalendarDays]
|
|
12305
12692
|
);
|
|
12306
|
-
const isDateReserved =
|
|
12693
|
+
const isDateReserved = React9.useCallback(
|
|
12307
12694
|
(date) => dateRanges.some((r) => date >= r.arrival && date <= r.departure),
|
|
12308
12695
|
[dateRanges]
|
|
12309
12696
|
);
|
|
@@ -12397,14 +12784,14 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12397
12784
|
"December"
|
|
12398
12785
|
];
|
|
12399
12786
|
const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
12400
|
-
const setMonthYear =
|
|
12787
|
+
const setMonthYear = React9.useCallback(
|
|
12401
12788
|
(month, year) => {
|
|
12402
12789
|
setCurrentMonth(month);
|
|
12403
12790
|
setCurrentYear(year);
|
|
12404
12791
|
},
|
|
12405
12792
|
[setCurrentMonth, setCurrentYear]
|
|
12406
12793
|
);
|
|
12407
|
-
const shiftMonth =
|
|
12794
|
+
const shiftMonth = React9.useCallback(
|
|
12408
12795
|
(direction) => {
|
|
12409
12796
|
const delta = direction === "prev" ? -1 : 1;
|
|
12410
12797
|
let newMonth = currentMonth + delta;
|
|
@@ -12421,7 +12808,7 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12421
12808
|
},
|
|
12422
12809
|
[currentMonth, currentYear, setMonthYear]
|
|
12423
12810
|
);
|
|
12424
|
-
const jumpToNextAvailable =
|
|
12811
|
+
const jumpToNextAvailable = React9.useCallback(() => {
|
|
12425
12812
|
for (let offset = 1; offset <= 12; offset++) {
|
|
12426
12813
|
const candidateMonth = (currentMonth + offset) % 12;
|
|
12427
12814
|
if (!SUMMER_MONTHS.has(candidateMonth)) continue;
|
|
@@ -12438,7 +12825,7 @@ var OwnerBooking = ({ propertyName, token }) => {
|
|
|
12438
12825
|
setMonthYear(month, selectorYear);
|
|
12439
12826
|
setIsDateSelectorOpen(false);
|
|
12440
12827
|
};
|
|
12441
|
-
|
|
12828
|
+
React9.useEffect(() => {
|
|
12442
12829
|
const handleClickOutside = (event) => {
|
|
12443
12830
|
if (dateSelectorRef.current && !dateSelectorRef.current.contains(event.target)) {
|
|
12444
12831
|
setIsDateSelectorOpen(false);
|
|
@@ -12882,21 +13269,21 @@ function PropertyValuation({
|
|
|
12882
13269
|
loading = false,
|
|
12883
13270
|
error = null
|
|
12884
13271
|
}) {
|
|
12885
|
-
const now =
|
|
12886
|
-
const lastPrice =
|
|
13272
|
+
const now = React9.useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
13273
|
+
const lastPrice = React9.useMemo(() => {
|
|
12887
13274
|
const fallback = Number.isFinite(tokenPrice) && tokenPrice > 0 ? tokenPrice : 0;
|
|
12888
13275
|
if (!summary?.lastPrice || summary.lastPrice <= 0) {
|
|
12889
13276
|
return fallback;
|
|
12890
13277
|
}
|
|
12891
13278
|
return summary.lastPrice;
|
|
12892
13279
|
}, [summary, tokenPrice]);
|
|
12893
|
-
const fairValue =
|
|
13280
|
+
const fairValue = React9.useMemo(() => {
|
|
12894
13281
|
if (summary?.fairValue && summary.fairValue > 0) {
|
|
12895
13282
|
return summary.fairValue;
|
|
12896
13283
|
}
|
|
12897
13284
|
return lastPrice || 1;
|
|
12898
13285
|
}, [summary, lastPrice]);
|
|
12899
|
-
const tokensOutstanding =
|
|
13286
|
+
const tokensOutstanding = React9.useMemo(() => {
|
|
12900
13287
|
if (summary?.totalTokens && summary.totalTokens > 0) {
|
|
12901
13288
|
return summary.totalTokens;
|
|
12902
13289
|
}
|
|
@@ -12911,8 +13298,8 @@ function PropertyValuation({
|
|
|
12911
13298
|
const valuationStatus = summary?.valuationStatus ?? (lastPrice < fairValue ? "Undervalued" : lastPrice > fairValue ? "Overvalued" : "Fair Value");
|
|
12912
13299
|
const valuationDelta = summary?.valuationDeltaPercent ?? (lastPrice - fairValue) / fairValue * 100;
|
|
12913
13300
|
const valuationDeltaFormatted = `${valuationDelta >= 0 ? "+" : ""}${valuationDelta.toFixed(1)}%`;
|
|
12914
|
-
const { valuationPath, fairValuePath, axisLabels } =
|
|
12915
|
-
const recentSales =
|
|
13301
|
+
const { valuationPath, fairValuePath, axisLabels } = React9.useMemo(() => buildChartPaths(history, fairValue), [history, fairValue]);
|
|
13302
|
+
const recentSales = React9.useMemo(() => {
|
|
12916
13303
|
if (summary?.recentSales?.length) {
|
|
12917
13304
|
return summary.recentSales;
|
|
12918
13305
|
}
|
|
@@ -14064,19 +14451,19 @@ function PropertyPhotoGallery({
|
|
|
14064
14451
|
);
|
|
14065
14452
|
}
|
|
14066
14453
|
function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose }) {
|
|
14067
|
-
const [currentIndex, setCurrentIndex] =
|
|
14068
|
-
const [activeHotspotId, setActiveHotspotId] =
|
|
14069
|
-
const sliderRef =
|
|
14070
|
-
const [isDragging, setIsDragging] =
|
|
14071
|
-
const wasDraggingRef =
|
|
14072
|
-
const touchStartX =
|
|
14073
|
-
const touchStartY =
|
|
14074
|
-
const isSwiping =
|
|
14075
|
-
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(() => {
|
|
14076
14463
|
if (galleryImages.length <= 1) return 0;
|
|
14077
14464
|
return currentIndex / (galleryImages.length - 1) * 100;
|
|
14078
14465
|
}, [currentIndex, galleryImages.length]);
|
|
14079
|
-
|
|
14466
|
+
React9.useEffect(() => {
|
|
14080
14467
|
document.body.style.overflow = "hidden";
|
|
14081
14468
|
document.body.style.touchAction = "none";
|
|
14082
14469
|
return () => {
|
|
@@ -14084,7 +14471,7 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
|
|
|
14084
14471
|
document.body.style.touchAction = "";
|
|
14085
14472
|
};
|
|
14086
14473
|
}, []);
|
|
14087
|
-
|
|
14474
|
+
React9.useEffect(() => {
|
|
14088
14475
|
const handleKey = (event) => {
|
|
14089
14476
|
if (event.key === "Escape") onClose();
|
|
14090
14477
|
if (event.key === "ArrowLeft") setCurrentIndex((i) => i === 0 ? galleryImages.length - 1 : i - 1);
|
|
@@ -14357,13 +14744,13 @@ function truncateHash(hash) {
|
|
|
14357
14744
|
return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
|
|
14358
14745
|
}
|
|
14359
14746
|
function ToastItem({ toast, onDismiss }) {
|
|
14360
|
-
const [exiting, setExiting] =
|
|
14361
|
-
const timerRef =
|
|
14362
|
-
const dismiss =
|
|
14747
|
+
const [exiting, setExiting] = React9.useState(false);
|
|
14748
|
+
const timerRef = React9.useRef(null);
|
|
14749
|
+
const dismiss = React9.useCallback(() => {
|
|
14363
14750
|
setExiting(true);
|
|
14364
14751
|
setTimeout(() => onDismiss(toast.id), 280);
|
|
14365
14752
|
}, [onDismiss, toast.id]);
|
|
14366
|
-
|
|
14753
|
+
React9.useEffect(() => {
|
|
14367
14754
|
const duration2 = toast.duration ?? 6e3;
|
|
14368
14755
|
if (duration2 > 0) {
|
|
14369
14756
|
timerRef.current = setTimeout(dismiss, duration2);
|
|
@@ -14392,15 +14779,15 @@ function ToastItem({ toast, onDismiss }) {
|
|
|
14392
14779
|
duration > 0 && /* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { $color: accent, $duration: duration })
|
|
14393
14780
|
] });
|
|
14394
14781
|
}
|
|
14395
|
-
var ToastContext =
|
|
14782
|
+
var ToastContext = React9.createContext(null);
|
|
14396
14783
|
function ToastProvider({ children }) {
|
|
14397
|
-
const [toasts, setToasts] =
|
|
14398
|
-
const addToast =
|
|
14784
|
+
const [toasts, setToasts] = React9.useState([]);
|
|
14785
|
+
const addToast = React9.useCallback((data) => {
|
|
14399
14786
|
const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
14400
14787
|
setToasts((prev) => [...prev, { ...data, id }]);
|
|
14401
14788
|
return id;
|
|
14402
14789
|
}, []);
|
|
14403
|
-
const dismiss =
|
|
14790
|
+
const dismiss = React9.useCallback((id) => {
|
|
14404
14791
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
14405
14792
|
}, []);
|
|
14406
14793
|
return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
|
|
@@ -14409,10 +14796,71 @@ function ToastProvider({ children }) {
|
|
|
14409
14796
|
] });
|
|
14410
14797
|
}
|
|
14411
14798
|
function useToast() {
|
|
14412
|
-
const ctx =
|
|
14799
|
+
const ctx = React9.useContext(ToastContext);
|
|
14413
14800
|
if (!ctx) throw new Error("useToast must be used within a ToastProvider");
|
|
14414
14801
|
return ctx;
|
|
14415
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
|
+
}
|
|
14416
14864
|
|
|
14417
14865
|
exports.AssetSelectorBar = AssetSelectorBar;
|
|
14418
14866
|
exports.Badge = Badge;
|
|
@@ -14449,12 +14897,15 @@ exports.PropertyPhotoGallery = PropertyPhotoGallery;
|
|
|
14449
14897
|
exports.PropertySubheader = PropertySubheader;
|
|
14450
14898
|
exports.PropertyTour = PropertyTour;
|
|
14451
14899
|
exports.PropertyValuation = PropertyValuation;
|
|
14900
|
+
exports.Skeleton = Skeleton;
|
|
14452
14901
|
exports.ToastProvider = ToastProvider;
|
|
14453
14902
|
exports.TradeConfirmationModal = TradeConfirmationModal;
|
|
14454
14903
|
exports.TradingSlider = TradingSlider;
|
|
14455
14904
|
exports.YourOrders = YourOrders;
|
|
14456
14905
|
exports.badgeVariants = badgeVariants;
|
|
14457
14906
|
exports.buttonVariants = buttonVariants;
|
|
14907
|
+
exports.hasPendingActivity = hasPendingActivity;
|
|
14908
|
+
exports.useAdaptivePolling = useAdaptivePolling;
|
|
14458
14909
|
exports.useToast = useToast;
|
|
14459
14910
|
//# sourceMappingURL=index.js.map
|
|
14460
14911
|
//# sourceMappingURL=index.js.map
|