@loafmarkets/ui 0.1.40 → 0.1.42

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 CHANGED
@@ -901,7 +901,7 @@ type PropertyBuyProps = {
901
901
  walletUsdcBalance?: number | null;
902
902
  walletPropertyTokenBalance?: number | null;
903
903
  onPurchase?: (tokenAmount: number) => Promise<void>;
904
- purchaseStatus?: 'idle' | 'checking-allowance' | 'approving' | 'purchasing' | 'success' | 'error';
904
+ purchaseStatus?: 'idle' | 'checking-allowance' | 'approving' | 'purchasing' | 'pending-allocation' | 'success' | 'error';
905
905
  purchaseError?: string | null;
906
906
  onDeposit?: () => void;
907
907
  initialUserSubscriptions?: PropertySubscription[];
package/dist/index.d.ts CHANGED
@@ -901,7 +901,7 @@ type PropertyBuyProps = {
901
901
  walletUsdcBalance?: number | null;
902
902
  walletPropertyTokenBalance?: number | null;
903
903
  onPurchase?: (tokenAmount: number) => Promise<void>;
904
- purchaseStatus?: 'idle' | 'checking-allowance' | 'approving' | 'purchasing' | 'success' | 'error';
904
+ purchaseStatus?: 'idle' | 'checking-allowance' | 'approving' | 'purchasing' | 'pending-allocation' | 'success' | 'error';
905
905
  purchaseError?: string | null;
906
906
  onDeposit?: () => void;
907
907
  initialUserSubscriptions?: PropertySubscription[];
package/dist/index.js CHANGED
@@ -2009,7 +2009,7 @@ function DesktopOrderbookLayout({
2009
2009
  /* @__PURE__ */ jsxRuntime.jsx(
2010
2010
  "div",
2011
2011
  {
2012
- className: "divide-y divide-white/5 overflow-y-auto",
2012
+ className: "flex flex-col justify-end divide-y divide-white/5 overflow-y-auto",
2013
2013
  style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
2014
2014
  children: asks.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2015
2015
  DepthRow,
@@ -4875,8 +4875,9 @@ var Header = ({
4875
4875
  const portfolioActive = resolvedActiveTab === "portfolio";
4876
4876
  const learnActive = resolvedActiveTab === "learn";
4877
4877
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4878
+ /* @__PURE__ */ jsxRuntime.jsx(SafeAreaCover, {}),
4878
4879
  /* @__PURE__ */ jsxRuntime.jsx(Overlay, { $isOpen: isMobileMenuOpen, onClick: () => setIsMobileMenuOpen(false) }),
4879
- /* @__PURE__ */ jsxRuntime.jsxs(HeaderContainer, { children: [
4880
+ /* @__PURE__ */ jsxRuntime.jsxs(HeaderContainer, { id: "loaf-header", children: [
4880
4881
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
4881
4882
  /* @__PURE__ */ jsxRuntime.jsxs(Logo, { children: [
4882
4883
  /* @__PURE__ */ jsxRuntime.jsx(LogoLink, { href: logoHref ?? resolvedHomePath, onClick: handleLogoNavigation, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: Loaf_logo_Banner_default, alt: "LOAF Logo" }) }),
@@ -5114,6 +5115,7 @@ var Header = ({
5114
5115
  )
5115
5116
  ] })
5116
5117
  ] }),
5118
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderSpacer, {}),
5117
5119
  LoginPopupComponent && showLoginPopup && /* @__PURE__ */ jsxRuntime.jsx(
5118
5120
  LoginPopupComponent,
5119
5121
  {
@@ -5124,6 +5126,17 @@ var Header = ({
5124
5126
  ] });
5125
5127
  };
5126
5128
  Header.displayName = "Header";
5129
+ var SafeAreaCover = styled24__default.default.div`
5130
+ position: fixed;
5131
+ top: 0;
5132
+ left: 0;
5133
+ right: 0;
5134
+ height: env(safe-area-inset-top, 0px);
5135
+ min-height: env(safe-area-inset-top, 0px);
5136
+ background-color: #0d1117;
5137
+ z-index: 1001;
5138
+ pointer-events: none;
5139
+ `;
5127
5140
  var Overlay = styled24__default.default.div`
5128
5141
  display: ${(props) => props.$isOpen ? "block" : "none"};
5129
5142
  position: fixed;
@@ -5170,22 +5183,34 @@ var HeaderContainer = styled24__default.default.header`
5170
5183
  display: flex;
5171
5184
  justify-content: space-between;
5172
5185
  align-items: center;
5186
+ /* Split padding so browsers that don't support env() inside shorthand
5187
+ still get the horizontal padding — only the top falls back to 0 */
5173
5188
  padding: 0 2rem;
5189
+ padding-top: env(safe-area-inset-top, 0px);
5174
5190
  background-color: #0d1117;
5175
5191
  border-bottom: 1px solid #232a32;
5176
- position: sticky;
5192
+ position: fixed;
5177
5193
  top: 0;
5178
5194
  left: 0;
5179
5195
  right: 0;
5180
5196
  z-index: 1000;
5181
5197
  width: 100%;
5182
- height: 56px;
5198
+ /* Fallback min-height for browsers that can't evaluate calc+env */
5199
+ min-height: 56px;
5200
+ min-height: calc(56px + env(safe-area-inset-top, 0px));
5183
5201
  box-sizing: border-box;
5184
5202
 
5185
5203
  @media (max-width: 768px) {
5186
5204
  padding: 0 1rem;
5205
+ padding-top: env(safe-area-inset-top, 0px);
5187
5206
  }
5188
5207
  `;
5208
+ var HeaderSpacer = styled24__default.default.div`
5209
+ width: 100%;
5210
+ min-height: 56px;
5211
+ min-height: calc(56px + env(safe-area-inset-top, 0px));
5212
+ flex-shrink: 0;
5213
+ `;
5189
5214
  var Logo = styled24__default.default.div`
5190
5215
  display: flex;
5191
5216
  align-items: center;
@@ -5238,10 +5263,12 @@ var Nav = styled24__default.default.nav`
5238
5263
  @media (max-width: 1300px) {
5239
5264
  position: fixed;
5240
5265
  top: 56px;
5266
+ top: calc(56px + env(safe-area-inset-top, 0px));
5241
5267
  right: ${(props) => props.$isOpen ? "0" : "-100%"} ;
5242
5268
  width: 280px;
5243
5269
  max-width: 280px;
5244
5270
  height: calc(100vh - 56px);
5271
+ height: calc(100vh - 56px - env(safe-area-inset-top, 0px));
5245
5272
  background: linear-gradient(180deg, #0f1419 0%, #0a0e13 100%);
5246
5273
  z-index: 1000;
5247
5274
  transition: right 0.3s ease;
@@ -9781,6 +9808,7 @@ function OrderPanel({
9781
9808
  displayedOwnedTokens,
9782
9809
  ownedTokensJustUpdated,
9783
9810
  lastOrderQuantity,
9811
+ orderPendingAllocation,
9784
9812
  orderPlacedSuccess,
9785
9813
  lastOrderDetails,
9786
9814
  tokenQuantity,
@@ -9843,7 +9871,40 @@ function OrderPanel({
9843
9871
  statusLabel
9844
9872
  ] })
9845
9873
  ] }),
9846
- orderPlacedSuccess ? /* @__PURE__ */ jsxRuntime.jsxs(OrderSuccessCard, { children: [
9874
+ orderPendingAllocation ? /* @__PURE__ */ jsxRuntime.jsxs(OrderPendingCard, { children: [
9875
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pending-header", children: [
9876
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner" }),
9877
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9878
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Processing Order" }),
9879
+ /* @__PURE__ */ jsxRuntime.jsx("small", { children: "Awaiting allocation..." })
9880
+ ] })
9881
+ ] }),
9882
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pending-body", children: [
9883
+ [
9884
+ { label: "Units Requested", value: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9885
+ lastOrderDetails?.tokens?.toFixed(2) || "0.00",
9886
+ " ",
9887
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "rgba(255,255,255,0.4)", fontWeight: 400 }, children: tokenSymbol })
9888
+ ] }) },
9889
+ { label: "Price Per Unit", value: `$${tokenPrice.toFixed(2)}` },
9890
+ {
9891
+ label: `${tokenDisplayName} Exposure`,
9892
+ value: `${((lastOrderDetails?.tokens ?? 0) / supplyToSell * 100).toFixed(3)}%`
9893
+ }
9894
+ ].map((row) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pending-row", children: [
9895
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: row.label }),
9896
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: row.value })
9897
+ ] }, row.label)),
9898
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pending-total", children: [
9899
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total Investment" }),
9900
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
9901
+ "$",
9902
+ lastOrderDetails?.total?.toLocaleString() || "0"
9903
+ ] })
9904
+ ] })
9905
+ ] }),
9906
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pending-footnote", children: "Your order has been submitted and is being processed. This usually takes a few seconds." })
9907
+ ] }) : orderPlacedSuccess ? /* @__PURE__ */ jsxRuntime.jsxs(OrderSuccessCard, { children: [
9847
9908
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "success-header", children: [
9848
9909
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "icon", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "#D4AF37", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }) }),
9849
9910
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -10022,7 +10083,7 @@ function OrderPanel({
10022
10083
  ] })
10023
10084
  ] })
10024
10085
  ] }),
10025
- !orderPlacedSuccess && /* @__PURE__ */ jsxRuntime.jsx(
10086
+ !orderPlacedSuccess && !orderPendingAllocation && /* @__PURE__ */ jsxRuntime.jsx(
10026
10087
  SubscribeButton,
10027
10088
  {
10028
10089
  type: "button",
@@ -10345,6 +10406,110 @@ var BalanceSub = styled24__default.default.div`
10345
10406
  color: var(--color-text-secondary);
10346
10407
  margin-top: 0.25rem;
10347
10408
  `;
10409
+ var OrderPendingCard = styled24__default.default.div`
10410
+ margin-bottom: 1.5rem;
10411
+ background: linear-gradient(180deg, rgba(25,27,31,0.95) 0%, rgba(18,20,24,0.98) 100%);
10412
+ border: 1px solid rgba(212,175,55,0.08);
10413
+ border-radius: 12px;
10414
+ overflow: hidden;
10415
+ box-shadow: 0 4px 20px rgba(0,0,0,0.3);
10416
+
10417
+ @keyframes spin {
10418
+ to { transform: rotate(360deg); }
10419
+ }
10420
+
10421
+ @keyframes pulse {
10422
+ 0%, 100% { opacity: 1; }
10423
+ 50% { opacity: 0.6; }
10424
+ }
10425
+
10426
+ .pending-header {
10427
+ border-bottom: 1px solid rgba(255,255,255,0.06);
10428
+ padding: 1.25rem 1.5rem;
10429
+ display: flex;
10430
+ align-items: center;
10431
+ gap: 0.875rem;
10432
+ background: linear-gradient(135deg, rgba(212,175,55,0.04) 0%, transparent 100%);
10433
+
10434
+ .spinner {
10435
+ width: 32px;
10436
+ height: 32px;
10437
+ border-radius: 50%;
10438
+ border: 2.5px solid rgba(212,175,55,0.15);
10439
+ border-top-color: #D4AF37;
10440
+ animation: spin 0.8s linear infinite;
10441
+ flex-shrink: 0;
10442
+ }
10443
+
10444
+ p {
10445
+ font-size: 0.95rem;
10446
+ font-weight: 600;
10447
+ color: #fff;
10448
+ margin: 0;
10449
+ animation: pulse 2s ease-in-out infinite;
10450
+ }
10451
+ small {
10452
+ font-size: 0.7rem;
10453
+ color: rgba(255,255,255,0.4);
10454
+ }
10455
+ }
10456
+
10457
+ .pending-body {
10458
+ padding: 1.25rem 1.5rem;
10459
+ }
10460
+ .pending-row {
10461
+ display: flex;
10462
+ justify-content: space-between;
10463
+ align-items: center;
10464
+ padding-bottom: 0.875rem;
10465
+ margin-bottom: 0.875rem;
10466
+ border-bottom: 1px solid rgba(255,255,255,0.06);
10467
+ span {
10468
+ font-size: 0.75rem;
10469
+ color: rgba(255,255,255,0.4);
10470
+ text-transform: uppercase;
10471
+ letter-spacing: 0.05em;
10472
+ font-weight: 500;
10473
+ }
10474
+ strong {
10475
+ font-size: 0.95rem;
10476
+ font-weight: 500;
10477
+ color: rgba(255,255,255,0.5);
10478
+ font-family: monospace;
10479
+ }
10480
+ }
10481
+ .pending-total {
10482
+ display: flex;
10483
+ justify-content: space-between;
10484
+ align-items: center;
10485
+ padding: 0.875rem;
10486
+ background: rgba(212,175,55,0.03);
10487
+ border-radius: 8px;
10488
+ border: 1px solid rgba(212,175,55,0.06);
10489
+ span {
10490
+ font-size: 0.75rem;
10491
+ color: rgba(255,255,255,0.5);
10492
+ text-transform: uppercase;
10493
+ letter-spacing: 0.05em;
10494
+ font-weight: 500;
10495
+ }
10496
+ strong {
10497
+ font-size: 1.05rem;
10498
+ font-weight: 700;
10499
+ color: rgba(212,175,55,0.7);
10500
+ font-family: monospace;
10501
+ }
10502
+ }
10503
+ .pending-footnote {
10504
+ padding: 1rem 1.5rem;
10505
+ border-top: 1px solid rgba(255,255,255,0.06);
10506
+ background: rgba(0,0,0,0.2);
10507
+ font-size: 0.75rem;
10508
+ color: rgba(255,255,255,0.4);
10509
+ line-height: 1.6;
10510
+ animation: pulse 2s ease-in-out infinite;
10511
+ }
10512
+ `;
10348
10513
  var OrderSuccessCard = styled24__default.default.div`
10349
10514
  margin-bottom: 1.5rem;
10350
10515
  background: linear-gradient(180deg, rgba(25,27,31,0.95) 0%, rgba(18,20,24,0.98) 100%);
@@ -11200,6 +11365,7 @@ function OrderConfirmationModal({
11200
11365
  tokenQuantity,
11201
11366
  tokenPrice,
11202
11367
  propertyName,
11368
+ tokenSymbol,
11203
11369
  estExposure,
11204
11370
  orderTotal,
11205
11371
  availableBalance,
@@ -11214,7 +11380,7 @@ function OrderConfirmationModal({
11214
11380
  /* @__PURE__ */ jsxRuntime.jsx(ModalBody, { children: [
11215
11381
  { label: "Order Type", value: "Primary Offering" },
11216
11382
  { label: "Property", value: propertyName },
11217
- { label: "Units", value: `${tokenQuantity.toLocaleString()} MUS`, highlight: true },
11383
+ { label: "Units", value: `${tokenQuantity.toLocaleString()} ${tokenSymbol}`, highlight: true },
11218
11384
  {
11219
11385
  label: "Unit Price",
11220
11386
  value: `$${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
@@ -11245,7 +11411,9 @@ function OrderConfirmationModal({
11245
11411
  "Your order for ",
11246
11412
  /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
11247
11413
  tokenQuantity.toLocaleString(),
11248
- " MUS units"
11414
+ " ",
11415
+ tokenSymbol,
11416
+ " units"
11249
11417
  ] }),
11250
11418
  " in the",
11251
11419
  " ",
@@ -11474,6 +11642,7 @@ function PropertyBuy({
11474
11642
  const [displayedOwnedTokens, setDisplayedOwnedTokens] = React5.useState(0);
11475
11643
  const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React5.useState(false);
11476
11644
  const [lastOrderQuantity, setLastOrderQuantity] = React5.useState(0);
11645
+ const [orderPendingAllocation, setOrderPendingAllocation] = React5.useState(false);
11477
11646
  const [orderPlacedSuccess, setOrderPlacedSuccess] = React5.useState(false);
11478
11647
  const [lastOrderDetails, setLastOrderDetails] = React5.useState(null);
11479
11648
  const [showOrderConfirmModal, setShowOrderConfirmModal] = React5.useState(false);
@@ -11521,12 +11690,23 @@ function PropertyBuy({
11521
11690
  }
11522
11691
  setShowOrderConfirmModal(true);
11523
11692
  };
11524
- const isPurchaseInFlight = purchaseStatus === "checking-allowance" || purchaseStatus === "approving" || purchaseStatus === "purchasing";
11693
+ React5.useEffect(() => {
11694
+ if (purchaseStatus === "success" && orderPendingAllocation) {
11695
+ setOrderPendingAllocation(false);
11696
+ setOrderPlacedSuccess(true);
11697
+ }
11698
+ }, [purchaseStatus, orderPendingAllocation]);
11699
+ const handlePlaceAnotherOrder = React5.useCallback(() => {
11700
+ setOrderPlacedSuccess(false);
11701
+ setOrderPendingAllocation(false);
11702
+ }, []);
11703
+ const isPurchaseInFlight = purchaseStatus === "checking-allowance" || purchaseStatus === "approving" || purchaseStatus === "purchasing" || purchaseStatus === "pending-allocation";
11525
11704
  const getOrderButtonText = () => {
11526
11705
  if (!isAuthenticated) return "Sign In to Invest";
11527
11706
  if (purchaseStatus === "checking-allowance") return "Checking allowance\u2026";
11528
11707
  if (purchaseStatus === "approving") return "Approving USDC\u2026";
11529
11708
  if (purchaseStatus === "purchasing") return "Confirming purchase\u2026";
11709
+ if (purchaseStatus === "pending-allocation") return "Awaiting allocation\u2026";
11530
11710
  if (ipoStatus === "PENDING" && !isPrivateClient) return "Sale Not Open Yet";
11531
11711
  if (ipoStatus === "CLOSED") return "Sale Completed";
11532
11712
  if (ipoStatus === "CANCELLED") return "Sale Cancelled";
@@ -11569,7 +11749,7 @@ function PropertyBuy({
11569
11749
  total: orderTotal,
11570
11750
  price: tokenPrice
11571
11751
  });
11572
- setOrderPlacedSuccess(true);
11752
+ setOrderPendingAllocation(true);
11573
11753
  setSliderValue(0);
11574
11754
  setManualOrderAmount(null);
11575
11755
  };
@@ -11655,6 +11835,7 @@ function PropertyBuy({
11655
11835
  displayedOwnedTokens,
11656
11836
  ownedTokensJustUpdated,
11657
11837
  lastOrderQuantity,
11838
+ orderPendingAllocation,
11658
11839
  orderPlacedSuccess,
11659
11840
  lastOrderDetails,
11660
11841
  tokenQuantity,
@@ -11669,7 +11850,7 @@ function PropertyBuy({
11669
11850
  orderButtonText: getOrderButtonText(),
11670
11851
  isOrderButtonDisabled: isOrderButtonDisabled(),
11671
11852
  hasInsufficientFunds,
11672
- onPlaceAnotherOrder: () => setOrderPlacedSuccess(false),
11853
+ onPlaceAnotherOrder: handlePlaceAnotherOrder,
11673
11854
  onDeposit
11674
11855
  }
11675
11856
  ),
@@ -11703,6 +11884,7 @@ function PropertyBuy({
11703
11884
  tokenQuantity,
11704
11885
  tokenPrice,
11705
11886
  propertyName,
11887
+ tokenSymbol,
11706
11888
  estExposure,
11707
11889
  orderTotal,
11708
11890
  availableBalance,