@loafmarkets/ui 0.1.40 → 0.1.41

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,6 +4875,7 @@ 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
4880
  /* @__PURE__ */ jsxRuntime.jsxs(HeaderContainer, { children: [
4880
4881
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
@@ -5124,6 +5125,17 @@ var Header = ({
5124
5125
  ] });
5125
5126
  };
5126
5127
  Header.displayName = "Header";
5128
+ var SafeAreaCover = styled24__default.default.div`
5129
+ position: fixed;
5130
+ top: 0;
5131
+ left: 0;
5132
+ right: 0;
5133
+ height: env(safe-area-inset-top, 0px);
5134
+ min-height: env(safe-area-inset-top, 0px);
5135
+ background-color: #0d1117;
5136
+ z-index: 1001;
5137
+ pointer-events: none;
5138
+ `;
5127
5139
  var Overlay = styled24__default.default.div`
5128
5140
  display: ${(props) => props.$isOpen ? "block" : "none"};
5129
5141
  position: fixed;
@@ -5170,20 +5182,24 @@ var HeaderContainer = styled24__default.default.header`
5170
5182
  display: flex;
5171
5183
  justify-content: space-between;
5172
5184
  align-items: center;
5185
+ /* Split padding so browsers that don't support env() inside shorthand
5186
+ still get the horizontal padding — only the top falls back to 0 */
5173
5187
  padding: 0 2rem;
5188
+ padding-top: env(safe-area-inset-top, 0px);
5174
5189
  background-color: #0d1117;
5175
5190
  border-bottom: 1px solid #232a32;
5176
5191
  position: sticky;
5177
5192
  top: 0;
5178
- left: 0;
5179
- right: 0;
5180
5193
  z-index: 1000;
5181
5194
  width: 100%;
5182
- height: 56px;
5195
+ /* Fallback min-height for browsers that can't evaluate calc+env */
5196
+ min-height: 56px;
5197
+ min-height: calc(56px + env(safe-area-inset-top, 0px));
5183
5198
  box-sizing: border-box;
5184
5199
 
5185
5200
  @media (max-width: 768px) {
5186
5201
  padding: 0 1rem;
5202
+ padding-top: env(safe-area-inset-top, 0px);
5187
5203
  }
5188
5204
  `;
5189
5205
  var Logo = styled24__default.default.div`
@@ -9781,6 +9797,7 @@ function OrderPanel({
9781
9797
  displayedOwnedTokens,
9782
9798
  ownedTokensJustUpdated,
9783
9799
  lastOrderQuantity,
9800
+ orderPendingAllocation,
9784
9801
  orderPlacedSuccess,
9785
9802
  lastOrderDetails,
9786
9803
  tokenQuantity,
@@ -9843,7 +9860,40 @@ function OrderPanel({
9843
9860
  statusLabel
9844
9861
  ] })
9845
9862
  ] }),
9846
- orderPlacedSuccess ? /* @__PURE__ */ jsxRuntime.jsxs(OrderSuccessCard, { children: [
9863
+ orderPendingAllocation ? /* @__PURE__ */ jsxRuntime.jsxs(OrderPendingCard, { children: [
9864
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pending-header", children: [
9865
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner" }),
9866
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9867
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Processing Order" }),
9868
+ /* @__PURE__ */ jsxRuntime.jsx("small", { children: "Awaiting allocation..." })
9869
+ ] })
9870
+ ] }),
9871
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pending-body", children: [
9872
+ [
9873
+ { label: "Units Requested", value: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9874
+ lastOrderDetails?.tokens?.toFixed(2) || "0.00",
9875
+ " ",
9876
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "rgba(255,255,255,0.4)", fontWeight: 400 }, children: tokenSymbol })
9877
+ ] }) },
9878
+ { label: "Price Per Unit", value: `$${tokenPrice.toFixed(2)}` },
9879
+ {
9880
+ label: `${tokenDisplayName} Exposure`,
9881
+ value: `${((lastOrderDetails?.tokens ?? 0) / supplyToSell * 100).toFixed(3)}%`
9882
+ }
9883
+ ].map((row) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pending-row", children: [
9884
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: row.label }),
9885
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: row.value })
9886
+ ] }, row.label)),
9887
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pending-total", children: [
9888
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total Investment" }),
9889
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
9890
+ "$",
9891
+ lastOrderDetails?.total?.toLocaleString() || "0"
9892
+ ] })
9893
+ ] })
9894
+ ] }),
9895
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pending-footnote", children: "Your order has been submitted and is being processed. This usually takes a few seconds." })
9896
+ ] }) : orderPlacedSuccess ? /* @__PURE__ */ jsxRuntime.jsxs(OrderSuccessCard, { children: [
9847
9897
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "success-header", children: [
9848
9898
  /* @__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
9899
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -10022,7 +10072,7 @@ function OrderPanel({
10022
10072
  ] })
10023
10073
  ] })
10024
10074
  ] }),
10025
- !orderPlacedSuccess && /* @__PURE__ */ jsxRuntime.jsx(
10075
+ !orderPlacedSuccess && !orderPendingAllocation && /* @__PURE__ */ jsxRuntime.jsx(
10026
10076
  SubscribeButton,
10027
10077
  {
10028
10078
  type: "button",
@@ -10345,6 +10395,110 @@ var BalanceSub = styled24__default.default.div`
10345
10395
  color: var(--color-text-secondary);
10346
10396
  margin-top: 0.25rem;
10347
10397
  `;
10398
+ var OrderPendingCard = styled24__default.default.div`
10399
+ margin-bottom: 1.5rem;
10400
+ background: linear-gradient(180deg, rgba(25,27,31,0.95) 0%, rgba(18,20,24,0.98) 100%);
10401
+ border: 1px solid rgba(212,175,55,0.08);
10402
+ border-radius: 12px;
10403
+ overflow: hidden;
10404
+ box-shadow: 0 4px 20px rgba(0,0,0,0.3);
10405
+
10406
+ @keyframes spin {
10407
+ to { transform: rotate(360deg); }
10408
+ }
10409
+
10410
+ @keyframes pulse {
10411
+ 0%, 100% { opacity: 1; }
10412
+ 50% { opacity: 0.6; }
10413
+ }
10414
+
10415
+ .pending-header {
10416
+ border-bottom: 1px solid rgba(255,255,255,0.06);
10417
+ padding: 1.25rem 1.5rem;
10418
+ display: flex;
10419
+ align-items: center;
10420
+ gap: 0.875rem;
10421
+ background: linear-gradient(135deg, rgba(212,175,55,0.04) 0%, transparent 100%);
10422
+
10423
+ .spinner {
10424
+ width: 32px;
10425
+ height: 32px;
10426
+ border-radius: 50%;
10427
+ border: 2.5px solid rgba(212,175,55,0.15);
10428
+ border-top-color: #D4AF37;
10429
+ animation: spin 0.8s linear infinite;
10430
+ flex-shrink: 0;
10431
+ }
10432
+
10433
+ p {
10434
+ font-size: 0.95rem;
10435
+ font-weight: 600;
10436
+ color: #fff;
10437
+ margin: 0;
10438
+ animation: pulse 2s ease-in-out infinite;
10439
+ }
10440
+ small {
10441
+ font-size: 0.7rem;
10442
+ color: rgba(255,255,255,0.4);
10443
+ }
10444
+ }
10445
+
10446
+ .pending-body {
10447
+ padding: 1.25rem 1.5rem;
10448
+ }
10449
+ .pending-row {
10450
+ display: flex;
10451
+ justify-content: space-between;
10452
+ align-items: center;
10453
+ padding-bottom: 0.875rem;
10454
+ margin-bottom: 0.875rem;
10455
+ border-bottom: 1px solid rgba(255,255,255,0.06);
10456
+ span {
10457
+ font-size: 0.75rem;
10458
+ color: rgba(255,255,255,0.4);
10459
+ text-transform: uppercase;
10460
+ letter-spacing: 0.05em;
10461
+ font-weight: 500;
10462
+ }
10463
+ strong {
10464
+ font-size: 0.95rem;
10465
+ font-weight: 500;
10466
+ color: rgba(255,255,255,0.5);
10467
+ font-family: monospace;
10468
+ }
10469
+ }
10470
+ .pending-total {
10471
+ display: flex;
10472
+ justify-content: space-between;
10473
+ align-items: center;
10474
+ padding: 0.875rem;
10475
+ background: rgba(212,175,55,0.03);
10476
+ border-radius: 8px;
10477
+ border: 1px solid rgba(212,175,55,0.06);
10478
+ span {
10479
+ font-size: 0.75rem;
10480
+ color: rgba(255,255,255,0.5);
10481
+ text-transform: uppercase;
10482
+ letter-spacing: 0.05em;
10483
+ font-weight: 500;
10484
+ }
10485
+ strong {
10486
+ font-size: 1.05rem;
10487
+ font-weight: 700;
10488
+ color: rgba(212,175,55,0.7);
10489
+ font-family: monospace;
10490
+ }
10491
+ }
10492
+ .pending-footnote {
10493
+ padding: 1rem 1.5rem;
10494
+ border-top: 1px solid rgba(255,255,255,0.06);
10495
+ background: rgba(0,0,0,0.2);
10496
+ font-size: 0.75rem;
10497
+ color: rgba(255,255,255,0.4);
10498
+ line-height: 1.6;
10499
+ animation: pulse 2s ease-in-out infinite;
10500
+ }
10501
+ `;
10348
10502
  var OrderSuccessCard = styled24__default.default.div`
10349
10503
  margin-bottom: 1.5rem;
10350
10504
  background: linear-gradient(180deg, rgba(25,27,31,0.95) 0%, rgba(18,20,24,0.98) 100%);
@@ -11200,6 +11354,7 @@ function OrderConfirmationModal({
11200
11354
  tokenQuantity,
11201
11355
  tokenPrice,
11202
11356
  propertyName,
11357
+ tokenSymbol,
11203
11358
  estExposure,
11204
11359
  orderTotal,
11205
11360
  availableBalance,
@@ -11214,7 +11369,7 @@ function OrderConfirmationModal({
11214
11369
  /* @__PURE__ */ jsxRuntime.jsx(ModalBody, { children: [
11215
11370
  { label: "Order Type", value: "Primary Offering" },
11216
11371
  { label: "Property", value: propertyName },
11217
- { label: "Units", value: `${tokenQuantity.toLocaleString()} MUS`, highlight: true },
11372
+ { label: "Units", value: `${tokenQuantity.toLocaleString()} ${tokenSymbol}`, highlight: true },
11218
11373
  {
11219
11374
  label: "Unit Price",
11220
11375
  value: `$${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
@@ -11245,7 +11400,9 @@ function OrderConfirmationModal({
11245
11400
  "Your order for ",
11246
11401
  /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
11247
11402
  tokenQuantity.toLocaleString(),
11248
- " MUS units"
11403
+ " ",
11404
+ tokenSymbol,
11405
+ " units"
11249
11406
  ] }),
11250
11407
  " in the",
11251
11408
  " ",
@@ -11474,6 +11631,7 @@ function PropertyBuy({
11474
11631
  const [displayedOwnedTokens, setDisplayedOwnedTokens] = React5.useState(0);
11475
11632
  const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React5.useState(false);
11476
11633
  const [lastOrderQuantity, setLastOrderQuantity] = React5.useState(0);
11634
+ const [orderPendingAllocation, setOrderPendingAllocation] = React5.useState(false);
11477
11635
  const [orderPlacedSuccess, setOrderPlacedSuccess] = React5.useState(false);
11478
11636
  const [lastOrderDetails, setLastOrderDetails] = React5.useState(null);
11479
11637
  const [showOrderConfirmModal, setShowOrderConfirmModal] = React5.useState(false);
@@ -11521,12 +11679,23 @@ function PropertyBuy({
11521
11679
  }
11522
11680
  setShowOrderConfirmModal(true);
11523
11681
  };
11524
- const isPurchaseInFlight = purchaseStatus === "checking-allowance" || purchaseStatus === "approving" || purchaseStatus === "purchasing";
11682
+ React5.useEffect(() => {
11683
+ if (purchaseStatus === "success" && orderPendingAllocation) {
11684
+ setOrderPendingAllocation(false);
11685
+ setOrderPlacedSuccess(true);
11686
+ }
11687
+ }, [purchaseStatus, orderPendingAllocation]);
11688
+ const handlePlaceAnotherOrder = React5.useCallback(() => {
11689
+ setOrderPlacedSuccess(false);
11690
+ setOrderPendingAllocation(false);
11691
+ }, []);
11692
+ const isPurchaseInFlight = purchaseStatus === "checking-allowance" || purchaseStatus === "approving" || purchaseStatus === "purchasing" || purchaseStatus === "pending-allocation";
11525
11693
  const getOrderButtonText = () => {
11526
11694
  if (!isAuthenticated) return "Sign In to Invest";
11527
11695
  if (purchaseStatus === "checking-allowance") return "Checking allowance\u2026";
11528
11696
  if (purchaseStatus === "approving") return "Approving USDC\u2026";
11529
11697
  if (purchaseStatus === "purchasing") return "Confirming purchase\u2026";
11698
+ if (purchaseStatus === "pending-allocation") return "Awaiting allocation\u2026";
11530
11699
  if (ipoStatus === "PENDING" && !isPrivateClient) return "Sale Not Open Yet";
11531
11700
  if (ipoStatus === "CLOSED") return "Sale Completed";
11532
11701
  if (ipoStatus === "CANCELLED") return "Sale Cancelled";
@@ -11569,7 +11738,7 @@ function PropertyBuy({
11569
11738
  total: orderTotal,
11570
11739
  price: tokenPrice
11571
11740
  });
11572
- setOrderPlacedSuccess(true);
11741
+ setOrderPendingAllocation(true);
11573
11742
  setSliderValue(0);
11574
11743
  setManualOrderAmount(null);
11575
11744
  };
@@ -11655,6 +11824,7 @@ function PropertyBuy({
11655
11824
  displayedOwnedTokens,
11656
11825
  ownedTokensJustUpdated,
11657
11826
  lastOrderQuantity,
11827
+ orderPendingAllocation,
11658
11828
  orderPlacedSuccess,
11659
11829
  lastOrderDetails,
11660
11830
  tokenQuantity,
@@ -11669,7 +11839,7 @@ function PropertyBuy({
11669
11839
  orderButtonText: getOrderButtonText(),
11670
11840
  isOrderButtonDisabled: isOrderButtonDisabled(),
11671
11841
  hasInsufficientFunds,
11672
- onPlaceAnotherOrder: () => setOrderPlacedSuccess(false),
11842
+ onPlaceAnotherOrder: handlePlaceAnotherOrder,
11673
11843
  onDeposit
11674
11844
  }
11675
11845
  ),
@@ -11703,6 +11873,7 @@ function PropertyBuy({
11703
11873
  tokenQuantity,
11704
11874
  tokenPrice,
11705
11875
  propertyName,
11876
+ tokenSymbol,
11706
11877
  estExposure,
11707
11878
  orderTotal,
11708
11879
  availableBalance,