@loafmarkets/ui 0.1.14 → 0.1.17

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React5 from 'react';
2
- import React5__default, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
2
+ import React5__default, { createContext, useState, useEffect, useMemo, useRef, useCallback, useContext } from 'react';
3
3
  import { Slot } from '@radix-ui/react-slot';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import { clsx } from 'clsx';
@@ -3349,6 +3349,7 @@ var YourOrders = React5.forwardRef(
3349
3349
  onTabChange,
3350
3350
  renderOrderActions,
3351
3351
  renderTabContent,
3352
+ pageSize: pageSizeOverride,
3352
3353
  ...props
3353
3354
  }, ref) => {
3354
3355
  const [internalActiveTab, setInternalActiveTab] = React5.useState(tabs?.[0]?.id ?? "portfolio");
@@ -3369,7 +3370,8 @@ var YourOrders = React5.forwardRef(
3369
3370
  const activeOrders = activeTab?.orders ?? orders ?? [];
3370
3371
  const DEFAULT_PAGE_SIZE = 5;
3371
3372
  const HISTORY_PAGE_SIZE = 3;
3372
- const pageSize = activeTab?.id === "order-history" || activeTab?.id === "trade-history" ? HISTORY_PAGE_SIZE : DEFAULT_PAGE_SIZE;
3373
+ const resolvedPageSize = pageSizeOverride ?? (activeTab?.id === "order-history" || activeTab?.id === "trade-history" ? HISTORY_PAGE_SIZE : DEFAULT_PAGE_SIZE);
3374
+ const pageSize = Math.max(1, resolvedPageSize);
3373
3375
  const totalOrders = activeOrders.length;
3374
3376
  const totalPages = Math.max(1, Math.ceil(totalOrders / pageSize));
3375
3377
  const safePage = Math.min(page, totalPages - 1);
@@ -4065,6 +4067,10 @@ var PropertyHeroHeader = React5.forwardRef(
4065
4067
  propertyTypeLabel,
4066
4068
  onTrade,
4067
4069
  onMakeOffer,
4070
+ tradeButtonLabel = "Trade",
4071
+ makeOfferButtonLabel = "Make Offer",
4072
+ makeOfferDisabled = false,
4073
+ hideMakeOfferButton = false,
4068
4074
  ...props
4069
4075
  }, ref) => {
4070
4076
  const isPositive = changePercent == null ? void 0 : changePercent >= 0;
@@ -4073,6 +4079,17 @@ var PropertyHeroHeader = React5.forwardRef(
4073
4079
  const [isTradeInteracting, setIsTradeInteracting] = React5.useState(false);
4074
4080
  const [isOfferInteracting, setIsOfferInteracting] = React5.useState(false);
4075
4081
  const hasAmenities = beds != null || baths != null || cars != null || propertyTypeLabel != null;
4082
+ const isTradeDisabled = !onTrade;
4083
+ const isMakeOfferButtonDisabled = makeOfferDisabled || !onMakeOffer;
4084
+ const showMakeOfferButton = !hideMakeOfferButton;
4085
+ const setTradeInteraction = (state) => {
4086
+ if (isTradeDisabled) return;
4087
+ setIsTradeInteracting(state);
4088
+ };
4089
+ const setOfferInteraction = (state) => {
4090
+ if (isMakeOfferButtonDisabled) return;
4091
+ setIsOfferInteracting(state);
4092
+ };
4076
4093
  const headingStyle = {
4077
4094
  fontSize: "clamp(1.6rem, 4vw, 2.5rem)",
4078
4095
  marginBottom: "0.5rem",
@@ -4157,54 +4174,60 @@ var PropertyHeroHeader = React5.forwardRef(
4157
4174
  "button",
4158
4175
  {
4159
4176
  type: "button",
4160
- onClick: onTrade,
4177
+ onClick: isTradeDisabled ? void 0 : onTrade,
4161
4178
  className: "flex items-center justify-center rounded border font-semibold transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_8px_rgba(0,0,0,0.2)] active:translate-y-0 active:shadow-[0_2px_4px_rgba(0,0,0,0.1)] text-[0.95rem] max-[480px]:text-[0.9rem]",
4162
4179
  style: {
4163
4180
  backgroundColor: isTradeInteracting ? tradeHoverColor : accentColor,
4164
4181
  color: "black",
4165
- width: "88.06px",
4166
- height: "43px",
4167
- minWidth: "88.06px",
4182
+ minWidth: "140px",
4183
+ padding: "0.65rem 1.5rem",
4168
4184
  borderColor: isTradeInteracting ? accentColor : "transparent",
4169
- boxShadow: isTradeInteracting ? `0 0 0 2px rgba(0,0,0,0.4), 0 0 0 4px ${accentColor}` : "none"
4185
+ boxShadow: isTradeInteracting ? `0 0 0 2px rgba(0,0,0,0.4), 0 0 0 4px ${accentColor}` : "none",
4186
+ opacity: isTradeDisabled ? 0.5 : 1,
4187
+ cursor: isTradeDisabled ? "not-allowed" : "pointer"
4170
4188
  },
4171
- onMouseEnter: () => setIsTradeInteracting(true),
4172
- onMouseLeave: () => setIsTradeInteracting(false),
4173
- onMouseDown: () => setIsTradeInteracting(true),
4174
- onMouseUp: () => setIsTradeInteracting(false),
4175
- onFocus: () => setIsTradeInteracting(true),
4176
- onBlur: () => setIsTradeInteracting(false),
4177
- onTouchStart: () => setIsTradeInteracting(true),
4178
- onTouchEnd: () => setIsTradeInteracting(false),
4179
- children: "Trade"
4189
+ onMouseEnter: () => setTradeInteraction(true),
4190
+ onMouseLeave: () => setTradeInteraction(false),
4191
+ onMouseDown: () => setTradeInteraction(true),
4192
+ onMouseUp: () => setTradeInteraction(false),
4193
+ onFocus: () => setTradeInteraction(true),
4194
+ onBlur: () => setTradeInteraction(false),
4195
+ onTouchStart: () => setTradeInteraction(true),
4196
+ onTouchEnd: () => setTradeInteraction(false),
4197
+ disabled: isTradeDisabled,
4198
+ "aria-disabled": isTradeDisabled,
4199
+ children: tradeButtonLabel
4180
4200
  }
4181
4201
  ),
4182
- /* @__PURE__ */ jsx(
4202
+ showMakeOfferButton ? /* @__PURE__ */ jsx(
4183
4203
  "button",
4184
4204
  {
4185
4205
  type: "button",
4186
- onClick: onMakeOffer,
4206
+ onClick: isMakeOfferButtonDisabled ? void 0 : onMakeOffer,
4187
4207
  className: "flex items-center justify-center rounded border font-semibold transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_8px_rgba(0,0,0,0.2)] active:translate-y-0 active:shadow-[0_2px_4px_rgba(0,0,0,0.1)] text-[0.95rem] max-[480px]:text-[0.9rem]",
4188
4208
  style: {
4189
4209
  backgroundColor: isOfferInteracting ? accentColor : "transparent",
4190
4210
  borderColor: accentColor,
4191
4211
  color: isOfferInteracting ? "black" : accentColor,
4192
- width: "127.14px",
4193
- height: "43px",
4194
- minWidth: "127.14px",
4195
- boxShadow: isOfferInteracting ? `0 0 0 2px rgba(0,0,0,0.4), 0 0 0 4px ${accentColor}` : "none"
4212
+ minWidth: "140px",
4213
+ padding: "0.65rem 1.5rem",
4214
+ boxShadow: isOfferInteracting ? `0 0 0 2px rgba(0,0,0,0.4), 0 0 0 4px ${accentColor}` : "none",
4215
+ opacity: isMakeOfferButtonDisabled ? 0.5 : 1,
4216
+ cursor: isMakeOfferButtonDisabled ? "not-allowed" : "pointer"
4196
4217
  },
4197
- onMouseEnter: () => setIsOfferInteracting(true),
4198
- onMouseLeave: () => setIsOfferInteracting(false),
4199
- onMouseDown: () => setIsOfferInteracting(true),
4200
- onMouseUp: () => setIsOfferInteracting(false),
4201
- onFocus: () => setIsOfferInteracting(true),
4202
- onBlur: () => setIsOfferInteracting(false),
4203
- onTouchStart: () => setIsOfferInteracting(true),
4204
- onTouchEnd: () => setIsOfferInteracting(false),
4205
- children: "Make Offer"
4218
+ onMouseEnter: () => setOfferInteraction(true),
4219
+ onMouseLeave: () => setOfferInteraction(false),
4220
+ onMouseDown: () => setOfferInteraction(true),
4221
+ onMouseUp: () => setOfferInteraction(false),
4222
+ onFocus: () => setOfferInteraction(true),
4223
+ onBlur: () => setOfferInteraction(false),
4224
+ onTouchStart: () => setOfferInteraction(true),
4225
+ onTouchEnd: () => setOfferInteraction(false),
4226
+ disabled: isMakeOfferButtonDisabled,
4227
+ "aria-disabled": isMakeOfferButtonDisabled,
4228
+ children: makeOfferButtonLabel
4206
4229
  }
4207
- )
4230
+ ) : null
4208
4231
  ] })
4209
4232
  ] })
4210
4233
  ] }),
@@ -4393,11 +4416,14 @@ var DEFAULT_TRADE_URL = "https://loafx-frontend-web.vercel.app/";
4393
4416
  var DEFAULT_TRADE_PATH = "/trade";
4394
4417
  var DEFAULT_HOME_PATH = "/";
4395
4418
  var DEFAULT_ABOUT_PATH = "/about";
4419
+ var DEFAULT_LEARN_PATH = "/learn";
4396
4420
  var DEFAULT_OFFERINGS_PATH = "/ipo/musgrave";
4397
4421
  var DEFAULT_PROPERTY_MAP_PATH = "/map";
4422
+ var DEFAULT_PORTFOLIO_PATH = "/portfolio";
4398
4423
  var DEFAULT_LOAF_LIQUIDITY_PATH = "/loaf-liquidity";
4399
4424
  var DEFAULT_AUTH_LOGIN_URL = "http://localhost:5174/";
4400
4425
  var DEFAULT_AUTH_RETURN_PARAM = "returnTo";
4426
+ var LOGIN_POPUP_EVENT = "loaf:open-login-popup";
4401
4427
  var Header = ({
4402
4428
  currentUser,
4403
4429
  isAuthenticated = false,
@@ -4411,8 +4437,10 @@ var Header = ({
4411
4437
  tradePath = DEFAULT_TRADE_PATH,
4412
4438
  homePath = DEFAULT_HOME_PATH,
4413
4439
  aboutPath = DEFAULT_ABOUT_PATH,
4440
+ learnPath = DEFAULT_LEARN_PATH,
4414
4441
  offeringsPath = DEFAULT_OFFERINGS_PATH,
4415
4442
  propertyMapPath = DEFAULT_PROPERTY_MAP_PATH,
4443
+ portfolioPath = DEFAULT_PORTFOLIO_PATH,
4416
4444
  loafLiquidityPath = DEFAULT_LOAF_LIQUIDITY_PATH,
4417
4445
  authLoginUrl = DEFAULT_AUTH_LOGIN_URL,
4418
4446
  authReturnParam = DEFAULT_AUTH_RETURN_PARAM,
@@ -4430,13 +4458,23 @@ var Header = ({
4430
4458
  const [isMoreMenuOpen, setIsMoreMenuOpen] = useState(false);
4431
4459
  const [showLoginPopup, setShowLoginPopup] = useState(false);
4432
4460
  const [loginPopupInitialView, setLoginPopupInitialView] = useState(void 0);
4461
+ useEffect(() => {
4462
+ console.log("[LoginTrace][Header] mounted");
4463
+ return () => console.log("[LoginTrace][Header] unmounted");
4464
+ }, []);
4465
+ useEffect(() => {
4466
+ console.log("[LoginTrace][Header] showLoginPopup changed", { showLoginPopup, loginPopupInitialView });
4467
+ }, [showLoginPopup, loginPopupInitialView]);
4468
+ useEffect(() => {
4469
+ console.log("[LoginTrace][Header] loginPopupComponent updated", { hasComponent: Boolean(LoginPopupComponent) });
4470
+ }, [LoginPopupComponent]);
4433
4471
  useEffect(() => {
4434
4472
  const handleClickOutside = (event) => {
4435
4473
  const target = event.target;
4436
4474
  if (!target) return;
4437
4475
  const clickedInsideUserMenu = target.closest(".user-menu") || target.closest(".user-menu-dropdown");
4438
4476
  if (isUserMenuOpen && !clickedInsideUserMenu) {
4439
- console.log("[Header] Closing user menu due to outside click");
4477
+ console.log("[LoginTrace][Header] Closing user menu due to outside click");
4440
4478
  setIsUserMenuOpen(false);
4441
4479
  }
4442
4480
  if (isMobileMenuOpen && !target.closest(".mobile-menu") && !target.closest(".mobile-menu-button")) {
@@ -4451,6 +4489,19 @@ var Header = ({
4451
4489
  document.removeEventListener("mousedown", handleClickOutside);
4452
4490
  };
4453
4491
  }, [isUserMenuOpen, isMobileMenuOpen, isMoreMenuOpen]);
4492
+ useEffect(() => {
4493
+ if (typeof window === "undefined") return;
4494
+ const handleExternalLoginPopup = (event) => {
4495
+ const customEvent = event;
4496
+ setLoginPopupInitialView(customEvent.detail?.initialView);
4497
+ console.log("[LoginTrace][Header] Received LOGIN_POPUP_EVENT", customEvent.detail);
4498
+ setShowLoginPopup(true);
4499
+ };
4500
+ window.addEventListener(LOGIN_POPUP_EVENT, handleExternalLoginPopup);
4501
+ return () => {
4502
+ window.removeEventListener(LOGIN_POPUP_EVENT, handleExternalLoginPopup);
4503
+ };
4504
+ }, []);
4454
4505
  const closeMenus = () => {
4455
4506
  setIsMobileMenuOpen(false);
4456
4507
  setIsUserMenuOpen(false);
@@ -4458,7 +4509,7 @@ var Header = ({
4458
4509
  };
4459
4510
  const handleUserMenuToggle = () => {
4460
4511
  const nextState = !isUserMenuOpen;
4461
- console.log("[Header] User dropdown toggle clicked", { nextState });
4512
+ console.log("[LoginTrace][Header] User dropdown toggle clicked", { nextState });
4462
4513
  setIsUserMenuOpen(nextState);
4463
4514
  };
4464
4515
  const performNavigation = (path) => {
@@ -4502,18 +4553,30 @@ var Header = ({
4502
4553
  const handleLogoutClick = async (event) => {
4503
4554
  event?.preventDefault();
4504
4555
  closeMenus();
4505
- console.log("[Header] Logout option selected, invoking onLogout handler");
4556
+ console.log("[LoginTrace][Header] Logout option selected, invoking onLogout handler");
4506
4557
  await onLogout?.();
4507
4558
  };
4508
4559
  const handleAddFundingClick = (event) => {
4509
4560
  event?.preventDefault();
4510
4561
  closeMenus();
4511
- console.log("[Header] Add funding selected");
4562
+ console.log("[LoginTrace][Header] Add funding selected");
4512
4563
  if (LoginPopupComponent) {
4513
- setLoginPopupInitialView(void 0);
4564
+ setLoginPopupInitialView("funding");
4514
4565
  setShowLoginPopup(true);
4515
4566
  }
4516
4567
  };
4568
+ const handlePortfolioNavigate = (event) => {
4569
+ event?.preventDefault();
4570
+ closeMenus();
4571
+ console.log("[LoginTrace][Header] Portfolio selected");
4572
+ if (_onOrdersNavigate) {
4573
+ _onOrdersNavigate();
4574
+ return;
4575
+ }
4576
+ if (onNavigate) {
4577
+ onNavigate("/portfolio");
4578
+ }
4579
+ };
4517
4580
  const userPrimaryLabel = currentUser?.displayName?.trim() || "User";
4518
4581
  const resolveAuthReturnUrl = () => {
4519
4582
  if (getAuthReturnUrl) {
@@ -4547,6 +4610,7 @@ var Header = ({
4547
4610
  return false;
4548
4611
  };
4549
4612
  const handleSignIn = () => {
4613
+ console.log("[LoginTrace][Header] handleSignIn invoked", { hasCustomHandler: Boolean(onSignInClick) });
4550
4614
  if (onSignInClick) {
4551
4615
  onSignInClick();
4552
4616
  return;
@@ -4555,15 +4619,23 @@ var Header = ({
4555
4619
  return;
4556
4620
  }
4557
4621
  if (LoginPopupComponent) {
4622
+ console.log("[LoginTrace][Header] Opening login popup via handleSignIn");
4558
4623
  setShowLoginPopup(true);
4559
4624
  }
4560
4625
  };
4626
+ const handleLoginPopupClose = React5__default.useCallback(() => {
4627
+ console.log("[LoginTrace][Header] Closing login popup via onClose handler");
4628
+ setShowLoginPopup(false);
4629
+ setLoginPopupInitialView(void 0);
4630
+ }, []);
4561
4631
  const inferredActiveTab = (() => {
4562
4632
  if (locationPath === tradePath) return "trade";
4563
4633
  if (locationPath === homePath) return "home";
4564
4634
  if (locationPath === aboutPath) return "about";
4635
+ if (locationPath === learnPath) return "learn";
4565
4636
  if (locationPath.startsWith(offeringsPath)) return "offerings";
4566
4637
  if (locationPath === propertyMapPath) return "propertyMap";
4638
+ if (locationPath === portfolioPath) return "portfolio";
4567
4639
  return null;
4568
4640
  })();
4569
4641
  const resolvedActiveTab = activeTab ?? inferredActiveTab;
@@ -4572,6 +4644,8 @@ var Header = ({
4572
4644
  const offeringsActive = resolvedActiveTab === "offerings";
4573
4645
  const propertyMapActive = resolvedActiveTab === "propertyMap";
4574
4646
  const aboutActive = resolvedActiveTab === "about";
4647
+ const portfolioActive = resolvedActiveTab === "portfolio";
4648
+ const learnActive = resolvedActiveTab === "learn";
4575
4649
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4576
4650
  /* @__PURE__ */ jsx(Overlay, { $isOpen: isMobileMenuOpen, onClick: () => setIsMobileMenuOpen(false) }),
4577
4651
  /* @__PURE__ */ jsxs(HeaderContainer, { children: [
@@ -4611,6 +4685,18 @@ var Header = ({
4611
4685
  children: "Trade"
4612
4686
  }
4613
4687
  ),
4688
+ /* @__PURE__ */ jsx(
4689
+ NavLink,
4690
+ {
4691
+ href: portfolioPath,
4692
+ className: portfolioActive ? "active" : "",
4693
+ onClick: (event) => {
4694
+ event.preventDefault();
4695
+ handleNavigation(portfolioPath);
4696
+ },
4697
+ children: "Portfolio"
4698
+ }
4699
+ ),
4614
4700
  /* @__PURE__ */ jsx(
4615
4701
  NavLink,
4616
4702
  {
@@ -4620,7 +4706,7 @@ var Header = ({
4620
4706
  event.preventDefault();
4621
4707
  handleNavigation(offeringsPath);
4622
4708
  },
4623
- children: "Offerings"
4709
+ children: "Initial Offerings"
4624
4710
  }
4625
4711
  ),
4626
4712
  /* @__PURE__ */ jsx(
@@ -4635,6 +4721,18 @@ var Header = ({
4635
4721
  children: "Property Map"
4636
4722
  }
4637
4723
  ),
4724
+ /* @__PURE__ */ jsx(
4725
+ NavLink,
4726
+ {
4727
+ href: learnPath,
4728
+ className: learnActive ? "active" : "",
4729
+ onClick: (event) => {
4730
+ event.preventDefault();
4731
+ handleNavigation(learnPath);
4732
+ },
4733
+ children: "Learn"
4734
+ }
4735
+ ),
4638
4736
  /* @__PURE__ */ jsx(
4639
4737
  NavLink,
4640
4738
  {
@@ -4682,8 +4780,10 @@ var Header = ({
4682
4780
  children: "Trade"
4683
4781
  }
4684
4782
  ),
4685
- /* @__PURE__ */ jsx(MobileNavItem, { onClick: () => handleNavigation(offeringsPath), children: "Offerings" }),
4783
+ /* @__PURE__ */ jsx(MobileNavItem, { onClick: () => handleNavigation(portfolioPath), children: "Portfolio" }),
4784
+ /* @__PURE__ */ jsx(MobileNavItem, { onClick: () => handleNavigation(offeringsPath), children: "Initial Offerings" }),
4686
4785
  /* @__PURE__ */ jsx(MobileNavItem, { onClick: () => handleNavigation(propertyMapPath), children: "Property Map" }),
4786
+ /* @__PURE__ */ jsx(MobileNavItem, { onClick: () => handleNavigation(learnPath), children: "Learn" }),
4687
4787
  /* @__PURE__ */ jsx(MobileNavItem, { onClick: () => handleNavigation(aboutPath), children: "About" }),
4688
4788
  /* @__PURE__ */ jsx("div", { style: { borderTop: "1px solid #2b3139", margin: "8px 0" } }),
4689
4789
  /* @__PURE__ */ jsx(
@@ -4725,14 +4825,13 @@ var Header = ({
4725
4825
  ),
4726
4826
  isUserMenuOpen && /* @__PURE__ */ jsxs(DropdownMenu, { className: "user-menu-dropdown", children: [
4727
4827
  /* @__PURE__ */ jsx(
4728
- "div",
4828
+ "button",
4729
4829
  {
4730
- style: {
4731
- padding: "12px 16px",
4732
- borderBottom: "1px solid rgba(255,255,255,0.08)",
4733
- textAlign: "left"
4830
+ type: "button",
4831
+ onClick: (event) => {
4832
+ handlePortfolioNavigate(event);
4734
4833
  },
4735
- children: /* @__PURE__ */ jsx("p", { style: { margin: 0, fontWeight: 600 }, children: userPrimaryLabel })
4834
+ children: /* @__PURE__ */ jsx(MenuItem, { children: "Portfolio" })
4736
4835
  }
4737
4836
  ),
4738
4837
  /* @__PURE__ */ jsx(
@@ -4740,7 +4839,7 @@ var Header = ({
4740
4839
  {
4741
4840
  type: "button",
4742
4841
  onClick: (event) => {
4743
- console.log("[Header] Add funding menu item clicked");
4842
+ console.log("[LoginTrace][Header] Add funding menu item clicked");
4744
4843
  handleAddFundingClick(event);
4745
4844
  },
4746
4845
  children: /* @__PURE__ */ jsx(MenuItem, { children: "Add funding" })
@@ -4751,7 +4850,7 @@ var Header = ({
4751
4850
  {
4752
4851
  type: "button",
4753
4852
  onClick: (event) => {
4754
- console.log("[Header] Logout menu item clicked");
4853
+ console.log("[LoginTrace][Header] Logout menu item clicked");
4755
4854
  void handleLogoutClick(event);
4756
4855
  },
4757
4856
  children: /* @__PURE__ */ jsx(MenuItem, { className: "logout", children: "Logout" })
@@ -4786,10 +4885,7 @@ var Header = ({
4786
4885
  LoginPopupComponent && showLoginPopup && /* @__PURE__ */ jsx(
4787
4886
  LoginPopupComponent,
4788
4887
  {
4789
- onClose: () => {
4790
- setShowLoginPopup(false);
4791
- setLoginPopupInitialView(void 0);
4792
- },
4888
+ onClose: handleLoginPopupClose,
4793
4889
  initialView: loginPopupInitialView
4794
4890
  }
4795
4891
  )
@@ -5317,6 +5413,7 @@ var OTP_INPUT_LENGTH = 6;
5317
5413
  var LoginPopup = ({
5318
5414
  onClose,
5319
5415
  onOpenEarlyAccess,
5416
+ onWalletLogin,
5320
5417
  isAuthenticated,
5321
5418
  currentUser,
5322
5419
  onSendEmailCode,
@@ -5341,38 +5438,74 @@ var LoginPopup = ({
5341
5438
  const [fundingLoading, setFundingLoading] = useState(false);
5342
5439
  const [fundingError, setFundingError] = useState("");
5343
5440
  const suppressAutoCloseRef = React5__default.useRef(false);
5441
+ useEffect(() => {
5442
+ console.log("[LoginTrace][Popup] mounted");
5443
+ return () => console.log("[LoginTrace][Popup] unmounted");
5444
+ }, []);
5445
+ useEffect(() => {
5446
+ console.log("[LoginTrace][Popup] view updated", { view });
5447
+ }, [view]);
5448
+ useEffect(() => {
5449
+ console.log("[LoginTrace][Popup] auth props updated", { isAuthenticated, hasUser: Boolean(currentUser) });
5450
+ }, [isAuthenticated, currentUser]);
5344
5451
  useEffect(() => {
5345
5452
  if (typeof initialView === "string") {
5453
+ console.log("[LoginTrace][Popup] initialView prop changed", { initialView });
5346
5454
  setView(initialView);
5347
5455
  }
5348
5456
  }, [initialView]);
5349
5457
  useEffect(() => {
5350
5458
  if (!autoCloseOnAuth) {
5459
+ console.log("[LoginTrace][Popup] autoClose disabled", { autoCloseOnAuth, view });
5351
5460
  return;
5352
5461
  }
5353
5462
  if (suppressAutoCloseRef.current) {
5463
+ console.log("[LoginTrace][Popup] autoClose suppressed", { view });
5354
5464
  return;
5355
5465
  }
5356
5466
  if (view === "kyc" || view === "kyc-success" || view === "kyc-failed" || view === "funding") {
5467
+ console.log("[LoginTrace][Popup] autoClose skipped due to onboarding view", { view });
5357
5468
  return;
5358
5469
  }
5470
+ console.log("[LoginTrace][Popup] autoClose effect evaluating", {
5471
+ autoCloseOnAuth,
5472
+ isAuthenticated,
5473
+ hasUser: Boolean(currentUser),
5474
+ view
5475
+ });
5359
5476
  if (isAuthenticated || currentUser) {
5477
+ console.log("[LoginTrace][Popup] autoClose triggered", { isAuthenticated, hasUser: Boolean(currentUser), view });
5360
5478
  onClose();
5361
5479
  }
5362
5480
  }, [autoCloseOnAuth, currentUser, isAuthenticated, onClose, view]);
5363
- const handleWalletLogin = () => {
5481
+ const handleWalletLogin = async () => {
5482
+ console.log("[LoginTrace][Popup] Wallet login clicked, onWalletLogin:", !!onWalletLogin);
5483
+ if (onWalletLogin) {
5484
+ try {
5485
+ console.log("[LoginTrace][Popup] Calling onWalletLogin...");
5486
+ await onWalletLogin();
5487
+ console.log("[LoginTrace][Popup] onWalletLogin completed, closing popup");
5488
+ onClose();
5489
+ return;
5490
+ } catch (err) {
5491
+ console.error("[LoginTrace][Popup] Wallet login failed", err);
5492
+ }
5493
+ }
5494
+ console.log("[LoginTrace][Popup] No onWalletLogin handler, closing popup");
5364
5495
  onClose();
5365
5496
  if (onOpenEarlyAccess) {
5366
5497
  onOpenEarlyAccess();
5367
5498
  }
5368
5499
  };
5369
5500
  const handleEmailClick = (signUp = false) => {
5501
+ console.log("[LoginTrace][Popup] handleEmailClick", { signUp });
5370
5502
  setIsSignUp(signUp);
5371
5503
  setView("email");
5372
5504
  setError("");
5373
5505
  };
5374
5506
  const handleSendCode = async (event) => {
5375
5507
  event?.preventDefault();
5508
+ console.log("[LoginTrace][Popup] handleSendCode invoked", { email, isSignUp, handle, eventType: event?.type });
5376
5509
  if (!email || !email.includes("@")) {
5377
5510
  setError("Please enter a valid email address");
5378
5511
  return;
@@ -5385,13 +5518,15 @@ var LoginPopup = ({
5385
5518
  setError("");
5386
5519
  const normalizedHandle = isSignUp ? handle.trim() : void 0;
5387
5520
  try {
5521
+ console.log("[LoginTrace][Popup] Attempting demo login fallback", { hasDemoHandler: Boolean(onDemoLogin) });
5388
5522
  const demoResult = await onDemoLogin?.(email, normalizedHandle ?? null);
5389
5523
  if (demoResult && demoResult.success) {
5524
+ console.log("[LoginTrace][Popup] Demo login succeeded, skipping OTP flow");
5390
5525
  setLoading(false);
5391
5526
  return;
5392
5527
  }
5393
5528
  } catch (err) {
5394
- console.warn("Demo login failed, attempting email OTP", err);
5529
+ console.warn("[LoginTrace][Popup] Demo login failed, attempting email OTP", err);
5395
5530
  }
5396
5531
  if (!onSendEmailCode) {
5397
5532
  setError("Email authentication is not configured for this popup.");
@@ -5399,10 +5534,13 @@ var LoginPopup = ({
5399
5534
  return;
5400
5535
  }
5401
5536
  try {
5537
+ console.log("[LoginTrace][Popup] Calling onSendEmailCode", { email, isSignUp, normalizedHandle });
5402
5538
  await onSendEmailCode({ email, isSignUp, handle: normalizedHandle ?? null });
5539
+ console.log("[LoginTrace][Popup] onSendEmailCode resolved, switching to OTP view");
5403
5540
  setView("otp");
5404
5541
  setOtp(Array(OTP_INPUT_LENGTH).fill(""));
5405
5542
  } catch (err) {
5543
+ console.error("[LoginTrace][Popup] onSendEmailCode threw", err);
5406
5544
  setError(err instanceof Error ? err.message : "Failed to send verification code");
5407
5545
  } finally {
5408
5546
  setLoading(false);
@@ -5435,9 +5573,32 @@ var LoginPopup = ({
5435
5573
  document.getElementById(`otp-${index - 1}`)?.focus();
5436
5574
  }
5437
5575
  };
5576
+ const handleOTPInput = (index, event) => {
5577
+ const rawValue = event.currentTarget.value ?? "";
5578
+ const nativeEvent = event.nativeEvent;
5579
+ const isPasteLike = nativeEvent?.inputType === "insertFromPaste" || rawValue.length > 1;
5580
+ if (isPasteLike) {
5581
+ handleOTPChange(index, rawValue);
5582
+ }
5583
+ };
5584
+ const handleOTPPaste = (event) => {
5585
+ event.preventDefault();
5586
+ const pasted = event.clipboardData?.getData("text") ?? "";
5587
+ const digits = pasted.replace(/\D/g, "").slice(0, OTP_INPUT_LENGTH).split("");
5588
+ if (digits.length === 0) return;
5589
+ const next = Array.from({ length: OTP_INPUT_LENGTH }, (_, i) => digits[i] ?? "");
5590
+ setOtp(next);
5591
+ const lastIndex = Math.min(digits.length, OTP_INPUT_LENGTH) - 1;
5592
+ if (lastIndex >= 0) {
5593
+ requestAnimationFrame(() => {
5594
+ document.getElementById(`otp-${lastIndex}`)?.focus();
5595
+ });
5596
+ }
5597
+ };
5438
5598
  const handleVerifyCode = async (event) => {
5439
5599
  event.preventDefault();
5440
5600
  const code = otp.join("");
5601
+ console.log("[LoginTrace][Popup] handleVerifyCode", { codeLength: code.length, isSignUp });
5441
5602
  if (code.length !== OTP_INPUT_LENGTH) {
5442
5603
  setError("Please enter the 6-digit code");
5443
5604
  return;
@@ -5452,13 +5613,16 @@ var LoginPopup = ({
5452
5613
  suppressAutoCloseRef.current = true;
5453
5614
  }
5454
5615
  try {
5616
+ console.log("[LoginTrace][Popup] Calling onVerifyEmailCode");
5455
5617
  await onVerifyEmailCode({ code, email });
5456
5618
  if (isSignUp) {
5619
+ console.log("[LoginTrace][Popup] Signup OTP verified, moving to KYC view");
5457
5620
  setView("kyc");
5458
5621
  setLoading(false);
5459
5622
  return;
5460
5623
  }
5461
5624
  } catch (err) {
5625
+ console.error("[LoginTrace][Popup] onVerifyEmailCode threw", err);
5462
5626
  suppressAutoCloseRef.current = false;
5463
5627
  setError(err instanceof Error ? err.message : "Invalid verification code");
5464
5628
  } finally {
@@ -5643,6 +5807,9 @@ var LoginPopup = ({
5643
5807
  value: digit,
5644
5808
  onChange: (event) => handleOTPChange(index, event.target.value),
5645
5809
  onKeyDown: (event) => handleOTPKeyDown(index, event),
5810
+ onInput: (event) => handleOTPInput(index, event),
5811
+ onPaste: handleOTPPaste,
5812
+ autoComplete: index === 0 ? "one-time-code" : "off",
5646
5813
  autoFocus: index === 0
5647
5814
  },
5648
5815
  index
@@ -6699,27 +6866,55 @@ var PriceChange = styled23.span`
6699
6866
  gap: 0.35rem;
6700
6867
  color: ${(props) => props.$isPositive == null ? "var(--color-text-secondary, rgba(255, 255, 255, 0.6))" : props.$isPositive ? "var(--color-positive, #0ecb81)" : "var(--color-negative, #f6465d)"};
6701
6868
  `;
6702
- function PropertyOverview({ propertyName: _propertyName, location: _location, midPrice: _midPrice, onTradeClick: _onTradeClick }) {
6869
+ function PropertyOverview({
6870
+ propertyName: _propertyName,
6871
+ location: _location,
6872
+ midPrice: _midPrice,
6873
+ onTradeClick: _onTradeClick,
6874
+ overviewData,
6875
+ minimumParticipation,
6876
+ bedrooms,
6877
+ bathrooms,
6878
+ carSpaces,
6879
+ propertyTypeLabel
6880
+ }) {
6881
+ const description = overviewData?.description ?? "N/A";
6882
+ const tokensIssued = overviewData?.tokensIssued ?? null;
6883
+ const offeringValuation = overviewData?.offeringValuation ?? null;
6884
+ const weeklyRent = overviewData?.weeklyRent ?? null;
6885
+ const indicativeListing = overviewData?.indicativeListing ?? "N/A";
6886
+ const minParticipationValue = minimumParticipation ?? overviewData?.minimumParticipation ?? null;
6887
+ const landSize = overviewData?.landSizeSqm ?? null;
6888
+ const buildingSize = overviewData?.buildingSizeSqm ?? null;
6889
+ const propertyType = propertyTypeLabel ?? overviewData?.propertyType ?? "N/A";
6890
+ overviewData?.yearBuilt ?? null;
6891
+ const ownership = overviewData?.ownership ?? "N/A";
6892
+ const zoning = overviewData?.zoning ?? "N/A";
6893
+ const levels = overviewData?.levels ?? null;
6894
+ const daStatus = overviewData?.daStatus ?? "N/A";
6895
+ const unitPrice = tokensIssued && offeringValuation ? offeringValuation / tokensIssued : null;
6896
+ const formattedPropertyType = propertyType !== "N/A" ? propertyType.charAt(0).toUpperCase() + propertyType.slice(1).toLowerCase() : "N/A";
6703
6897
  return /* @__PURE__ */ jsxs(Fragment, { children: [
6704
6898
  /* @__PURE__ */ jsxs(TwoColGrid, { children: [
6705
6899
  /* @__PURE__ */ jsxs(Section, { children: [
6706
6900
  /* @__PURE__ */ jsx(SectionHeading, { children: "About This Property" }),
6707
- /* @__PURE__ */ jsxs(BodyText, { children: [
6708
- "Musgrave is Mosman's oldest mansion. Built in 1880 and meticulously maintained for over 140 years. This is not just property - it's legacy.",
6709
- /* @__PURE__ */ jsx("br", {}),
6710
- /* @__PURE__ */ jsx("br", {}),
6711
- "Assets like this are irreplaceable. Pre-Federation sandstone architecture of this calibre simply cannot be recreated. With fewer than a handful of comparable estates remaining, scarcity drives enduring value."
6712
- ] })
6901
+ /* @__PURE__ */ jsx(BodyText, { children: description === "N/A" ? description : description.split("\n\n").map((paragraph, i) => /* @__PURE__ */ jsxs("span", { children: [
6902
+ paragraph,
6903
+ i < description.split("\n\n").length - 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
6904
+ /* @__PURE__ */ jsx("br", {}),
6905
+ /* @__PURE__ */ jsx("br", {})
6906
+ ] })
6907
+ ] }, i)) })
6713
6908
  ] }),
6714
6909
  /* @__PURE__ */ jsxs(Section, { children: [
6715
6910
  /* @__PURE__ */ jsx(SectionHeading, { children: "The Offering" }),
6716
6911
  /* @__PURE__ */ jsx(OfferingGrid, { children: [
6717
- { label: "Units Issued", value: "50,000", gold: false },
6718
- { label: "Issue Price", value: "$250 / Unit", gold: true },
6719
- { label: "Implied Value", value: "$26,000,000", gold: false },
6720
- { label: "Minimum Participation", value: "$20,000", gold: false },
6721
- { label: "Est. Cash Flow", value: "$6000/wk", gold: true },
6722
- { label: "Indicative Listing Date", value: "MAY 2026", gold: false }
6912
+ { label: "Units Issued", value: tokensIssued?.toLocaleString() ?? "-", gold: false },
6913
+ { label: "Issue Price", value: unitPrice ? `$${unitPrice.toFixed(2)} / Unit` : "-", gold: true },
6914
+ { label: "Implied Value", value: offeringValuation ? `$${offeringValuation.toLocaleString()}` : "-", gold: false },
6915
+ { label: "Minimum Participation", value: minParticipationValue != null ? `$${minParticipationValue.toLocaleString()}` : "-", gold: false },
6916
+ { label: "Est. Cash Flow", value: weeklyRent ? `$${weeklyRent.toLocaleString()}/wk` : "-", gold: true },
6917
+ { label: "Indicative Listing Date", value: indicativeListing, gold: false }
6723
6918
  ].map(({ label, value, gold }) => /* @__PURE__ */ jsxs(OfferingItem, { children: [
6724
6919
  /* @__PURE__ */ jsx(OfferingLabel, { children: label }),
6725
6920
  /* @__PURE__ */ jsx(OfferingValue, { $gold: gold, children: value })
@@ -6732,10 +6927,10 @@ function PropertyOverview({ propertyName: _propertyName, location: _location, mi
6732
6927
  /* @__PURE__ */ jsx(AssetDetailsTitle, { children: "Asset Details" })
6733
6928
  ] }),
6734
6929
  /* @__PURE__ */ jsx(StatGrid, { children: [
6735
- { label: "Bedrooms", value: "6", icon: "\u{1F6CF}\uFE0F" },
6736
- { label: "Bathrooms", value: "6", icon: "\u{1F6BF}" },
6737
- { type: "dual", label1: "Land", value1: "1,862", label2: "Floor", value2: "700", unit: "sqm", highlight: true },
6738
- { label: "Car Spaces", value: "6", icon: "\u{1F697}" }
6930
+ { label: "Bedrooms", value: bedrooms != null ? bedrooms.toString() : "-", icon: "\u{1F6CF}\uFE0F" },
6931
+ { label: "Bathrooms", value: bathrooms != null ? bathrooms.toString() : "-", icon: "\u{1F6BF}" },
6932
+ { type: "dual", label1: "Land", value1: landSize?.toString() ?? "-", label2: "Floor", value2: buildingSize?.toString() ?? "-", unit: "sqm", highlight: true },
6933
+ { label: "Car Spaces", value: carSpaces != null ? carSpaces.toString() : "-", icon: "\u{1F697}" }
6739
6934
  ].map((stat, i) => /* @__PURE__ */ jsx(StatCard, { $highlight: !!stat.highlight, children: stat.type === "dual" ? /* @__PURE__ */ jsxs(DualStatInner, { children: [
6740
6935
  /* @__PURE__ */ jsxs(DualStatCol, { children: [
6741
6936
  /* @__PURE__ */ jsx(StatLabel, { $gold: true, children: stat.label1 }),
@@ -6757,14 +6952,14 @@ function PropertyOverview({ propertyName: _propertyName, location: _location, mi
6757
6952
  /* @__PURE__ */ jsx(StatBigValue, { $gold: !!stat.highlight, children: stat.value })
6758
6953
  ] }) }, i)) }),
6759
6954
  /* @__PURE__ */ jsx(DetailTable, { children: /* @__PURE__ */ jsx(DetailTableGrid, { children: [
6760
- { label: "Last Sale", value: "$13M (2021)" },
6761
- { label: "Suburb Median", value: "$7M" },
6762
- { label: "Replication Cost of Architecture", value: "$7M" },
6763
- { label: "DA Status", value: "In Progress", status: "progress" },
6764
- { label: "Property Type", value: "Heritage Home" },
6765
- { label: "Ownership", value: "Freehold" },
6766
- { label: "Zoning", value: "R2 Low Density" },
6767
- { label: "Levels", value: "3" }
6955
+ { label: "Last Sale", value: "-" },
6956
+ { label: "Suburb Median", value: "-" },
6957
+ { label: "Replication Cost of Architecture", value: "-" },
6958
+ { label: "DA Status", value: daStatus, status: daStatus.toLowerCase() === "approved" ? "success" : "progress" },
6959
+ { label: "Property Type", value: formattedPropertyType },
6960
+ { label: "Ownership", value: ownership ?? "N/A" },
6961
+ { label: "Zoning", value: zoning ?? "N/A" },
6962
+ { label: "Levels", value: levels?.toString() ?? "N/A" }
6768
6963
  ].map((item, i) => /* @__PURE__ */ jsxs(DetailCell, { $borderBottom: i < 4, $borderRight: (i + 1) % 4 !== 0, children: [
6769
6964
  /* @__PURE__ */ jsx(DetailCellLabel, { children: item.label }),
6770
6965
  /* @__PURE__ */ jsxs(DetailCellValue, { $status: item.status, children: [
@@ -7650,7 +7845,7 @@ var DocIcon = () => /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", vie
7650
7845
  /* @__PURE__ */ jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
7651
7846
  /* @__PURE__ */ jsx("polyline", { points: "10 9 9 9 8 9" })
7652
7847
  ] });
7653
- var docs = [
7848
+ var fallbackDocs = [
7654
7849
  { href: "/documents/musgrave-valuation-report.pdf", label: "Valuation Report" },
7655
7850
  { href: "/documents/musgrave-offering-material.pdf", label: "Offering Material" },
7656
7851
  { href: "/documents/musgrave-mortgage-agreement.pdf", label: "Mortgage Agreement" },
@@ -7659,13 +7854,26 @@ var docs = [
7659
7854
  { href: "/documents/musgrave-risk-disclosure.pdf", label: "Risk Disclosure Statement" },
7660
7855
  { href: "/documents/musgrave-building-inspection.pdf", label: "Building & Pest Inspection Report" }
7661
7856
  ];
7662
- function PropertyDocuments() {
7857
+ function PropertyDocuments({ documentsData }) {
7858
+ const backendDocuments = Array.isArray(documentsData?.documents) ? documentsData.documents : null;
7859
+ const hasBackendDocuments = !!backendDocuments?.length;
7860
+ const documents = hasBackendDocuments ? backendDocuments : fallbackDocs.map((doc) => ({
7861
+ title: doc.label,
7862
+ documentUrl: doc.href
7863
+ }));
7663
7864
  return /* @__PURE__ */ jsxs(Section2, { children: [
7664
7865
  /* @__PURE__ */ jsx(SectionHeading2, { children: "Investment Documents" }),
7665
- /* @__PURE__ */ jsx(DocList, { children: docs.map(({ href, label }) => /* @__PURE__ */ jsx(DocItem, { children: /* @__PURE__ */ jsxs(DocLink, { href, target: "_blank", rel: "noopener noreferrer", children: [
7666
- /* @__PURE__ */ jsx(DocIconWrapper, { children: /* @__PURE__ */ jsx(DocIcon, {}) }),
7667
- label
7668
- ] }) }, href)) })
7866
+ /* @__PURE__ */ jsx(DocList, { children: documents.map(({ documentUrl, title }) => {
7867
+ const isAvailable = Boolean(documentUrl);
7868
+ return /* @__PURE__ */ jsx(DocItem, { children: hasBackendDocuments && isAvailable ? /* @__PURE__ */ jsxs(DocLink, { href: documentUrl, target: "_blank", rel: "noopener noreferrer", children: [
7869
+ /* @__PURE__ */ jsx(DocIconWrapper, { children: /* @__PURE__ */ jsx(DocIcon, {}) }),
7870
+ title
7871
+ ] }) : /* @__PURE__ */ jsxs(DocItemDisabled, { children: [
7872
+ /* @__PURE__ */ jsx(DocIconWrapper, { children: /* @__PURE__ */ jsx(DocIcon, {}) }),
7873
+ title,
7874
+ /* @__PURE__ */ jsx(ComingSoonBadge, { children: "Coming Soon" })
7875
+ ] }) }, `${title}-${documentUrl ?? "pending"}`);
7876
+ }) })
7669
7877
  ] });
7670
7878
  }
7671
7879
  var Section2 = styled23.section`
@@ -7709,11 +7917,29 @@ var DocLink = styled23.a`
7709
7917
  color: var(--color-accent);
7710
7918
  }
7711
7919
  `;
7920
+ var DocItemDisabled = styled23.div`
7921
+ display: flex;
7922
+ align-items: center;
7923
+ color: var(--color-text-secondary);
7924
+ cursor: not-allowed;
7925
+ opacity: 0.6;
7926
+ `;
7712
7927
  var DocIconWrapper = styled23.span`
7713
7928
  margin-right: 0.75rem;
7714
7929
  flex-shrink: 0;
7715
7930
  color: var(--color-text-secondary);
7716
7931
  `;
7932
+ var ComingSoonBadge = styled23.span`
7933
+ margin-left: auto;
7934
+ padding: 0.25rem 0.5rem;
7935
+ background: rgba(212, 175, 55, 0.1);
7936
+ color: #D4AF37;
7937
+ border-radius: 0.25rem;
7938
+ font-size: 0.7rem;
7939
+ font-weight: 500;
7940
+ text-transform: uppercase;
7941
+ letter-spacing: 0.05em;
7942
+ `;
7717
7943
  var formatIsoDate = (value) => {
7718
7944
  const parsed = new Date(value);
7719
7945
  if (Number.isNaN(parsed.getTime())) return value;
@@ -8000,7 +8226,7 @@ function AssetSelectorBar({ propertyName, tokenPrice, offeringValuation }) {
8000
8226
  /* @__PURE__ */ jsxs(SelectorMetrics, { children: [
8001
8227
  /* @__PURE__ */ jsxs("div", { children: [
8002
8228
  /* @__PURE__ */ jsx(MetricLabel, { children: "Unit Price" }),
8003
- /* @__PURE__ */ jsxs(MetricValue, { accent: true, children: [
8229
+ /* @__PURE__ */ jsxs(MetricValue, { $accent: true, children: [
8004
8230
  "$",
8005
8231
  tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
8006
8232
  ] })
@@ -8095,7 +8321,7 @@ var MetricLabel = styled23.span`
8095
8321
  var MetricValue = styled23.span`
8096
8322
  font-size: 1.1rem;
8097
8323
  font-weight: 700;
8098
- color: ${(p) => p.accent ? "#D4AF37" : "#fff"};
8324
+ color: ${(p) => p.$accent ? "#D4AF37" : "#fff"};
8099
8325
  `;
8100
8326
  var Separator = styled23.span`
8101
8327
  font-size: 1rem;
@@ -8214,7 +8440,7 @@ function OfferingProgressCard({
8214
8440
  /* @__PURE__ */ jsx("span", { children: "\u24D8" })
8215
8441
  ] }),
8216
8442
  /* @__PURE__ */ jsxs(LivePercent, { children: [
8217
- percentSold.toFixed(1),
8443
+ percentSold < 0.1 && percentSold > 0 ? percentSold.toFixed(3) : percentSold.toFixed(1),
8218
8444
  "%",
8219
8445
  /* @__PURE__ */ jsx("span", { children: "\u2191" })
8220
8446
  ] })
@@ -8567,6 +8793,7 @@ function OrderPanel({
8567
8793
  statusLabel,
8568
8794
  statusColor,
8569
8795
  ipoStarted,
8796
+ isAuthenticated,
8570
8797
  tokenPrice,
8571
8798
  feeRate,
8572
8799
  supplyToSell,
@@ -8584,10 +8811,14 @@ function OrderPanel({
8584
8811
  setSliderValue,
8585
8812
  setManualOrderAmount,
8586
8813
  onOrderButtonClick,
8814
+ onSignInClick,
8587
8815
  orderButtonText,
8588
8816
  isOrderButtonDisabled,
8589
8817
  hasInsufficientFunds,
8590
- onPlaceAnotherOrder
8818
+ onPlaceAnotherOrder,
8819
+ onDeposit,
8820
+ tokenDisplayName,
8821
+ tokenSymbol
8591
8822
  }) {
8592
8823
  const [payInputValue, setPayInputValue] = useState("");
8593
8824
  const [receiveInputValue, setReceiveInputValue] = useState("");
@@ -8596,11 +8827,14 @@ function OrderPanel({
8596
8827
  const handlePayBlur = () => {
8597
8828
  setIsPayInputFocused(false);
8598
8829
  const parsed = parseInt(payInputValue.replace(/[^0-9]/g, ""), 10) || 0;
8599
- if (parsed > availableBalance) {
8600
- setManualOrderAmount(parsed);
8830
+ if (parsed <= 0) {
8831
+ setManualOrderAmount(null);
8832
+ setSliderValue(0);
8833
+ } else if (parsed >= availableBalance) {
8834
+ setManualOrderAmount(null);
8601
8835
  setSliderValue(100);
8602
8836
  } else {
8603
- setManualOrderAmount(null);
8837
+ setManualOrderAmount(parsed);
8604
8838
  const ratio = availableBalance === 0 ? 0 : Math.round(Math.max(0, parsed / availableBalance * 100));
8605
8839
  setSliderValue(ratio);
8606
8840
  }
@@ -8609,11 +8843,14 @@ function OrderPanel({
8609
8843
  setIsReceiveInputFocused(false);
8610
8844
  const parsed = parseFloat(receiveInputValue) || 0;
8611
8845
  const newOrderTotal = Math.round(parsed * tokenPrice);
8612
- if (newOrderTotal > availableBalance) {
8613
- setManualOrderAmount(newOrderTotal);
8846
+ if (newOrderTotal <= 0) {
8847
+ setManualOrderAmount(null);
8848
+ setSliderValue(0);
8849
+ } else if (newOrderTotal >= availableBalance) {
8850
+ setManualOrderAmount(null);
8614
8851
  setSliderValue(100);
8615
8852
  } else {
8616
- setManualOrderAmount(null);
8853
+ setManualOrderAmount(newOrderTotal);
8617
8854
  const ratio = availableBalance === 0 ? 0 : Math.round(Math.max(0, newOrderTotal / availableBalance * 100));
8618
8855
  setSliderValue(ratio);
8619
8856
  }
@@ -8639,10 +8876,10 @@ function OrderPanel({
8639
8876
  ] }),
8640
8877
  /* @__PURE__ */ jsxs("div", { className: "success-body", children: [
8641
8878
  [
8642
- { label: "Units Acquired", value: `${lastOrderDetails?.tokens?.toFixed(2) || "0.00"} MUS` },
8879
+ { label: "Units Acquired", value: `${lastOrderDetails?.tokens?.toFixed(2) || "0.00"} ${tokenSymbol}` },
8643
8880
  { label: "Price Per Unit", value: `$${tokenPrice.toFixed(2)}` },
8644
8881
  {
8645
- label: "Musgrave Exposure",
8882
+ label: `${tokenDisplayName} Exposure`,
8646
8883
  value: `${((lastOrderDetails?.tokens ?? 0) / supplyToSell * 100).toFixed(3)}%`
8647
8884
  }
8648
8885
  ].map((row) => /* @__PURE__ */ jsxs("div", { className: "success-row", children: [
@@ -8683,7 +8920,7 @@ function OrderPanel({
8683
8920
  }
8684
8921
  }
8685
8922
  ),
8686
- /* @__PURE__ */ jsx("span", { children: "AUD" })
8923
+ /* @__PURE__ */ jsx("span", { children: "USDC" })
8687
8924
  ] }),
8688
8925
  /* @__PURE__ */ jsx(QuickSelectRow, { children: [25, 50, 75, 100].map((pct) => /* @__PURE__ */ jsxs(
8689
8926
  "button",
@@ -8704,13 +8941,19 @@ function OrderPanel({
8704
8941
  ] }),
8705
8942
  /* @__PURE__ */ jsxs(FundsRow, { children: [
8706
8943
  /* @__PURE__ */ jsxs("span", { children: [
8707
- "Available Funds: ",
8708
- /* @__PURE__ */ jsxs("strong", { children: [
8709
- "$",
8710
- availableBalance.toLocaleString()
8711
- ] })
8944
+ "Available Funds:",
8945
+ " ",
8946
+ /* @__PURE__ */ jsx("strong", { children: isAuthenticated ? `$${availableBalance.toLocaleString()}` : "\u2014" })
8712
8947
  ] }),
8713
- /* @__PURE__ */ jsx(DepositButton, { type: "button", children: "+ Deposit" })
8948
+ /* @__PURE__ */ jsx(
8949
+ DepositButton,
8950
+ {
8951
+ type: "button",
8952
+ onClick: isAuthenticated ? onDeposit : void 0,
8953
+ disabled: !isAuthenticated,
8954
+ children: "+ Deposit"
8955
+ }
8956
+ )
8714
8957
  ] }),
8715
8958
  /* @__PURE__ */ jsx(Divider2, { children: "\u2193" }),
8716
8959
  /* @__PURE__ */ jsxs(Card2, { children: [
@@ -8742,7 +8985,7 @@ function OrderPanel({
8742
8985
  }
8743
8986
  }
8744
8987
  ),
8745
- /* @__PURE__ */ jsx("span", { children: "MUSGRAVE" })
8988
+ /* @__PURE__ */ jsx("span", { children: tokenDisplayName })
8746
8989
  ] })
8747
8990
  ] }),
8748
8991
  /* @__PURE__ */ jsxs(OrderSummary, { children: [
@@ -8758,7 +9001,8 @@ function OrderPanel({
8758
9001
  /* @__PURE__ */ jsx("span", { children: "Buying" }),
8759
9002
  /* @__PURE__ */ jsxs("strong", { children: [
8760
9003
  tokenQuantity.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }),
8761
- " units"
9004
+ " ",
9005
+ tokenSymbol
8762
9006
  ] })
8763
9007
  ] }),
8764
9008
  /* @__PURE__ */ jsxs(SummaryRow, { children: [
@@ -8769,7 +9013,8 @@ function OrderPanel({
8769
9013
  ] }),
8770
9014
  /* @__PURE__ */ jsxs("strong", { children: [
8771
9015
  feeInTokens.toFixed(2),
8772
- " units"
9016
+ " ",
9017
+ tokenSymbol
8773
9018
  ] })
8774
9019
  ] }),
8775
9020
  /* @__PURE__ */ jsxs(SummaryTotal, { children: [
@@ -8777,7 +9022,7 @@ function OrderPanel({
8777
9022
  /* @__PURE__ */ jsxs("strong", { children: [
8778
9023
  "$",
8779
9024
  orderTotal.toLocaleString(),
8780
- " AUD"
9025
+ " USDC"
8781
9026
  ] })
8782
9027
  ] })
8783
9028
  ] })
@@ -8788,32 +9033,46 @@ function OrderPanel({
8788
9033
  type: "button",
8789
9034
  disabled: isOrderButtonDisabled,
8790
9035
  "data-green": orderButtonText === "Place Order",
8791
- onClick: onOrderButtonClick,
9036
+ onClick: () => {
9037
+ if (!isAuthenticated) {
9038
+ onSignInClick();
9039
+ return;
9040
+ }
9041
+ onOrderButtonClick();
9042
+ },
8792
9043
  children: orderButtonText
8793
9044
  }
8794
9045
  ),
8795
- /* @__PURE__ */ jsxs(BalanceCards, { children: [
9046
+ isAuthenticated && /* @__PURE__ */ jsxs(BalanceCards, { children: [
8796
9047
  /* @__PURE__ */ jsxs(BalanceCard, { children: [
8797
9048
  /* @__PURE__ */ jsx(BalanceLabel, { children: "Available to Invest" }),
8798
9049
  /* @__PURE__ */ jsxs(BalanceValue, { children: [
8799
9050
  "$",
8800
9051
  availableBalance.toLocaleString()
8801
9052
  ] }),
8802
- /* @__PURE__ */ jsx(BalanceAction, { children: "+ Deposit" })
9053
+ /* @__PURE__ */ jsx(BalanceAction, { onClick: onDeposit, style: { cursor: onDeposit ? "pointer" : "default" }, children: "+ Deposit" })
8803
9054
  ] }),
8804
9055
  /* @__PURE__ */ jsxs(BalanceCard, { children: [
8805
- /* @__PURE__ */ jsx(BalanceLabel, { children: "Musgrave Owned" }),
9056
+ /* @__PURE__ */ jsx(BalanceLabel, { children: `${tokenDisplayName} Owned` }),
8806
9057
  /* @__PURE__ */ jsxs(BalanceValue, { children: [
8807
9058
  displayedOwnedTokens.toFixed(2),
9059
+ " ",
9060
+ tokenSymbol,
8808
9061
  ownedTokensJustUpdated && /* @__PURE__ */ jsxs("span", { children: [
8809
9062
  "+",
8810
- lastOrderQuantity.toFixed(2)
9063
+ lastOrderQuantity.toFixed(2),
9064
+ " ",
9065
+ tokenSymbol
8811
9066
  ] })
8812
9067
  ] }),
8813
9068
  /* @__PURE__ */ jsxs(BalanceSub, { children: [
8814
9069
  "$",
8815
- (displayedOwnedTokens * tokenPrice).toLocaleString(),
8816
- " \u2022 ",
9070
+ (displayedOwnedTokens * tokenPrice).toLocaleString("en-US", {
9071
+ minimumFractionDigits: 0,
9072
+ maximumFractionDigits: 0
9073
+ }),
9074
+ " ",
9075
+ "\u2022 ",
8817
9076
  (displayedOwnedTokens / supplyToSell * 100).toFixed(3),
8818
9077
  "%"
8819
9078
  ] })
@@ -9431,7 +9690,23 @@ var IframeShield = styled23.div`
9431
9690
  z-index: 1;
9432
9691
  cursor: pointer;
9433
9692
  `;
9434
- function NewsOrdersSection({ newsItems, userSubscription, tokenPrice }) {
9693
+ var SUBSCRIPTIONS_PAGE_SIZE = 6;
9694
+ function NewsOrdersSection({ newsItems, userSubscriptions, tokenPrice }) {
9695
+ const [page, setPage] = useState(0);
9696
+ const totalPages = Math.max(1, Math.ceil(userSubscriptions.length / SUBSCRIPTIONS_PAGE_SIZE));
9697
+ useEffect(() => {
9698
+ if (page > totalPages - 1) {
9699
+ setPage(totalPages - 1);
9700
+ }
9701
+ }, [page, totalPages]);
9702
+ useEffect(() => {
9703
+ setPage(0);
9704
+ }, [userSubscriptions]);
9705
+ const paginatedSubscriptions = useMemo(() => {
9706
+ const start = page * SUBSCRIPTIONS_PAGE_SIZE;
9707
+ return userSubscriptions.slice(start, start + SUBSCRIPTIONS_PAGE_SIZE);
9708
+ }, [page, userSubscriptions]);
9709
+ const hasPagination = userSubscriptions.length > SUBSCRIPTIONS_PAGE_SIZE;
9435
9710
  return /* @__PURE__ */ jsxs(Row2, { children: [
9436
9711
  /* @__PURE__ */ jsxs(TradeNewsPanel, { children: [
9437
9712
  /* @__PURE__ */ jsxs(TradeNewsHeader, { children: [
@@ -9458,34 +9733,57 @@ function NewsOrdersSection({ newsItems, userSubscription, tokenPrice }) {
9458
9733
  ] }),
9459
9734
  /* @__PURE__ */ jsxs(TradeNewsPanel, { children: [
9460
9735
  /* @__PURE__ */ jsxs(TradeNewsHeader, { children: [
9461
- /* @__PURE__ */ jsx("h3", { children: "Your Orders" }),
9462
- /* @__PURE__ */ jsx("span", { children: "Offering Subscriptions" })
9736
+ /* @__PURE__ */ jsxs("div", { children: [
9737
+ /* @__PURE__ */ jsx("h3", { children: "Your Orders" }),
9738
+ /* @__PURE__ */ jsx("span", { children: "Offering Subscriptions" })
9739
+ ] }),
9740
+ hasPagination ? /* @__PURE__ */ jsxs(Pagination, { children: [
9741
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setPage((prev) => Math.max(prev - 1, 0)), disabled: page === 0, children: "Prev" }),
9742
+ /* @__PURE__ */ jsxs("span", { children: [
9743
+ "Page ",
9744
+ page + 1,
9745
+ "/",
9746
+ totalPages
9747
+ ] }),
9748
+ /* @__PURE__ */ jsx(
9749
+ "button",
9750
+ {
9751
+ type: "button",
9752
+ onClick: () => setPage((prev) => Math.min(prev + 1, totalPages - 1)),
9753
+ disabled: page >= totalPages - 1,
9754
+ children: "Next"
9755
+ }
9756
+ )
9757
+ ] }) : null
9463
9758
  ] }),
9464
9759
  /* @__PURE__ */ jsxs(OrdersTable, { children: [
9465
9760
  /* @__PURE__ */ jsx(OrdersHead, { children: ["Date", "Units", "Price", "Total", "Status"].map((h) => /* @__PURE__ */ jsx("div", { children: h }, h)) }),
9466
- userSubscription ? /* @__PURE__ */ jsxs(OrdersRow, { children: [
9467
- /* @__PURE__ */ jsxs("div", { children: [
9468
- new Date(userSubscription.timestamp).toLocaleDateString("en-AU", {
9469
- day: "2-digit",
9470
- month: "short",
9471
- year: "numeric"
9472
- }),
9473
- /* @__PURE__ */ jsx("span", { children: new Date(userSubscription.timestamp).toLocaleTimeString("en-AU", {
9474
- hour: "2-digit",
9475
- minute: "2-digit"
9476
- }) })
9477
- ] }),
9478
- /* @__PURE__ */ jsx("div", { className: "units", children: userSubscription.tokens.toFixed(2) }),
9479
- /* @__PURE__ */ jsxs("div", { children: [
9480
- "$",
9481
- tokenPrice.toFixed(2)
9482
- ] }),
9483
- /* @__PURE__ */ jsxs("div", { className: "total", children: [
9484
- "$",
9485
- userSubscription.value.toLocaleString()
9486
- ] }),
9487
- /* @__PURE__ */ jsx("div", { className: "status", children: "Confirmed" })
9488
- ] }) : /* @__PURE__ */ jsxs(OrdersEmpty, { children: [
9761
+ paginatedSubscriptions.length ? paginatedSubscriptions.map((subscription) => {
9762
+ const subscriptionDate = new Date(subscription.timestamp);
9763
+ return /* @__PURE__ */ jsxs(OrdersRow, { children: [
9764
+ /* @__PURE__ */ jsxs("div", { children: [
9765
+ subscriptionDate.toLocaleDateString("en-AU", {
9766
+ day: "2-digit",
9767
+ month: "short",
9768
+ year: "numeric"
9769
+ }),
9770
+ /* @__PURE__ */ jsx("span", { children: subscriptionDate.toLocaleTimeString("en-AU", {
9771
+ hour: "2-digit",
9772
+ minute: "2-digit"
9773
+ }) })
9774
+ ] }),
9775
+ /* @__PURE__ */ jsx("div", { className: "units", children: subscription.tokens.toFixed(2) }),
9776
+ /* @__PURE__ */ jsxs("div", { children: [
9777
+ "$",
9778
+ tokenPrice.toFixed(2)
9779
+ ] }),
9780
+ /* @__PURE__ */ jsxs("div", { className: "total", children: [
9781
+ "$",
9782
+ subscription.value.toLocaleString()
9783
+ ] }),
9784
+ /* @__PURE__ */ jsx("div", { className: "status", children: subscription.status ?? "Confirmed" })
9785
+ ] }, `${subscription.timestamp}-${subscription.tokens}`);
9786
+ }) : /* @__PURE__ */ jsxs(OrdersEmpty, { children: [
9489
9787
  /* @__PURE__ */ jsx("div", { children: "\u{1F4CB}" }),
9490
9788
  /* @__PURE__ */ jsx("p", { children: "No orders yet" }),
9491
9789
  /* @__PURE__ */ jsx("small", { children: "Subscribe to the IPO above to place your first order" })
@@ -9612,6 +9910,28 @@ var OrdersTable = styled23.div`
9612
9910
  flex: 1;
9613
9911
  overflow: auto;
9614
9912
  `;
9913
+ var Pagination = styled23.div`
9914
+ display: flex;
9915
+ align-items: center;
9916
+ gap: 0.75rem;
9917
+ font-size: 0.75rem;
9918
+ color: var(--color-text-secondary);
9919
+
9920
+ button {
9921
+ border: 1px solid rgba(255,255,255,0.2);
9922
+ background: rgba(255,255,255,0.05);
9923
+ color: #fff;
9924
+ border-radius: 9999px;
9925
+ padding: 0.25rem 0.9rem;
9926
+ font-size: 0.7rem;
9927
+ cursor: pointer;
9928
+ transition: opacity 0.2s;
9929
+ &:disabled {
9930
+ opacity: 0.4;
9931
+ cursor: not-allowed;
9932
+ }
9933
+ }
9934
+ `;
9615
9935
  var OrdersHead = styled23.div`
9616
9936
  display: grid;
9617
9937
  grid-template-columns: 1fr 1fr 1fr 1fr 1.2fr;
@@ -9881,19 +10201,24 @@ var ButtonRow = styled23.div`
9881
10201
  }
9882
10202
  `;
9883
10203
  function PropertyBuy({
9884
- propertyName = "8c Mcleod Street (Musgrave)",
9885
- propertyLocation: propertyLocationLabel = "Mosman, Sydney",
10204
+ propertyName = "Loaf Property",
10205
+ propertyLocation: propertyLocationLabel = "Sydney, NSW",
10206
+ tokenDisplayName = "Property Token",
10207
+ tokenSymbol = "LOAF",
9886
10208
  isAuthenticated,
9887
10209
  onSignIn,
9888
10210
  saleData,
9889
10211
  walletUsdcBalance,
10212
+ walletPropertyTokenBalance,
9890
10213
  onPurchase,
9891
10214
  purchaseStatus = "idle",
9892
- purchaseError
10215
+ purchaseError,
10216
+ onDeposit,
10217
+ initialUserSubscriptions = []
9893
10218
  }) {
9894
10219
  const [sliderValue, setSliderValue] = useState(0);
9895
10220
  const [availableBalance, setAvailableBalance] = useState(walletUsdcBalance ?? 125e3);
9896
- const [userSubscription, setUserSubscription] = useState(null);
10221
+ const [optimisticUserSubscriptions, setOptimisticUserSubscriptions] = useState([]);
9897
10222
  const [manualOrderAmount, setManualOrderAmount] = useState(null);
9898
10223
  const [ownedTokens, setOwnedTokens] = useState(0);
9899
10224
  const [displayedOwnedTokens, setDisplayedOwnedTokens] = useState(0);
@@ -9911,6 +10236,12 @@ function PropertyBuy({
9911
10236
  isNew: false
9912
10237
  }))
9913
10238
  );
10239
+ const resolvedUserSubscriptions = initialUserSubscriptions && initialUserSubscriptions.length > 0 ? initialUserSubscriptions : optimisticUserSubscriptions;
10240
+ useEffect(() => {
10241
+ if (initialUserSubscriptions?.length) {
10242
+ setOptimisticUserSubscriptions([]);
10243
+ }
10244
+ }, [initialUserSubscriptions]);
9914
10245
  const tokenPrice = saleData?.tokenPrice ?? 250;
9915
10246
  const feeRate = (saleData?.feePercent ?? 0.5) / 100;
9916
10247
  const totalSold = saleData?.totalSold ?? 0;
@@ -9933,11 +10264,13 @@ function PropertyBuy({
9933
10264
  setAvailableBalance(walletUsdcBalance);
9934
10265
  }
9935
10266
  }, [walletUsdcBalance]);
9936
- const handleOrderButtonClick = () => {
9937
- if (!isAuthenticated) {
9938
- onSignIn();
9939
- return;
10267
+ useEffect(() => {
10268
+ if (walletPropertyTokenBalance != null) {
10269
+ setOwnedTokens(walletPropertyTokenBalance);
10270
+ setDisplayedOwnedTokens(walletPropertyTokenBalance);
9940
10271
  }
10272
+ }, [walletPropertyTokenBalance]);
10273
+ const handleOrderButtonClick = () => {
9941
10274
  if (!ipoStarted || tokenQuantity === 0) {
9942
10275
  return;
9943
10276
  }
@@ -9982,15 +10315,17 @@ function PropertyBuy({
9982
10315
  setOwnedTokensJustUpdated(true);
9983
10316
  setLastOrderQuantity(tokenAmountInt);
9984
10317
  setTimeout(() => setOwnedTokensJustUpdated(false), 2e3);
9985
- setUserSubscription({
10318
+ const optimisticEntry = {
9986
10319
  propertyName,
9987
- tokenSymbol: "MUS",
10320
+ tokenSymbol,
9988
10321
  tokens: tokenAmountInt,
9989
10322
  value: orderTotal,
9990
10323
  avgPrice: tokenPrice,
9991
10324
  percentOfProperty: estExposure,
9992
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
9993
- });
10325
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10326
+ status: "pending"
10327
+ };
10328
+ setOptimisticUserSubscriptions((prev) => [optimisticEntry, ...prev]);
9994
10329
  setLastOrderDetails({
9995
10330
  tokens: tokenAmountInt,
9996
10331
  total: orderTotal,
@@ -10052,36 +10387,43 @@ function PropertyBuy({
10052
10387
  }
10053
10388
  ),
10054
10389
  /* @__PURE__ */ jsx(VideoActivitySection, { ipoStarted }),
10055
- /* @__PURE__ */ jsx(
10056
- OrderPanel,
10057
- {
10058
- statusLabel,
10059
- statusColor,
10060
- ipoStarted,
10061
- isAuthenticated,
10062
- tokenPrice,
10063
- feeRate,
10064
- supplyToSell,
10065
- availableBalance,
10066
- displayedOwnedTokens,
10067
- ownedTokensJustUpdated,
10068
- lastOrderQuantity,
10069
- orderPlacedSuccess,
10070
- lastOrderDetails,
10071
- tokenQuantity,
10072
- feeInTokens,
10073
- orderTotal,
10074
- sliderValue,
10075
- manualOrderAmount,
10076
- setSliderValue,
10077
- setManualOrderAmount,
10078
- onOrderButtonClick: handleOrderButtonClick,
10079
- orderButtonText: getOrderButtonText(),
10080
- isOrderButtonDisabled: isOrderButtonDisabled(),
10081
- hasInsufficientFunds,
10082
- onPlaceAnotherOrder: () => setOrderPlacedSuccess(false)
10083
- }
10084
- )
10390
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
10391
+ /* @__PURE__ */ jsx(
10392
+ OrderPanel,
10393
+ {
10394
+ statusLabel,
10395
+ statusColor,
10396
+ ipoStarted,
10397
+ tokenDisplayName,
10398
+ tokenSymbol,
10399
+ isAuthenticated,
10400
+ tokenPrice,
10401
+ feeRate,
10402
+ supplyToSell,
10403
+ availableBalance,
10404
+ displayedOwnedTokens,
10405
+ ownedTokensJustUpdated,
10406
+ lastOrderQuantity,
10407
+ orderPlacedSuccess,
10408
+ lastOrderDetails,
10409
+ tokenQuantity,
10410
+ feeInTokens,
10411
+ orderTotal,
10412
+ sliderValue,
10413
+ manualOrderAmount,
10414
+ setSliderValue,
10415
+ setManualOrderAmount,
10416
+ onSignInClick: onSignIn,
10417
+ onOrderButtonClick: handleOrderButtonClick,
10418
+ orderButtonText: getOrderButtonText(),
10419
+ isOrderButtonDisabled: isOrderButtonDisabled(),
10420
+ hasInsufficientFunds,
10421
+ onPlaceAnotherOrder: () => setOrderPlacedSuccess(false),
10422
+ onDeposit
10423
+ }
10424
+ ),
10425
+ purchaseError && /* @__PURE__ */ jsx("div", { style: { marginTop: "0.75rem", padding: "0.75rem 1rem", borderRadius: "8px", background: "rgba(246,70,93,0.1)", border: "1px solid rgba(246,70,93,0.3)", color: "#f6465d", fontSize: "0.8rem", fontWeight: 500 }, children: purchaseError })
10426
+ ] })
10085
10427
  ] }),
10086
10428
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
10087
10429
  /* @__PURE__ */ jsx(GalleryMapSection, { propertyLocation: propertyLocationLabel }),
@@ -10089,7 +10431,7 @@ function PropertyBuy({
10089
10431
  NewsOrdersSection,
10090
10432
  {
10091
10433
  newsItems,
10092
- userSubscription,
10434
+ userSubscriptions: resolvedUserSubscriptions,
10093
10435
  tokenPrice
10094
10436
  }
10095
10437
  )
@@ -12444,7 +12786,192 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
12444
12786
  }
12445
12787
  );
12446
12788
  }
12789
+ var slideIn = keyframes`
12790
+ from { transform: translateX(110%); opacity: 0; }
12791
+ to { transform: translateX(0); opacity: 1; }
12792
+ `;
12793
+ var slideOut = keyframes`
12794
+ from { transform: translateX(0); opacity: 1; }
12795
+ to { transform: translateX(110%); opacity: 0; }
12796
+ `;
12797
+ var progressShrink = keyframes`
12798
+ from { width: 100%; }
12799
+ to { width: 0%; }
12800
+ `;
12801
+ var VARIANT_COLORS = {
12802
+ success: { accent: "#0ecb81", icon: "\u2713" },
12803
+ error: { accent: "#f6465d", icon: "\u2715" },
12804
+ info: { accent: "#E6C656", icon: "\u2139" },
12805
+ pending: { accent: "#7EB3E6", icon: "\u25CC" }
12806
+ };
12807
+ var Wrapper = styled23.div`
12808
+ position: relative;
12809
+ display: flex;
12810
+ flex-direction: column;
12811
+ gap: 0;
12812
+ width: 340px;
12813
+ background: #0d0f1a;
12814
+ border: 1px solid rgba(255, 255, 255, 0.08);
12815
+ border-radius: 10px;
12816
+ overflow: hidden;
12817
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.04);
12818
+ animation: ${({ $exiting }) => $exiting ? css`${slideOut} 0.28s cubic-bezier(0.4,0,1,1) forwards` : css`${slideIn} 0.32s cubic-bezier(0,0,0.2,1) forwards`};
12819
+ pointer-events: all;
12820
+ `;
12821
+ var Body = styled23.div`
12822
+ display: flex;
12823
+ align-items: flex-start;
12824
+ gap: 12px;
12825
+ padding: 14px 16px 12px;
12826
+ `;
12827
+ var IconDot = styled23.div`
12828
+ flex-shrink: 0;
12829
+ width: 28px;
12830
+ height: 28px;
12831
+ border-radius: 50%;
12832
+ background: ${({ $color }) => $color}1a;
12833
+ border: 1px solid ${({ $color }) => $color}55;
12834
+ display: flex;
12835
+ align-items: center;
12836
+ justify-content: center;
12837
+ font-size: 0.75rem;
12838
+ font-weight: 700;
12839
+ color: ${({ $color }) => $color};
12840
+ margin-top: 1px;
12841
+ `;
12842
+ var Content = styled23.div`
12843
+ flex: 1;
12844
+ min-width: 0;
12845
+ `;
12846
+ var Title2 = styled23.p`
12847
+ margin: 0 0 2px;
12848
+ font-size: 0.8rem;
12849
+ font-weight: 600;
12850
+ color: #fff;
12851
+ letter-spacing: 0.01em;
12852
+ `;
12853
+ var Amount = styled23.p`
12854
+ margin: 0 0 6px;
12855
+ font-size: 1.05rem;
12856
+ font-weight: 700;
12857
+ color: #E6C656;
12858
+ letter-spacing: -0.01em;
12859
+ `;
12860
+ var TxRow = styled23.a`
12861
+ display: inline-flex;
12862
+ align-items: center;
12863
+ gap: 5px;
12864
+ font-family: 'IBM Plex Mono', 'Space Mono', monospace;
12865
+ font-size: 0.68rem;
12866
+ color: rgba(255, 255, 255, 0.4);
12867
+ text-decoration: none;
12868
+ transition: color 0.15s;
12869
+ &:hover {
12870
+ color: #7EB3E6;
12871
+ }
12872
+ `;
12873
+ var TxArrow = styled23.span`
12874
+ font-size: 0.6rem;
12875
+ opacity: 0.6;
12876
+ `;
12877
+ var CloseBtn = styled23.button`
12878
+ flex-shrink: 0;
12879
+ background: none;
12880
+ border: none;
12881
+ padding: 2px 4px;
12882
+ cursor: pointer;
12883
+ color: rgba(255, 255, 255, 0.25);
12884
+ font-size: 0.9rem;
12885
+ line-height: 1;
12886
+ transition: color 0.15s;
12887
+ &:hover { color: rgba(255, 255, 255, 0.7); }
12888
+ `;
12889
+ var ProgressBar2 = styled23.div`
12890
+ height: 2px;
12891
+ background: rgba(255, 255, 255, 0.06);
12892
+ position: relative;
12893
+ &::after {
12894
+ content: '';
12895
+ position: absolute;
12896
+ left: 0;
12897
+ top: 0;
12898
+ height: 100%;
12899
+ background: ${({ $color }) => $color};
12900
+ animation: ${css`${progressShrink} ${({ $duration }) => $duration}ms linear forwards`};
12901
+ }
12902
+ `;
12903
+ var Container2 = styled23.div`
12904
+ position: fixed;
12905
+ bottom: 24px;
12906
+ right: 24px;
12907
+ z-index: 9999;
12908
+ display: flex;
12909
+ flex-direction: column-reverse;
12910
+ gap: 10px;
12911
+ pointer-events: none;
12912
+ `;
12913
+ var DEFAULT_EXPLORER = "https://sepolia.basescan.org/tx/";
12914
+ function truncateHash(hash) {
12915
+ return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
12916
+ }
12917
+ function ToastItem({ toast, onDismiss }) {
12918
+ const [exiting, setExiting] = useState(false);
12919
+ const timerRef = useRef(null);
12920
+ const dismiss = useCallback(() => {
12921
+ setExiting(true);
12922
+ setTimeout(() => onDismiss(toast.id), 280);
12923
+ }, [onDismiss, toast.id]);
12924
+ useEffect(() => {
12925
+ const duration2 = toast.duration ?? 6e3;
12926
+ if (duration2 > 0) {
12927
+ timerRef.current = setTimeout(dismiss, duration2);
12928
+ }
12929
+ return () => {
12930
+ if (timerRef.current) clearTimeout(timerRef.current);
12931
+ };
12932
+ }, [dismiss, toast.duration]);
12933
+ const { accent, icon } = VARIANT_COLORS[toast.variant];
12934
+ const duration = toast.duration ?? 6e3;
12935
+ const explorerBase = toast.explorerUrl ?? DEFAULT_EXPLORER;
12936
+ const txUrl = toast.txHash ? `${explorerBase}${toast.txHash}` : void 0;
12937
+ return /* @__PURE__ */ jsxs(Wrapper, { $exiting: exiting, children: [
12938
+ /* @__PURE__ */ jsxs(Body, { children: [
12939
+ /* @__PURE__ */ jsx(IconDot, { $color: accent, children: icon }),
12940
+ /* @__PURE__ */ jsxs(Content, { children: [
12941
+ /* @__PURE__ */ jsx(Title2, { children: toast.title }),
12942
+ toast.amount && /* @__PURE__ */ jsx(Amount, { children: toast.amount }),
12943
+ toast.txHash && txUrl && /* @__PURE__ */ jsxs(TxRow, { href: txUrl, target: "_blank", rel: "noopener noreferrer", children: [
12944
+ truncateHash(toast.txHash),
12945
+ /* @__PURE__ */ jsx(TxArrow, { children: "\u2197" })
12946
+ ] })
12947
+ ] }),
12948
+ /* @__PURE__ */ jsx(CloseBtn, { type: "button", onClick: dismiss, "aria-label": "Dismiss", children: "\u2715" })
12949
+ ] }),
12950
+ duration > 0 && /* @__PURE__ */ jsx(ProgressBar2, { $color: accent, $duration: duration })
12951
+ ] });
12952
+ }
12953
+ var ToastContext = createContext(null);
12954
+ function ToastProvider({ children }) {
12955
+ const [toasts, setToasts] = useState([]);
12956
+ const addToast = useCallback((data) => {
12957
+ const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
12958
+ setToasts((prev) => [...prev, { ...data, id }]);
12959
+ return id;
12960
+ }, []);
12961
+ const dismiss = useCallback((id) => {
12962
+ setToasts((prev) => prev.filter((t) => t.id !== id));
12963
+ }, []);
12964
+ return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
12965
+ children,
12966
+ /* @__PURE__ */ jsx(Container2, { children: toasts.map((t) => /* @__PURE__ */ jsx(ToastItem, { toast: t, onDismiss: dismiss }, t.id)) })
12967
+ ] });
12968
+ }
12969
+ function useToast() {
12970
+ const ctx = useContext(ToastContext);
12971
+ if (!ctx) throw new Error("useToast must be used within a ToastProvider");
12972
+ return ctx;
12973
+ }
12447
12974
 
12448
- export { Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Header, HousePositionSlider, HousePositionSliderMobile, LoafLiquidityBadge, LoafLiquidityLogo, LoginPopup, MobileTradeNav, Orderbook, owner_booking_default as OwnerBooking, PaymentPopup, PortfolioSummary, PriceChart, PropertyBuy, PropertyCompareBar, PropertyDocuments, PropertyHeroHeader, PropertyHistory, PropertyInspectionTimes, PropertyNewsUpdates, PropertyOffers, PropertyOverview, PropertyPhotoGallery, PropertySubheader, PropertyTour, PropertyValuation, TradeConfirmationModal, TradingSlider, YourOrders, badgeVariants, buttonVariants };
12975
+ export { Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Header, HousePositionSlider, HousePositionSliderMobile, LoafLiquidityBadge, LoafLiquidityLogo, LoginPopup, MobileTradeNav, Orderbook, owner_booking_default as OwnerBooking, PaymentPopup, PortfolioSummary, PriceChart, PropertyBuy, PropertyCompareBar, PropertyDocuments, PropertyHeroHeader, PropertyHistory, PropertyInspectionTimes, PropertyNewsUpdates, PropertyOffers, PropertyOverview, PropertyPhotoGallery, PropertySubheader, PropertyTour, PropertyValuation, ToastProvider, TradeConfirmationModal, TradingSlider, YourOrders, badgeVariants, buttonVariants, useToast };
12449
12976
  //# sourceMappingURL=index.mjs.map
12450
12977
  //# sourceMappingURL=index.mjs.map