@loafmarkets/ui 0.1.13 → 0.1.16

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
  ] }),
@@ -4510,10 +4533,22 @@ var Header = ({
4510
4533
  closeMenus();
4511
4534
  console.log("[Header] Add funding selected");
4512
4535
  if (LoginPopupComponent) {
4513
- setLoginPopupInitialView(void 0);
4536
+ setLoginPopupInitialView("funding");
4514
4537
  setShowLoginPopup(true);
4515
4538
  }
4516
4539
  };
4540
+ const handlePortfolioNavigate = (event) => {
4541
+ event?.preventDefault();
4542
+ closeMenus();
4543
+ console.log("[Header] Portfolio selected");
4544
+ if (_onOrdersNavigate) {
4545
+ _onOrdersNavigate();
4546
+ return;
4547
+ }
4548
+ if (onNavigate) {
4549
+ onNavigate("/portfolio");
4550
+ }
4551
+ };
4517
4552
  const userPrimaryLabel = currentUser?.displayName?.trim() || "User";
4518
4553
  const resolveAuthReturnUrl = () => {
4519
4554
  if (getAuthReturnUrl) {
@@ -4725,14 +4760,13 @@ var Header = ({
4725
4760
  ),
4726
4761
  isUserMenuOpen && /* @__PURE__ */ jsxs(DropdownMenu, { className: "user-menu-dropdown", children: [
4727
4762
  /* @__PURE__ */ jsx(
4728
- "div",
4763
+ "button",
4729
4764
  {
4730
- style: {
4731
- padding: "12px 16px",
4732
- borderBottom: "1px solid rgba(255,255,255,0.08)",
4733
- textAlign: "left"
4765
+ type: "button",
4766
+ onClick: (event) => {
4767
+ handlePortfolioNavigate(event);
4734
4768
  },
4735
- children: /* @__PURE__ */ jsx("p", { style: { margin: 0, fontWeight: 600 }, children: userPrimaryLabel })
4769
+ children: /* @__PURE__ */ jsx(MenuItem, { children: "Portfolio" })
4736
4770
  }
4737
4771
  ),
4738
4772
  /* @__PURE__ */ jsx(
@@ -6699,27 +6733,55 @@ var PriceChange = styled23.span`
6699
6733
  gap: 0.35rem;
6700
6734
  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
6735
  `;
6702
- function PropertyOverview({ propertyName: _propertyName, location: _location, midPrice: _midPrice, onTradeClick: _onTradeClick }) {
6736
+ function PropertyOverview({
6737
+ propertyName: _propertyName,
6738
+ location: _location,
6739
+ midPrice: _midPrice,
6740
+ onTradeClick: _onTradeClick,
6741
+ overviewData,
6742
+ minimumParticipation,
6743
+ bedrooms,
6744
+ bathrooms,
6745
+ carSpaces,
6746
+ propertyTypeLabel
6747
+ }) {
6748
+ const description = overviewData?.description ?? "N/A";
6749
+ const tokensIssued = overviewData?.tokensIssued ?? null;
6750
+ const offeringValuation = overviewData?.offeringValuation ?? null;
6751
+ const weeklyRent = overviewData?.weeklyRent ?? null;
6752
+ const indicativeListing = overviewData?.indicativeListing ?? "N/A";
6753
+ const minParticipationValue = minimumParticipation ?? overviewData?.minimumParticipation ?? null;
6754
+ const landSize = overviewData?.landSizeSqm ?? null;
6755
+ const buildingSize = overviewData?.buildingSizeSqm ?? null;
6756
+ const propertyType = propertyTypeLabel ?? overviewData?.propertyType ?? "N/A";
6757
+ overviewData?.yearBuilt ?? null;
6758
+ const ownership = overviewData?.ownership ?? "N/A";
6759
+ const zoning = overviewData?.zoning ?? "N/A";
6760
+ const levels = overviewData?.levels ?? null;
6761
+ const daStatus = overviewData?.daStatus ?? "N/A";
6762
+ const unitPrice = tokensIssued && offeringValuation ? offeringValuation / tokensIssued : null;
6763
+ const formattedPropertyType = propertyType !== "N/A" ? propertyType.charAt(0).toUpperCase() + propertyType.slice(1).toLowerCase() : "N/A";
6703
6764
  return /* @__PURE__ */ jsxs(Fragment, { children: [
6704
6765
  /* @__PURE__ */ jsxs(TwoColGrid, { children: [
6705
6766
  /* @__PURE__ */ jsxs(Section, { children: [
6706
6767
  /* @__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
- ] })
6768
+ /* @__PURE__ */ jsx(BodyText, { children: description === "N/A" ? description : description.split("\n\n").map((paragraph, i) => /* @__PURE__ */ jsxs("span", { children: [
6769
+ paragraph,
6770
+ i < description.split("\n\n").length - 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
6771
+ /* @__PURE__ */ jsx("br", {}),
6772
+ /* @__PURE__ */ jsx("br", {})
6773
+ ] })
6774
+ ] }, i)) })
6713
6775
  ] }),
6714
6776
  /* @__PURE__ */ jsxs(Section, { children: [
6715
6777
  /* @__PURE__ */ jsx(SectionHeading, { children: "The Offering" }),
6716
6778
  /* @__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 }
6779
+ { label: "Units Issued", value: tokensIssued?.toLocaleString() ?? "-", gold: false },
6780
+ { label: "Issue Price", value: unitPrice ? `$${unitPrice.toFixed(2)} / Unit` : "-", gold: true },
6781
+ { label: "Implied Value", value: offeringValuation ? `$${offeringValuation.toLocaleString()}` : "-", gold: false },
6782
+ { label: "Minimum Participation", value: minParticipationValue != null ? `$${minParticipationValue.toLocaleString()}` : "-", gold: false },
6783
+ { label: "Est. Cash Flow", value: weeklyRent ? `$${weeklyRent.toLocaleString()}/wk` : "-", gold: true },
6784
+ { label: "Indicative Listing Date", value: indicativeListing, gold: false }
6723
6785
  ].map(({ label, value, gold }) => /* @__PURE__ */ jsxs(OfferingItem, { children: [
6724
6786
  /* @__PURE__ */ jsx(OfferingLabel, { children: label }),
6725
6787
  /* @__PURE__ */ jsx(OfferingValue, { $gold: gold, children: value })
@@ -6732,10 +6794,10 @@ function PropertyOverview({ propertyName: _propertyName, location: _location, mi
6732
6794
  /* @__PURE__ */ jsx(AssetDetailsTitle, { children: "Asset Details" })
6733
6795
  ] }),
6734
6796
  /* @__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}" }
6797
+ { label: "Bedrooms", value: bedrooms != null ? bedrooms.toString() : "-", icon: "\u{1F6CF}\uFE0F" },
6798
+ { label: "Bathrooms", value: bathrooms != null ? bathrooms.toString() : "-", icon: "\u{1F6BF}" },
6799
+ { type: "dual", label1: "Land", value1: landSize?.toString() ?? "-", label2: "Floor", value2: buildingSize?.toString() ?? "-", unit: "sqm", highlight: true },
6800
+ { label: "Car Spaces", value: carSpaces != null ? carSpaces.toString() : "-", icon: "\u{1F697}" }
6739
6801
  ].map((stat, i) => /* @__PURE__ */ jsx(StatCard, { $highlight: !!stat.highlight, children: stat.type === "dual" ? /* @__PURE__ */ jsxs(DualStatInner, { children: [
6740
6802
  /* @__PURE__ */ jsxs(DualStatCol, { children: [
6741
6803
  /* @__PURE__ */ jsx(StatLabel, { $gold: true, children: stat.label1 }),
@@ -6757,14 +6819,14 @@ function PropertyOverview({ propertyName: _propertyName, location: _location, mi
6757
6819
  /* @__PURE__ */ jsx(StatBigValue, { $gold: !!stat.highlight, children: stat.value })
6758
6820
  ] }) }, i)) }),
6759
6821
  /* @__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" }
6822
+ { label: "Last Sale", value: "-" },
6823
+ { label: "Suburb Median", value: "-" },
6824
+ { label: "Replication Cost of Architecture", value: "-" },
6825
+ { label: "DA Status", value: daStatus, status: daStatus.toLowerCase() === "approved" ? "success" : "progress" },
6826
+ { label: "Property Type", value: formattedPropertyType },
6827
+ { label: "Ownership", value: ownership ?? "N/A" },
6828
+ { label: "Zoning", value: zoning ?? "N/A" },
6829
+ { label: "Levels", value: levels?.toString() ?? "N/A" }
6768
6830
  ].map((item, i) => /* @__PURE__ */ jsxs(DetailCell, { $borderBottom: i < 4, $borderRight: (i + 1) % 4 !== 0, children: [
6769
6831
  /* @__PURE__ */ jsx(DetailCellLabel, { children: item.label }),
6770
6832
  /* @__PURE__ */ jsxs(DetailCellValue, { $status: item.status, children: [
@@ -7650,7 +7712,7 @@ var DocIcon = () => /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", vie
7650
7712
  /* @__PURE__ */ jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
7651
7713
  /* @__PURE__ */ jsx("polyline", { points: "10 9 9 9 8 9" })
7652
7714
  ] });
7653
- var docs = [
7715
+ var fallbackDocs = [
7654
7716
  { href: "/documents/musgrave-valuation-report.pdf", label: "Valuation Report" },
7655
7717
  { href: "/documents/musgrave-offering-material.pdf", label: "Offering Material" },
7656
7718
  { href: "/documents/musgrave-mortgage-agreement.pdf", label: "Mortgage Agreement" },
@@ -7659,13 +7721,26 @@ var docs = [
7659
7721
  { href: "/documents/musgrave-risk-disclosure.pdf", label: "Risk Disclosure Statement" },
7660
7722
  { href: "/documents/musgrave-building-inspection.pdf", label: "Building & Pest Inspection Report" }
7661
7723
  ];
7662
- function PropertyDocuments() {
7724
+ function PropertyDocuments({ documentsData }) {
7725
+ const backendDocuments = Array.isArray(documentsData?.documents) ? documentsData.documents : null;
7726
+ const hasBackendDocuments = !!backendDocuments?.length;
7727
+ const documents = hasBackendDocuments ? backendDocuments : fallbackDocs.map((doc) => ({
7728
+ title: doc.label,
7729
+ documentUrl: doc.href
7730
+ }));
7663
7731
  return /* @__PURE__ */ jsxs(Section2, { children: [
7664
7732
  /* @__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)) })
7733
+ /* @__PURE__ */ jsx(DocList, { children: documents.map(({ documentUrl, title }) => {
7734
+ const isAvailable = Boolean(documentUrl);
7735
+ return /* @__PURE__ */ jsx(DocItem, { children: hasBackendDocuments && isAvailable ? /* @__PURE__ */ jsxs(DocLink, { href: documentUrl, target: "_blank", rel: "noopener noreferrer", children: [
7736
+ /* @__PURE__ */ jsx(DocIconWrapper, { children: /* @__PURE__ */ jsx(DocIcon, {}) }),
7737
+ title
7738
+ ] }) : /* @__PURE__ */ jsxs(DocItemDisabled, { children: [
7739
+ /* @__PURE__ */ jsx(DocIconWrapper, { children: /* @__PURE__ */ jsx(DocIcon, {}) }),
7740
+ title,
7741
+ /* @__PURE__ */ jsx(ComingSoonBadge, { children: "Coming Soon" })
7742
+ ] }) }, `${title}-${documentUrl ?? "pending"}`);
7743
+ }) })
7669
7744
  ] });
7670
7745
  }
7671
7746
  var Section2 = styled23.section`
@@ -7709,11 +7784,29 @@ var DocLink = styled23.a`
7709
7784
  color: var(--color-accent);
7710
7785
  }
7711
7786
  `;
7787
+ var DocItemDisabled = styled23.div`
7788
+ display: flex;
7789
+ align-items: center;
7790
+ color: var(--color-text-secondary);
7791
+ cursor: not-allowed;
7792
+ opacity: 0.6;
7793
+ `;
7712
7794
  var DocIconWrapper = styled23.span`
7713
7795
  margin-right: 0.75rem;
7714
7796
  flex-shrink: 0;
7715
7797
  color: var(--color-text-secondary);
7716
7798
  `;
7799
+ var ComingSoonBadge = styled23.span`
7800
+ margin-left: auto;
7801
+ padding: 0.25rem 0.5rem;
7802
+ background: rgba(212, 175, 55, 0.1);
7803
+ color: #D4AF37;
7804
+ border-radius: 0.25rem;
7805
+ font-size: 0.7rem;
7806
+ font-weight: 500;
7807
+ text-transform: uppercase;
7808
+ letter-spacing: 0.05em;
7809
+ `;
7717
7810
  var formatIsoDate = (value) => {
7718
7811
  const parsed = new Date(value);
7719
7812
  if (Number.isNaN(parsed.getTime())) return value;
@@ -8000,7 +8093,7 @@ function AssetSelectorBar({ propertyName, tokenPrice, offeringValuation }) {
8000
8093
  /* @__PURE__ */ jsxs(SelectorMetrics, { children: [
8001
8094
  /* @__PURE__ */ jsxs("div", { children: [
8002
8095
  /* @__PURE__ */ jsx(MetricLabel, { children: "Unit Price" }),
8003
- /* @__PURE__ */ jsxs(MetricValue, { accent: true, children: [
8096
+ /* @__PURE__ */ jsxs(MetricValue, { $accent: true, children: [
8004
8097
  "$",
8005
8098
  tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
8006
8099
  ] })
@@ -8095,7 +8188,7 @@ var MetricLabel = styled23.span`
8095
8188
  var MetricValue = styled23.span`
8096
8189
  font-size: 1.1rem;
8097
8190
  font-weight: 700;
8098
- color: ${(p) => p.accent ? "#D4AF37" : "#fff"};
8191
+ color: ${(p) => p.$accent ? "#D4AF37" : "#fff"};
8099
8192
  `;
8100
8193
  var Separator = styled23.span`
8101
8194
  font-size: 1rem;
@@ -8214,7 +8307,7 @@ function OfferingProgressCard({
8214
8307
  /* @__PURE__ */ jsx("span", { children: "\u24D8" })
8215
8308
  ] }),
8216
8309
  /* @__PURE__ */ jsxs(LivePercent, { children: [
8217
- percentSold.toFixed(1),
8310
+ percentSold < 0.1 && percentSold > 0 ? percentSold.toFixed(3) : percentSold.toFixed(1),
8218
8311
  "%",
8219
8312
  /* @__PURE__ */ jsx("span", { children: "\u2191" })
8220
8313
  ] })
@@ -8587,7 +8680,8 @@ function OrderPanel({
8587
8680
  orderButtonText,
8588
8681
  isOrderButtonDisabled,
8589
8682
  hasInsufficientFunds,
8590
- onPlaceAnotherOrder
8683
+ onPlaceAnotherOrder,
8684
+ onDeposit
8591
8685
  }) {
8592
8686
  const [payInputValue, setPayInputValue] = useState("");
8593
8687
  const [receiveInputValue, setReceiveInputValue] = useState("");
@@ -8596,11 +8690,14 @@ function OrderPanel({
8596
8690
  const handlePayBlur = () => {
8597
8691
  setIsPayInputFocused(false);
8598
8692
  const parsed = parseInt(payInputValue.replace(/[^0-9]/g, ""), 10) || 0;
8599
- if (parsed > availableBalance) {
8600
- setManualOrderAmount(parsed);
8693
+ if (parsed <= 0) {
8694
+ setManualOrderAmount(null);
8695
+ setSliderValue(0);
8696
+ } else if (parsed >= availableBalance) {
8697
+ setManualOrderAmount(null);
8601
8698
  setSliderValue(100);
8602
8699
  } else {
8603
- setManualOrderAmount(null);
8700
+ setManualOrderAmount(parsed);
8604
8701
  const ratio = availableBalance === 0 ? 0 : Math.round(Math.max(0, parsed / availableBalance * 100));
8605
8702
  setSliderValue(ratio);
8606
8703
  }
@@ -8609,11 +8706,14 @@ function OrderPanel({
8609
8706
  setIsReceiveInputFocused(false);
8610
8707
  const parsed = parseFloat(receiveInputValue) || 0;
8611
8708
  const newOrderTotal = Math.round(parsed * tokenPrice);
8612
- if (newOrderTotal > availableBalance) {
8613
- setManualOrderAmount(newOrderTotal);
8709
+ if (newOrderTotal <= 0) {
8710
+ setManualOrderAmount(null);
8711
+ setSliderValue(0);
8712
+ } else if (newOrderTotal >= availableBalance) {
8713
+ setManualOrderAmount(null);
8614
8714
  setSliderValue(100);
8615
8715
  } else {
8616
- setManualOrderAmount(null);
8716
+ setManualOrderAmount(newOrderTotal);
8617
8717
  const ratio = availableBalance === 0 ? 0 : Math.round(Math.max(0, newOrderTotal / availableBalance * 100));
8618
8718
  setSliderValue(ratio);
8619
8719
  }
@@ -8683,7 +8783,7 @@ function OrderPanel({
8683
8783
  }
8684
8784
  }
8685
8785
  ),
8686
- /* @__PURE__ */ jsx("span", { children: "AUD" })
8786
+ /* @__PURE__ */ jsx("span", { children: "USDC" })
8687
8787
  ] }),
8688
8788
  /* @__PURE__ */ jsx(QuickSelectRow, { children: [25, 50, 75, 100].map((pct) => /* @__PURE__ */ jsxs(
8689
8789
  "button",
@@ -8710,7 +8810,7 @@ function OrderPanel({
8710
8810
  availableBalance.toLocaleString()
8711
8811
  ] })
8712
8812
  ] }),
8713
- /* @__PURE__ */ jsx(DepositButton, { type: "button", children: "+ Deposit" })
8813
+ /* @__PURE__ */ jsx(DepositButton, { type: "button", onClick: onDeposit, children: "+ Deposit" })
8714
8814
  ] }),
8715
8815
  /* @__PURE__ */ jsx(Divider2, { children: "\u2193" }),
8716
8816
  /* @__PURE__ */ jsxs(Card2, { children: [
@@ -8777,7 +8877,7 @@ function OrderPanel({
8777
8877
  /* @__PURE__ */ jsxs("strong", { children: [
8778
8878
  "$",
8779
8879
  orderTotal.toLocaleString(),
8780
- " AUD"
8880
+ " USDC"
8781
8881
  ] })
8782
8882
  ] })
8783
8883
  ] })
@@ -8799,7 +8899,7 @@ function OrderPanel({
8799
8899
  "$",
8800
8900
  availableBalance.toLocaleString()
8801
8901
  ] }),
8802
- /* @__PURE__ */ jsx(BalanceAction, { children: "+ Deposit" })
8902
+ /* @__PURE__ */ jsx(BalanceAction, { onClick: onDeposit, style: { cursor: onDeposit ? "pointer" : "default" }, children: "+ Deposit" })
8803
8903
  ] }),
8804
8904
  /* @__PURE__ */ jsxs(BalanceCard, { children: [
8805
8905
  /* @__PURE__ */ jsx(BalanceLabel, { children: "Musgrave Owned" }),
@@ -9431,7 +9531,23 @@ var IframeShield = styled23.div`
9431
9531
  z-index: 1;
9432
9532
  cursor: pointer;
9433
9533
  `;
9434
- function NewsOrdersSection({ newsItems, userSubscription, tokenPrice }) {
9534
+ var SUBSCRIPTIONS_PAGE_SIZE = 6;
9535
+ function NewsOrdersSection({ newsItems, userSubscriptions, tokenPrice }) {
9536
+ const [page, setPage] = useState(0);
9537
+ const totalPages = Math.max(1, Math.ceil(userSubscriptions.length / SUBSCRIPTIONS_PAGE_SIZE));
9538
+ useEffect(() => {
9539
+ if (page > totalPages - 1) {
9540
+ setPage(totalPages - 1);
9541
+ }
9542
+ }, [page, totalPages]);
9543
+ useEffect(() => {
9544
+ setPage(0);
9545
+ }, [userSubscriptions]);
9546
+ const paginatedSubscriptions = useMemo(() => {
9547
+ const start = page * SUBSCRIPTIONS_PAGE_SIZE;
9548
+ return userSubscriptions.slice(start, start + SUBSCRIPTIONS_PAGE_SIZE);
9549
+ }, [page, userSubscriptions]);
9550
+ const hasPagination = userSubscriptions.length > SUBSCRIPTIONS_PAGE_SIZE;
9435
9551
  return /* @__PURE__ */ jsxs(Row2, { children: [
9436
9552
  /* @__PURE__ */ jsxs(TradeNewsPanel, { children: [
9437
9553
  /* @__PURE__ */ jsxs(TradeNewsHeader, { children: [
@@ -9458,34 +9574,57 @@ function NewsOrdersSection({ newsItems, userSubscription, tokenPrice }) {
9458
9574
  ] }),
9459
9575
  /* @__PURE__ */ jsxs(TradeNewsPanel, { children: [
9460
9576
  /* @__PURE__ */ jsxs(TradeNewsHeader, { children: [
9461
- /* @__PURE__ */ jsx("h3", { children: "Your Orders" }),
9462
- /* @__PURE__ */ jsx("span", { children: "Offering Subscriptions" })
9577
+ /* @__PURE__ */ jsxs("div", { children: [
9578
+ /* @__PURE__ */ jsx("h3", { children: "Your Orders" }),
9579
+ /* @__PURE__ */ jsx("span", { children: "Offering Subscriptions" })
9580
+ ] }),
9581
+ hasPagination ? /* @__PURE__ */ jsxs(Pagination, { children: [
9582
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setPage((prev) => Math.max(prev - 1, 0)), disabled: page === 0, children: "Prev" }),
9583
+ /* @__PURE__ */ jsxs("span", { children: [
9584
+ "Page ",
9585
+ page + 1,
9586
+ "/",
9587
+ totalPages
9588
+ ] }),
9589
+ /* @__PURE__ */ jsx(
9590
+ "button",
9591
+ {
9592
+ type: "button",
9593
+ onClick: () => setPage((prev) => Math.min(prev + 1, totalPages - 1)),
9594
+ disabled: page >= totalPages - 1,
9595
+ children: "Next"
9596
+ }
9597
+ )
9598
+ ] }) : null
9463
9599
  ] }),
9464
9600
  /* @__PURE__ */ jsxs(OrdersTable, { children: [
9465
9601
  /* @__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: [
9602
+ paginatedSubscriptions.length ? paginatedSubscriptions.map((subscription) => {
9603
+ const subscriptionDate = new Date(subscription.timestamp);
9604
+ return /* @__PURE__ */ jsxs(OrdersRow, { children: [
9605
+ /* @__PURE__ */ jsxs("div", { children: [
9606
+ subscriptionDate.toLocaleDateString("en-AU", {
9607
+ day: "2-digit",
9608
+ month: "short",
9609
+ year: "numeric"
9610
+ }),
9611
+ /* @__PURE__ */ jsx("span", { children: subscriptionDate.toLocaleTimeString("en-AU", {
9612
+ hour: "2-digit",
9613
+ minute: "2-digit"
9614
+ }) })
9615
+ ] }),
9616
+ /* @__PURE__ */ jsx("div", { className: "units", children: subscription.tokens.toFixed(2) }),
9617
+ /* @__PURE__ */ jsxs("div", { children: [
9618
+ "$",
9619
+ tokenPrice.toFixed(2)
9620
+ ] }),
9621
+ /* @__PURE__ */ jsxs("div", { className: "total", children: [
9622
+ "$",
9623
+ subscription.value.toLocaleString()
9624
+ ] }),
9625
+ /* @__PURE__ */ jsx("div", { className: "status", children: subscription.status ?? "Confirmed" })
9626
+ ] }, `${subscription.timestamp}-${subscription.tokens}`);
9627
+ }) : /* @__PURE__ */ jsxs(OrdersEmpty, { children: [
9489
9628
  /* @__PURE__ */ jsx("div", { children: "\u{1F4CB}" }),
9490
9629
  /* @__PURE__ */ jsx("p", { children: "No orders yet" }),
9491
9630
  /* @__PURE__ */ jsx("small", { children: "Subscribe to the IPO above to place your first order" })
@@ -9612,6 +9751,28 @@ var OrdersTable = styled23.div`
9612
9751
  flex: 1;
9613
9752
  overflow: auto;
9614
9753
  `;
9754
+ var Pagination = styled23.div`
9755
+ display: flex;
9756
+ align-items: center;
9757
+ gap: 0.75rem;
9758
+ font-size: 0.75rem;
9759
+ color: var(--color-text-secondary);
9760
+
9761
+ button {
9762
+ border: 1px solid rgba(255,255,255,0.2);
9763
+ background: rgba(255,255,255,0.05);
9764
+ color: #fff;
9765
+ border-radius: 9999px;
9766
+ padding: 0.25rem 0.9rem;
9767
+ font-size: 0.7rem;
9768
+ cursor: pointer;
9769
+ transition: opacity 0.2s;
9770
+ &:disabled {
9771
+ opacity: 0.4;
9772
+ cursor: not-allowed;
9773
+ }
9774
+ }
9775
+ `;
9615
9776
  var OrdersHead = styled23.div`
9616
9777
  display: grid;
9617
9778
  grid-template-columns: 1fr 1fr 1fr 1fr 1.2fr;
@@ -9885,11 +10046,18 @@ function PropertyBuy({
9885
10046
  propertyLocation: propertyLocationLabel = "Mosman, Sydney",
9886
10047
  isAuthenticated,
9887
10048
  onSignIn,
9888
- saleData
10049
+ saleData,
10050
+ walletUsdcBalance,
10051
+ walletPropertyTokenBalance,
10052
+ onPurchase,
10053
+ purchaseStatus = "idle",
10054
+ purchaseError,
10055
+ onDeposit,
10056
+ initialUserSubscriptions = []
9889
10057
  }) {
9890
10058
  const [sliderValue, setSliderValue] = useState(0);
9891
- const [availableBalance, setAvailableBalance] = useState(125e3);
9892
- const [userSubscription, setUserSubscription] = useState(null);
10059
+ const [availableBalance, setAvailableBalance] = useState(walletUsdcBalance ?? 125e3);
10060
+ const [optimisticUserSubscriptions, setOptimisticUserSubscriptions] = useState([]);
9893
10061
  const [manualOrderAmount, setManualOrderAmount] = useState(null);
9894
10062
  const [ownedTokens, setOwnedTokens] = useState(0);
9895
10063
  const [displayedOwnedTokens, setDisplayedOwnedTokens] = useState(0);
@@ -9907,6 +10075,12 @@ function PropertyBuy({
9907
10075
  isNew: false
9908
10076
  }))
9909
10077
  );
10078
+ const resolvedUserSubscriptions = initialUserSubscriptions && initialUserSubscriptions.length > 0 ? initialUserSubscriptions : optimisticUserSubscriptions;
10079
+ useEffect(() => {
10080
+ if (initialUserSubscriptions?.length) {
10081
+ setOptimisticUserSubscriptions([]);
10082
+ }
10083
+ }, [initialUserSubscriptions]);
9910
10084
  const tokenPrice = saleData?.tokenPrice ?? 250;
9911
10085
  const feeRate = (saleData?.feePercent ?? 0.5) / 100;
9912
10086
  const totalSold = saleData?.totalSold ?? 0;
@@ -9924,6 +10098,17 @@ function PropertyBuy({
9924
10098
  const orderTotal = totalSpend;
9925
10099
  const estExposure = (tokenQuantity / supplyToSell * 100).toFixed(4);
9926
10100
  const hasInsufficientFunds = orderTotal > availableBalance;
10101
+ useEffect(() => {
10102
+ if (walletUsdcBalance != null) {
10103
+ setAvailableBalance(walletUsdcBalance);
10104
+ }
10105
+ }, [walletUsdcBalance]);
10106
+ useEffect(() => {
10107
+ if (walletPropertyTokenBalance != null) {
10108
+ setOwnedTokens(walletPropertyTokenBalance);
10109
+ setDisplayedOwnedTokens(walletPropertyTokenBalance);
10110
+ }
10111
+ }, [walletPropertyTokenBalance]);
9927
10112
  const handleOrderButtonClick = () => {
9928
10113
  if (!isAuthenticated) {
9929
10114
  onSignIn();
@@ -9934,8 +10119,12 @@ function PropertyBuy({
9934
10119
  }
9935
10120
  setShowOrderConfirmModal(true);
9936
10121
  };
10122
+ const isPurchaseInFlight = purchaseStatus === "checking-allowance" || purchaseStatus === "approving" || purchaseStatus === "purchasing";
9937
10123
  const getOrderButtonText = () => {
9938
10124
  if (!isAuthenticated) return "Sign In to Invest";
10125
+ if (purchaseStatus === "checking-allowance") return "Checking allowance\u2026";
10126
+ if (purchaseStatus === "approving") return "Approving USDC\u2026";
10127
+ if (purchaseStatus === "purchasing") return "Confirming purchase\u2026";
9939
10128
  if (scStatus === 0) return "Sale Not Open Yet";
9940
10129
  if (scStatus === 2) return "Sale Completed";
9941
10130
  if (scStatus === 3) return "Sale Paused";
@@ -9944,30 +10133,44 @@ function PropertyBuy({
9944
10133
  };
9945
10134
  const isOrderButtonDisabled = () => {
9946
10135
  if (!isAuthenticated) return false;
10136
+ if (isPurchaseInFlight) return true;
9947
10137
  if (scStatus !== 1) return true;
9948
10138
  if (tokenQuantity === 0) return true;
9949
10139
  return false;
9950
10140
  };
9951
- const confirmOrder = () => {
10141
+ const confirmOrder = async () => {
9952
10142
  setShowOrderConfirmModal(false);
9953
- setAvailableBalance((prev) => prev - orderTotal);
9954
- const newTokens = ownedTokens + tokenQuantity;
10143
+ const tokenAmountInt = Math.floor(tokenQuantity);
10144
+ if (tokenAmountInt <= 0) return;
10145
+ if (onPurchase) {
10146
+ try {
10147
+ await onPurchase(tokenAmountInt);
10148
+ } catch {
10149
+ return;
10150
+ }
10151
+ }
10152
+ if (walletUsdcBalance == null) {
10153
+ setAvailableBalance((prev) => prev - orderTotal);
10154
+ }
10155
+ const newTokens = ownedTokens + tokenAmountInt;
9955
10156
  setOwnedTokens(newTokens);
9956
10157
  setDisplayedOwnedTokens(newTokens);
9957
10158
  setOwnedTokensJustUpdated(true);
9958
- setLastOrderQuantity(tokenQuantity);
10159
+ setLastOrderQuantity(tokenAmountInt);
9959
10160
  setTimeout(() => setOwnedTokensJustUpdated(false), 2e3);
9960
- setUserSubscription({
10161
+ const optimisticEntry = {
9961
10162
  propertyName,
9962
10163
  tokenSymbol: "MUS",
9963
- tokens: tokenQuantity,
10164
+ tokens: tokenAmountInt,
9964
10165
  value: orderTotal,
9965
10166
  avgPrice: tokenPrice,
9966
10167
  percentOfProperty: estExposure,
9967
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
9968
- });
10168
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10169
+ status: "pending"
10170
+ };
10171
+ setOptimisticUserSubscriptions((prev) => [optimisticEntry, ...prev]);
9969
10172
  setLastOrderDetails({
9970
- tokens: tokenQuantity,
10173
+ tokens: tokenAmountInt,
9971
10174
  total: orderTotal,
9972
10175
  price: tokenPrice,
9973
10176
  orderNumber: Math.floor(1e7 + Math.random() * 9e7)
@@ -10027,36 +10230,40 @@ function PropertyBuy({
10027
10230
  }
10028
10231
  ),
10029
10232
  /* @__PURE__ */ jsx(VideoActivitySection, { ipoStarted }),
10030
- /* @__PURE__ */ jsx(
10031
- OrderPanel,
10032
- {
10033
- statusLabel,
10034
- statusColor,
10035
- ipoStarted,
10036
- isAuthenticated,
10037
- tokenPrice,
10038
- feeRate,
10039
- supplyToSell,
10040
- availableBalance,
10041
- displayedOwnedTokens,
10042
- ownedTokensJustUpdated,
10043
- lastOrderQuantity,
10044
- orderPlacedSuccess,
10045
- lastOrderDetails,
10046
- tokenQuantity,
10047
- feeInTokens,
10048
- orderTotal,
10049
- sliderValue,
10050
- manualOrderAmount,
10051
- setSliderValue,
10052
- setManualOrderAmount,
10053
- onOrderButtonClick: handleOrderButtonClick,
10054
- orderButtonText: getOrderButtonText(),
10055
- isOrderButtonDisabled: isOrderButtonDisabled(),
10056
- hasInsufficientFunds,
10057
- onPlaceAnotherOrder: () => setOrderPlacedSuccess(false)
10058
- }
10059
- )
10233
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
10234
+ /* @__PURE__ */ jsx(
10235
+ OrderPanel,
10236
+ {
10237
+ statusLabel,
10238
+ statusColor,
10239
+ ipoStarted,
10240
+ isAuthenticated,
10241
+ tokenPrice,
10242
+ feeRate,
10243
+ supplyToSell,
10244
+ availableBalance,
10245
+ displayedOwnedTokens,
10246
+ ownedTokensJustUpdated,
10247
+ lastOrderQuantity,
10248
+ orderPlacedSuccess,
10249
+ lastOrderDetails,
10250
+ tokenQuantity,
10251
+ feeInTokens,
10252
+ orderTotal,
10253
+ sliderValue,
10254
+ manualOrderAmount,
10255
+ setSliderValue,
10256
+ setManualOrderAmount,
10257
+ onOrderButtonClick: handleOrderButtonClick,
10258
+ orderButtonText: getOrderButtonText(),
10259
+ isOrderButtonDisabled: isOrderButtonDisabled(),
10260
+ hasInsufficientFunds,
10261
+ onPlaceAnotherOrder: () => setOrderPlacedSuccess(false),
10262
+ onDeposit
10263
+ }
10264
+ ),
10265
+ 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 })
10266
+ ] })
10060
10267
  ] }),
10061
10268
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
10062
10269
  /* @__PURE__ */ jsx(GalleryMapSection, { propertyLocation: propertyLocationLabel }),
@@ -10064,7 +10271,7 @@ function PropertyBuy({
10064
10271
  NewsOrdersSection,
10065
10272
  {
10066
10273
  newsItems,
10067
- userSubscription,
10274
+ userSubscriptions: resolvedUserSubscriptions,
10068
10275
  tokenPrice
10069
10276
  }
10070
10277
  )
@@ -12419,7 +12626,192 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
12419
12626
  }
12420
12627
  );
12421
12628
  }
12629
+ var slideIn = keyframes`
12630
+ from { transform: translateX(110%); opacity: 0; }
12631
+ to { transform: translateX(0); opacity: 1; }
12632
+ `;
12633
+ var slideOut = keyframes`
12634
+ from { transform: translateX(0); opacity: 1; }
12635
+ to { transform: translateX(110%); opacity: 0; }
12636
+ `;
12637
+ var progressShrink = keyframes`
12638
+ from { width: 100%; }
12639
+ to { width: 0%; }
12640
+ `;
12641
+ var VARIANT_COLORS = {
12642
+ success: { accent: "#0ecb81", icon: "\u2713" },
12643
+ error: { accent: "#f6465d", icon: "\u2715" },
12644
+ info: { accent: "#E6C656", icon: "\u2139" },
12645
+ pending: { accent: "#7EB3E6", icon: "\u25CC" }
12646
+ };
12647
+ var Wrapper = styled23.div`
12648
+ position: relative;
12649
+ display: flex;
12650
+ flex-direction: column;
12651
+ gap: 0;
12652
+ width: 340px;
12653
+ background: #0d0f1a;
12654
+ border: 1px solid rgba(255, 255, 255, 0.08);
12655
+ border-radius: 10px;
12656
+ overflow: hidden;
12657
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.04);
12658
+ 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`};
12659
+ pointer-events: all;
12660
+ `;
12661
+ var Body = styled23.div`
12662
+ display: flex;
12663
+ align-items: flex-start;
12664
+ gap: 12px;
12665
+ padding: 14px 16px 12px;
12666
+ `;
12667
+ var IconDot = styled23.div`
12668
+ flex-shrink: 0;
12669
+ width: 28px;
12670
+ height: 28px;
12671
+ border-radius: 50%;
12672
+ background: ${({ $color }) => $color}1a;
12673
+ border: 1px solid ${({ $color }) => $color}55;
12674
+ display: flex;
12675
+ align-items: center;
12676
+ justify-content: center;
12677
+ font-size: 0.75rem;
12678
+ font-weight: 700;
12679
+ color: ${({ $color }) => $color};
12680
+ margin-top: 1px;
12681
+ `;
12682
+ var Content = styled23.div`
12683
+ flex: 1;
12684
+ min-width: 0;
12685
+ `;
12686
+ var Title2 = styled23.p`
12687
+ margin: 0 0 2px;
12688
+ font-size: 0.8rem;
12689
+ font-weight: 600;
12690
+ color: #fff;
12691
+ letter-spacing: 0.01em;
12692
+ `;
12693
+ var Amount = styled23.p`
12694
+ margin: 0 0 6px;
12695
+ font-size: 1.05rem;
12696
+ font-weight: 700;
12697
+ color: #E6C656;
12698
+ letter-spacing: -0.01em;
12699
+ `;
12700
+ var TxRow = styled23.a`
12701
+ display: inline-flex;
12702
+ align-items: center;
12703
+ gap: 5px;
12704
+ font-family: 'IBM Plex Mono', 'Space Mono', monospace;
12705
+ font-size: 0.68rem;
12706
+ color: rgba(255, 255, 255, 0.4);
12707
+ text-decoration: none;
12708
+ transition: color 0.15s;
12709
+ &:hover {
12710
+ color: #7EB3E6;
12711
+ }
12712
+ `;
12713
+ var TxArrow = styled23.span`
12714
+ font-size: 0.6rem;
12715
+ opacity: 0.6;
12716
+ `;
12717
+ var CloseBtn = styled23.button`
12718
+ flex-shrink: 0;
12719
+ background: none;
12720
+ border: none;
12721
+ padding: 2px 4px;
12722
+ cursor: pointer;
12723
+ color: rgba(255, 255, 255, 0.25);
12724
+ font-size: 0.9rem;
12725
+ line-height: 1;
12726
+ transition: color 0.15s;
12727
+ &:hover { color: rgba(255, 255, 255, 0.7); }
12728
+ `;
12729
+ var ProgressBar2 = styled23.div`
12730
+ height: 2px;
12731
+ background: rgba(255, 255, 255, 0.06);
12732
+ position: relative;
12733
+ &::after {
12734
+ content: '';
12735
+ position: absolute;
12736
+ left: 0;
12737
+ top: 0;
12738
+ height: 100%;
12739
+ background: ${({ $color }) => $color};
12740
+ animation: ${css`${progressShrink} ${({ $duration }) => $duration}ms linear forwards`};
12741
+ }
12742
+ `;
12743
+ var Container2 = styled23.div`
12744
+ position: fixed;
12745
+ bottom: 24px;
12746
+ right: 24px;
12747
+ z-index: 9999;
12748
+ display: flex;
12749
+ flex-direction: column-reverse;
12750
+ gap: 10px;
12751
+ pointer-events: none;
12752
+ `;
12753
+ var DEFAULT_EXPLORER = "https://sepolia.basescan.org/tx/";
12754
+ function truncateHash(hash) {
12755
+ return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
12756
+ }
12757
+ function ToastItem({ toast, onDismiss }) {
12758
+ const [exiting, setExiting] = useState(false);
12759
+ const timerRef = useRef(null);
12760
+ const dismiss = useCallback(() => {
12761
+ setExiting(true);
12762
+ setTimeout(() => onDismiss(toast.id), 280);
12763
+ }, [onDismiss, toast.id]);
12764
+ useEffect(() => {
12765
+ const duration2 = toast.duration ?? 6e3;
12766
+ if (duration2 > 0) {
12767
+ timerRef.current = setTimeout(dismiss, duration2);
12768
+ }
12769
+ return () => {
12770
+ if (timerRef.current) clearTimeout(timerRef.current);
12771
+ };
12772
+ }, [dismiss, toast.duration]);
12773
+ const { accent, icon } = VARIANT_COLORS[toast.variant];
12774
+ const duration = toast.duration ?? 6e3;
12775
+ const explorerBase = toast.explorerUrl ?? DEFAULT_EXPLORER;
12776
+ const txUrl = toast.txHash ? `${explorerBase}${toast.txHash}` : void 0;
12777
+ return /* @__PURE__ */ jsxs(Wrapper, { $exiting: exiting, children: [
12778
+ /* @__PURE__ */ jsxs(Body, { children: [
12779
+ /* @__PURE__ */ jsx(IconDot, { $color: accent, children: icon }),
12780
+ /* @__PURE__ */ jsxs(Content, { children: [
12781
+ /* @__PURE__ */ jsx(Title2, { children: toast.title }),
12782
+ toast.amount && /* @__PURE__ */ jsx(Amount, { children: toast.amount }),
12783
+ toast.txHash && txUrl && /* @__PURE__ */ jsxs(TxRow, { href: txUrl, target: "_blank", rel: "noopener noreferrer", children: [
12784
+ truncateHash(toast.txHash),
12785
+ /* @__PURE__ */ jsx(TxArrow, { children: "\u2197" })
12786
+ ] })
12787
+ ] }),
12788
+ /* @__PURE__ */ jsx(CloseBtn, { type: "button", onClick: dismiss, "aria-label": "Dismiss", children: "\u2715" })
12789
+ ] }),
12790
+ duration > 0 && /* @__PURE__ */ jsx(ProgressBar2, { $color: accent, $duration: duration })
12791
+ ] });
12792
+ }
12793
+ var ToastContext = createContext(null);
12794
+ function ToastProvider({ children }) {
12795
+ const [toasts, setToasts] = useState([]);
12796
+ const addToast = useCallback((data) => {
12797
+ const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
12798
+ setToasts((prev) => [...prev, { ...data, id }]);
12799
+ return id;
12800
+ }, []);
12801
+ const dismiss = useCallback((id) => {
12802
+ setToasts((prev) => prev.filter((t) => t.id !== id));
12803
+ }, []);
12804
+ return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
12805
+ children,
12806
+ /* @__PURE__ */ jsx(Container2, { children: toasts.map((t) => /* @__PURE__ */ jsx(ToastItem, { toast: t, onDismiss: dismiss }, t.id)) })
12807
+ ] });
12808
+ }
12809
+ function useToast() {
12810
+ const ctx = useContext(ToastContext);
12811
+ if (!ctx) throw new Error("useToast must be used within a ToastProvider");
12812
+ return ctx;
12813
+ }
12422
12814
 
12423
- 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 };
12815
+ 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 };
12424
12816
  //# sourceMappingURL=index.mjs.map
12425
12817
  //# sourceMappingURL=index.mjs.map