@loafmarkets/ui 0.1.36 → 0.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -591,6 +591,8 @@ declare const PropertySubheader: React$1.ForwardRefExoticComponent<React$1.HTMLA
591
591
  type PropertyAddressOption = {
592
592
  id: string;
593
593
  label: string;
594
+ subtitle?: string;
595
+ status?: string;
594
596
  };
595
597
  type PropertyValueSummary = {
596
598
  value: number;
@@ -754,12 +756,13 @@ type OrderType = 'MARKET' | 'LIMIT';
754
756
  type TimeInForce = 'GTC' | 'IOC' | 'FOK' | 'GTD';
755
757
  type OrderStatus = 'OPEN' | 'PARTIALLY_FILLED' | 'FILLED' | 'CANCELLED' | 'REJECTED';
756
758
  interface OfferingOrder {
759
+ readonly ipoOrderId?: number;
757
760
  readonly tokenName: string;
758
761
  readonly txHash: string;
759
762
  readonly price: number;
760
763
  readonly quantity: number;
761
764
  readonly status: string;
762
- readonly imageUrl: string;
765
+ readonly imageUrl?: string;
763
766
  readonly createdAt: number;
764
767
  }
765
768
  interface OrderHistoryItem {
@@ -832,6 +835,14 @@ type PortfolioActivityPanelProps = {
832
835
  };
833
836
  declare function PortfolioActivityPanel({ positions, showPositionsTab, onPositionClick, offeringOrders, openOrders, orderHistory, tradeHistory, transfers, onCancelOrder, cancellingOrderId, defaultTab, pageSize, blockExplorerBaseUrl, className, style, }: PortfolioActivityPanelProps): react_jsx_runtime.JSX.Element;
834
837
 
838
+ type SelectorItem = {
839
+ readonly tokenName: string;
840
+ readonly ticker: string;
841
+ readonly streetAddress: string;
842
+ readonly suburb: string;
843
+ readonly status: string;
844
+ };
845
+
835
846
  type IpoStatus = 'PENDING' | 'LIVE' | 'CLOSED' | 'CANCELLED';
836
847
  type SaleData = {
837
848
  loading: boolean;
@@ -883,6 +894,8 @@ type PropertyBuyProps = {
883
894
  recentOrders?: readonly IpoRecentOrder[];
884
895
  ordersAllocated?: number;
885
896
  subscribers?: number;
897
+ selectorItems?: readonly SelectorItem[];
898
+ onSelectorSelect?: (tokenName: string) => void;
886
899
  portfolioActivity?: {
887
900
  positions?: readonly PortfolioPosition[];
888
901
  onPositionClick?: (tokenName: string, isIpo: boolean) => void;
@@ -895,7 +908,7 @@ type PropertyBuyProps = {
895
908
  cancellingOrderId?: number | null;
896
909
  };
897
910
  };
898
- declare function PropertyBuy({ propertyName, propertyLocation: propertyLocationLabel, tokenDisplayName, tokenSymbol, tokenName, isAuthenticated, onSignIn, saleData, walletUsdcBalance, walletPropertyTokenBalance, onPurchase, purchaseStatus, purchaseError, onDeposit, opensAt, isPrivateClient, recentOrders, ordersAllocated, subscribers, portfolioActivity, }: PropertyBuyProps): react_jsx_runtime.JSX.Element;
911
+ declare function PropertyBuy({ propertyName, propertyLocation: propertyLocationLabel, tokenDisplayName, tokenSymbol, tokenName, isAuthenticated, onSignIn, saleData, walletUsdcBalance, walletPropertyTokenBalance, onPurchase, purchaseStatus, purchaseError, onDeposit, opensAt, isPrivateClient, recentOrders, ordersAllocated, subscribers, selectorItems, onSelectorSelect, portfolioActivity, }: PropertyBuyProps): react_jsx_runtime.JSX.Element;
899
912
 
900
913
  type OwnerBookingProps = {
901
914
  propertyName?: string | null;
package/dist/index.d.ts CHANGED
@@ -591,6 +591,8 @@ declare const PropertySubheader: React$1.ForwardRefExoticComponent<React$1.HTMLA
591
591
  type PropertyAddressOption = {
592
592
  id: string;
593
593
  label: string;
594
+ subtitle?: string;
595
+ status?: string;
594
596
  };
595
597
  type PropertyValueSummary = {
596
598
  value: number;
@@ -754,12 +756,13 @@ type OrderType = 'MARKET' | 'LIMIT';
754
756
  type TimeInForce = 'GTC' | 'IOC' | 'FOK' | 'GTD';
755
757
  type OrderStatus = 'OPEN' | 'PARTIALLY_FILLED' | 'FILLED' | 'CANCELLED' | 'REJECTED';
756
758
  interface OfferingOrder {
759
+ readonly ipoOrderId?: number;
757
760
  readonly tokenName: string;
758
761
  readonly txHash: string;
759
762
  readonly price: number;
760
763
  readonly quantity: number;
761
764
  readonly status: string;
762
- readonly imageUrl: string;
765
+ readonly imageUrl?: string;
763
766
  readonly createdAt: number;
764
767
  }
765
768
  interface OrderHistoryItem {
@@ -832,6 +835,14 @@ type PortfolioActivityPanelProps = {
832
835
  };
833
836
  declare function PortfolioActivityPanel({ positions, showPositionsTab, onPositionClick, offeringOrders, openOrders, orderHistory, tradeHistory, transfers, onCancelOrder, cancellingOrderId, defaultTab, pageSize, blockExplorerBaseUrl, className, style, }: PortfolioActivityPanelProps): react_jsx_runtime.JSX.Element;
834
837
 
838
+ type SelectorItem = {
839
+ readonly tokenName: string;
840
+ readonly ticker: string;
841
+ readonly streetAddress: string;
842
+ readonly suburb: string;
843
+ readonly status: string;
844
+ };
845
+
835
846
  type IpoStatus = 'PENDING' | 'LIVE' | 'CLOSED' | 'CANCELLED';
836
847
  type SaleData = {
837
848
  loading: boolean;
@@ -883,6 +894,8 @@ type PropertyBuyProps = {
883
894
  recentOrders?: readonly IpoRecentOrder[];
884
895
  ordersAllocated?: number;
885
896
  subscribers?: number;
897
+ selectorItems?: readonly SelectorItem[];
898
+ onSelectorSelect?: (tokenName: string) => void;
886
899
  portfolioActivity?: {
887
900
  positions?: readonly PortfolioPosition[];
888
901
  onPositionClick?: (tokenName: string, isIpo: boolean) => void;
@@ -895,7 +908,7 @@ type PropertyBuyProps = {
895
908
  cancellingOrderId?: number | null;
896
909
  };
897
910
  };
898
- declare function PropertyBuy({ propertyName, propertyLocation: propertyLocationLabel, tokenDisplayName, tokenSymbol, tokenName, isAuthenticated, onSignIn, saleData, walletUsdcBalance, walletPropertyTokenBalance, onPurchase, purchaseStatus, purchaseError, onDeposit, opensAt, isPrivateClient, recentOrders, ordersAllocated, subscribers, portfolioActivity, }: PropertyBuyProps): react_jsx_runtime.JSX.Element;
911
+ declare function PropertyBuy({ propertyName, propertyLocation: propertyLocationLabel, tokenDisplayName, tokenSymbol, tokenName, isAuthenticated, onSignIn, saleData, walletUsdcBalance, walletPropertyTokenBalance, onPurchase, purchaseStatus, purchaseError, onDeposit, opensAt, isPrivateClient, recentOrders, ordersAllocated, subscribers, selectorItems, onSelectorSelect, portfolioActivity, }: PropertyBuyProps): react_jsx_runtime.JSX.Element;
899
912
 
900
913
  type OwnerBookingProps = {
901
914
  propertyName?: string | null;
package/dist/index.js CHANGED
@@ -6976,17 +6976,27 @@ var PropertyCompareBar = React5__namespace.forwardRef(
6976
6976
  }
6977
6977
  )
6978
6978
  ] }),
6979
- /* @__PURE__ */ jsxRuntime.jsx(PropertySelectorDropdown, { $isOpen: isDropdownOpen && hasAddresses, children: normalizedAddresses.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
6980
- PropertySelectorOption,
6981
- {
6982
- onClick: (event) => {
6983
- event.stopPropagation();
6984
- handleAddressSelect(option.id);
6979
+ /* @__PURE__ */ jsxRuntime.jsx(PropertySelectorDropdown, { $isOpen: isDropdownOpen && hasAddresses, children: normalizedAddresses.map((option) => {
6980
+ const isSelected = option.id === resolvedSelectedId;
6981
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6982
+ PropertySelectorOption,
6983
+ {
6984
+ $selected: isSelected,
6985
+ onClick: (event) => {
6986
+ event.stopPropagation();
6987
+ handleAddressSelect(option.id);
6988
+ },
6989
+ children: [
6990
+ /* @__PURE__ */ jsxRuntime.jsx(PropertySelectorName, { children: option.label }),
6991
+ option.subtitle && /* @__PURE__ */ jsxRuntime.jsxs(PropertySelectorSubtitle, { children: [
6992
+ option.subtitle,
6993
+ option.status && option.status !== "LIVE" && /* @__PURE__ */ jsxRuntime.jsx("span", { children: option.status === "PENDING" ? "Coming Soon" : option.status })
6994
+ ] })
6995
+ ]
6985
6996
  },
6986
- children: /* @__PURE__ */ jsxRuntime.jsx(PropertySelectorName, { children: option.label })
6987
- },
6988
- option.id
6989
- )) })
6997
+ option.id
6998
+ );
6999
+ }) })
6990
7000
  ] }),
6991
7001
  propertyValueVariant === "pill" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6992
7002
  priceContent,
@@ -7087,33 +7097,64 @@ var PropertyAddress = styled24__default.default.div`
7087
7097
  `;
7088
7098
  var PropertySelectorDropdown = styled24__default.default.div`
7089
7099
  position: absolute;
7090
- top: 100%;
7100
+ top: calc(100% + 12px);
7091
7101
  left: 0;
7092
- width: 100%;
7093
- max-width: 400px;
7094
- background-color: var(--color-card, #1f232b);
7095
- border-radius: 8px;
7096
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
7097
- z-index: 100;
7098
- overflow: hidden;
7102
+ right: 0;
7103
+ max-width: 420px;
7104
+ background: #0a0a0a;
7105
+ border-radius: 16px;
7106
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.8), 0 4px 12px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.1);
7107
+ z-index: 1000;
7108
+ max-height: 360px;
7109
+ overflow-y: auto;
7110
+ border: 1px solid rgba(255, 255, 255, 0.08);
7099
7111
  display: ${(props) => props.$isOpen ? "block" : "none"};
7112
+ animation: compareSlideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1);
7113
+ @keyframes compareSlideDown {
7114
+ from { opacity: 0; transform: translateY(-10px); }
7115
+ to { opacity: 1; transform: translateY(0); }
7116
+ }
7100
7117
  `;
7101
7118
  var PropertySelectorOption = styled24__default.default.div`
7102
- padding: 0.75rem 1rem;
7103
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
7119
+ padding: 1.25rem 1.5rem;
7120
+ transition: all 0.2s ease;
7121
+ border-bottom: 1px solid rgba(255, 255, 255, 0.03);
7122
+ position: relative;
7104
7123
  cursor: pointer;
7105
- transition: background-color 0.2s;
7106
7124
 
7107
- &:hover {
7108
- background-color: rgba(255, 255, 255, 0.05);
7125
+ &:last-child { border-bottom: none; }
7126
+
7127
+ &::before {
7128
+ content: '';
7129
+ position: absolute;
7130
+ left: 0;
7131
+ top: 0;
7132
+ bottom: 0;
7133
+ width: 3px;
7134
+ background: ${(p) => p.$selected ? "var(--color-accent, #e6c87e)" : "transparent"};
7135
+ transition: all 0.2s ease;
7109
7136
  }
7110
7137
 
7111
- &:last-child {
7112
- border-bottom: none;
7138
+ ${(p) => p.$selected && `background: linear-gradient(90deg, rgba(230, 200, 126, 0.08) 0%, transparent 100%);`}
7139
+
7140
+ &:hover {
7141
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0.06) 0%, transparent 100%);
7113
7142
  }
7114
7143
  `;
7115
7144
  var PropertySelectorName = styled24__default.default.div`
7116
7145
  font-weight: 600;
7146
+ font-size: 1rem;
7147
+ color: #ffffff;
7148
+ margin-bottom: 0.15rem;
7149
+ `;
7150
+ var PropertySelectorSubtitle = styled24__default.default.div`
7151
+ font-size: 0.875rem;
7152
+ color: rgba(255, 255, 255, 0.5);
7153
+ span {
7154
+ margin-left: 0.5rem;
7155
+ color: var(--color-accent, #e6c87e);
7156
+ font-size: 0.75rem;
7157
+ }
7117
7158
  `;
7118
7159
  var PropertyValueBlock = styled24__default.default.div`
7119
7160
  display: flex;
@@ -7532,22 +7573,22 @@ var GymIcon = /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16"
7532
7573
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 18h4" })
7533
7574
  ] });
7534
7575
  var DEFAULT_FEATURES = [
7535
- { icon: BedIcon, value: "4", label: "Beds" },
7536
- { icon: BathIcon, value: "5", label: "Baths" },
7537
- { icon: CarIcon, value: "4", label: "Cars" },
7576
+ { icon: BedIcon, value: "\u2014", label: "Beds" },
7577
+ { icon: BathIcon, value: "\u2014", label: "Baths" },
7578
+ { icon: CarIcon, value: "\u2014", label: "Cars" },
7538
7579
  { icon: PoolIcon, label: "Pool" },
7539
7580
  { icon: GardenIcon, label: "Garden" },
7540
7581
  { icon: GymIcon, label: "Gym" }
7541
7582
  ];
7542
7583
  var DEFAULT_PROPERTY_INFO = [
7543
- { label: "Property Type", value: "Contemporary House" },
7544
- { label: "Built", value: "2015" },
7545
- { label: "Ownership", value: "Freehold" },
7546
- { label: "Zoning", value: "R2 Low Density" },
7547
- { label: "Levels", value: "3" },
7548
- { label: "Status", value: "Rented", status: "active" }
7584
+ { label: "Property Type", value: "N/A" },
7585
+ { label: "Built", value: "N/A" },
7586
+ { label: "Ownership", value: "N/A" },
7587
+ { label: "Zoning", value: "N/A" },
7588
+ { label: "Levels", value: "N/A" },
7589
+ { label: "Status", value: "N/A" }
7549
7590
  ];
7550
- var DEFAULT_DESCRIPTION = "A sweeping panorama across Sydney Harbour stretching from Manly to the iconic city skyline creates a spectacular backdrop from every level of this contemporary masterpiece.";
7591
+ var DEFAULT_DESCRIPTION = "Property description not available.";
7551
7592
  function PropertyOverview({
7552
7593
  propertyName,
7553
7594
  location,
@@ -8836,66 +8877,25 @@ var SignInButton = styled24__default.default.button`
8836
8877
  background: rgba(240, 185, 11, 0.1);
8837
8878
  }
8838
8879
  `;
8839
-
8840
- // src/components/property-buy/constants.ts
8841
- var mockIPOList = [
8842
- { id: "musgrave", name: "8C Mcleod Street (Musgrave)", location: "Mosman, Sydney", status: "live" },
8843
- { id: "ipo-002", name: "15 Ocean View Drive", location: "Bondi, Sydney", status: "coming_soon" },
8844
- { id: "ipo-003", name: "42 Harbour Lane", location: "Mosman, Sydney", status: "coming_soon" }
8845
- ];
8846
- var allNewsItems = [
8847
- { id: 1, title: "RBA signals potential rate cut in Q1 2026 - property stocks rally", type: "market" },
8848
- { id: 2, title: "Sydney unemployment drops to 3.1% - Eastern suburbs lead recovery", type: "market" },
8849
- { id: 3, title: "Musgrave heritage listing confirmed - protects architectural value", type: "property" },
8850
- { id: 4, title: "Mosman Council approves DA for Musgrave restoration works", type: "property" },
8851
- { id: 5, title: "Nearby 12 Mcleod St sells for $18.5M - sets new street record", type: "market" },
8852
- { id: 6, title: "Eastern suburbs rental yields reach 3.8% - highest in 5 years", type: "market" },
8853
- { id: 7, title: "Musgrave pool resurfacing completed - heritage sandstone preserved", type: "property" },
8854
- { id: 8, title: "Mosman median house price hits $7.2M - up 9% YoY", type: "market" },
8855
- { id: 9, title: "Musgrave gardens featured in Heritage NSW annual report", type: "property" },
8856
- { id: 10, title: "Lower North Shore vacancy rates drop to 1.2% - rental demand surges", type: "market" },
8857
- { id: 11, title: "Musgrave structural inspection complete - excellent condition confirmed", type: "property" },
8858
- { id: 12, title: "Sydney harbour views premium reaches 35% - Mosman leads growth", type: "market" },
8859
- { id: 13, title: "New security system installed at Musgrave - smart home integration", type: "property" },
8860
- { id: 14, title: "Heritage property demand up 22% - pre-Federation homes most sought", type: "market" }
8861
- ];
8862
- var musgraveGalleryImages = [
8863
- { src: "/properties/Musgrave/ExteriorFront_Musgrave_Loafmarkets.jpg", title: "Exterior Front", subtitle: "Grand entrance" },
8864
- { src: "/properties/Musgrave/ExteriorDusk_Musgrave_Loafmarkets.jpg", title: "Exterior Dusk", subtitle: "Evening ambiance" },
8865
- { src: "/properties/Musgrave/LivingRoom_Musgrave_Loafmarkets.jpg", title: "Living Room", subtitle: "Spacious living" },
8866
- { src: "/properties/Musgrave/Kitchen_Musgrave_Loafmarkets.jpg", title: "Kitchen", subtitle: "Modern design" },
8867
- { src: "/properties/Musgrave/DiningRoom_Musgrave_Loafmarkets.jpg", title: "Dining Room", subtitle: "Elegant dining" },
8868
- { src: "/properties/Musgrave/BreakfastRoom_Musgrave_Loafmarkets.jpg", title: "Breakfast Room", subtitle: "Morning light" },
8869
- { src: "/properties/Musgrave/MainBedroom_Musgrave_Loafmarkets.jpg", title: "Main Bedroom", subtitle: "Master suite" },
8870
- { src: "/properties/Musgrave/GuestBedroom_Musgrave_Loafmarkets.jpg", title: "Guest Bedroom", subtitle: "Comfortable stay" },
8871
- { src: "/properties/Musgrave/Bathroom_Musgrave_Loafmarkets.jpg", title: "Bathroom", subtitle: "Luxury finishes" },
8872
- { src: "/properties/Musgrave/PoolArea_Musgrave_Loafmarkets.jpg", title: "Pool Area", subtitle: "Resort living" },
8873
- { src: "/properties/Musgrave/GardenView_Musgrave_Loafmarkets.jpg", title: "Garden View", subtitle: "Lush gardens" },
8874
- { src: "/properties/Musgrave/SideGarden_Musgrave_Loafmarkets.jpg", title: "Side Garden", subtitle: "Private retreat" },
8875
- { src: "/properties/Musgrave/AerialView_Musgrave_Loafmarkets.jpg", title: "Aerial View", subtitle: "Property overview" },
8876
- { src: "/properties/Musgrave/AerialLocation_Musgrave_Loafmarkets.jpg", title: "Aerial Location", subtitle: "Neighborhood" },
8877
- { src: "/properties/Musgrave/Floorplan_Musgrave_Loafmarkets.jpg", title: "Floorplan", subtitle: "Layout" }
8878
- ];
8879
- var galleryCategories = [
8880
- { name: "Exterior", startIndex: 0 },
8881
- { name: "Living", startIndex: 2 },
8882
- { name: "Bedrooms", startIndex: 6 },
8883
- { name: "Outdoor", startIndex: 9 },
8884
- { name: "Aerial", startIndex: 12 },
8885
- { name: "Floorplan", startIndex: 14 }
8886
- ];
8887
- var STATUS_COLOR2 = {
8888
- PENDING: "#D4AF37",
8889
- LIVE: "#0ecb81",
8890
- CLOSED: "#848e9c",
8891
- CANCELLED: "#f6465d"
8892
- };
8893
- function AssetSelectorBar({ propertyName, tokenPrice, offeringValuation }) {
8880
+ function AssetSelectorBar({
8881
+ propertyName,
8882
+ tokenPrice,
8883
+ offeringValuation,
8884
+ metrics: metricsProp,
8885
+ currentTokenName,
8886
+ selectorItems,
8887
+ onSelect
8888
+ }) {
8894
8889
  const [isDropdownOpen, setIsDropdownOpen] = React5.useState(false);
8890
+ const hasItems = selectorItems && selectorItems.length > 0;
8891
+ const metrics = metricsProp ?? [
8892
+ ...tokenPrice != null ? [{ label: "Unit Price", value: `$${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, accent: true }] : [],
8893
+ ...offeringValuation != null ? [{ label: "Offering Valuation", value: `$${offeringValuation.toLocaleString()}` }] : []
8894
+ ];
8895
8895
  return /* @__PURE__ */ jsxRuntime.jsx(AssetSelectorWrapper, { children: /* @__PURE__ */ jsxRuntime.jsxs(IPOAssetSelector, { children: [
8896
- /* @__PURE__ */ jsxRuntime.jsx(AssetSelectorDropdown, { onClick: () => setIsDropdownOpen((prev) => !prev), children: /* @__PURE__ */ jsxRuntime.jsxs(AssetName, { children: [
8896
+ /* @__PURE__ */ jsxRuntime.jsx(AssetSelectorDropdown, { onClick: () => hasItems && setIsDropdownOpen((prev) => !prev), children: /* @__PURE__ */ jsxRuntime.jsxs(AssetName, { children: [
8897
8897
  propertyName,
8898
- /* @__PURE__ */ jsxRuntime.jsx(
8898
+ hasItems && /* @__PURE__ */ jsxRuntime.jsx(
8899
8899
  "svg",
8900
8900
  {
8901
8901
  xmlns: "http://www.w3.org/2000/svg",
@@ -8908,42 +8908,47 @@ function AssetSelectorBar({ propertyName, tokenPrice, offeringValuation }) {
8908
8908
  }
8909
8909
  )
8910
8910
  ] }) }),
8911
- /* @__PURE__ */ jsxRuntime.jsxs(SelectorMetrics, { children: [
8912
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8913
- /* @__PURE__ */ jsxRuntime.jsx(MetricLabel2, { children: "Unit Price" }),
8914
- /* @__PURE__ */ jsxRuntime.jsxs(MetricValue, { $accent: true, children: [
8915
- "$",
8916
- tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
8917
- ] })
8918
- ] }),
8919
- /* @__PURE__ */ jsxRuntime.jsx(Separator, { children: "|" }),
8920
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8921
- /* @__PURE__ */ jsxRuntime.jsx(MetricLabel2, { children: "Offering Valuation" }),
8922
- /* @__PURE__ */ jsxRuntime.jsxs(MetricValue, { children: [
8911
+ metrics.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(SelectorMetrics, { children: metrics.map((m, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "contents" }, children: [
8912
+ i > 0 && /* @__PURE__ */ jsxRuntime.jsx(Separator, { children: "|" }),
8913
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
8914
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8915
+ /* @__PURE__ */ jsxRuntime.jsx(MetricLabel2, { children: m.label }),
8916
+ /* @__PURE__ */ jsxRuntime.jsx(MetricValue, { $accent: !!m.accent, children: m.value })
8917
+ ] }),
8918
+ m.change != null && /* @__PURE__ */ jsxRuntime.jsxs(MetricChange, { $positive: m.change >= 0, children: [
8919
+ m.change >= 0 ? "\u2191" : "\u2193",
8923
8920
  "$",
8924
- offeringValuation.toLocaleString()
8921
+ Math.abs(m.change).toLocaleString(void 0, { maximumFractionDigits: 0 })
8925
8922
  ] })
8926
8923
  ] })
8927
- ] }),
8928
- isDropdownOpen && /* @__PURE__ */ jsxRuntime.jsx(IPODropdown, { children: mockIPOList.map((ipo) => {
8929
- const isDisabled = ipo.status === "coming_soon";
8924
+ ] }, m.label)) }),
8925
+ isDropdownOpen && hasItems && /* @__PURE__ */ jsxRuntime.jsx(IPODropdown, { children: selectorItems.map((item) => {
8926
+ const isCurrent = item.tokenName === currentTokenName;
8927
+ const status = item.status?.toUpperCase();
8928
+ const statusLabel = status === "PENDING" ? "Coming Soon" : status === "CLOSED" ? "Closed" : status === "CANCELLED" ? "Cancelled" : null;
8930
8929
  return /* @__PURE__ */ jsxRuntime.jsxs(
8931
8930
  IPOOption,
8932
8931
  {
8933
8932
  onClick: () => {
8934
- if (!isDisabled) setIsDropdownOpen(false);
8933
+ if (!isCurrent && onSelect) {
8934
+ onSelect(item.tokenName);
8935
+ }
8936
+ setIsDropdownOpen(false);
8935
8937
  },
8936
- $selected: ipo.id === "musgrave",
8937
- style: { opacity: isDisabled ? 0.4 : 1, cursor: isDisabled ? "not-allowed" : "pointer" },
8938
+ $selected: isCurrent,
8939
+ style: { cursor: isCurrent ? "default" : "pointer" },
8938
8940
  children: [
8939
- /* @__PURE__ */ jsxRuntime.jsx(IPOOptionName, { children: ipo.name }),
8941
+ /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionName, { children: [
8942
+ item.streetAddress,
8943
+ item.ticker ? ` (${item.ticker})` : ""
8944
+ ] }),
8940
8945
  /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionLocation, { children: [
8941
- ipo.location,
8942
- isDisabled && /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Coming Soon" })
8946
+ item.suburb,
8947
+ statusLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: statusLabel })
8943
8948
  ] })
8944
8949
  ]
8945
8950
  },
8946
- ipo.id
8951
+ item.tokenName
8947
8952
  );
8948
8953
  }) })
8949
8954
  ] }) });
@@ -8997,17 +9002,26 @@ var SelectorMetrics = styled24__default.default.div`
8997
9002
  border: 1px solid rgba(255,255,255,0.05);
8998
9003
  `;
8999
9004
  var MetricLabel2 = styled24__default.default.span`
9000
- font-size: 0.65rem;
9005
+ font-size: 0.75rem;
9001
9006
  color: var(--color-text-secondary);
9002
9007
  text-transform: uppercase;
9003
9008
  letter-spacing: 0.05em;
9004
9009
  font-weight: 500;
9010
+ margin-right: 0.5rem;
9005
9011
  `;
9006
9012
  var MetricValue = styled24__default.default.span`
9007
- font-size: 1.1rem;
9013
+ font-size: 1.25rem;
9008
9014
  font-weight: 700;
9009
9015
  color: ${(p) => p.$accent ? "#D4AF37" : "#fff"};
9010
9016
  `;
9017
+ var MetricChange = styled24__default.default.span`
9018
+ font-size: 0.85rem;
9019
+ font-weight: 600;
9020
+ color: ${(p) => p.$positive ? "var(--color-positive, #0ecb81)" : "var(--color-negative, #f6465d)"};
9021
+ display: flex;
9022
+ align-items: center;
9023
+ gap: 0.25rem;
9024
+ `;
9011
9025
  var Separator = styled24__default.default.span`
9012
9026
  font-size: 1rem;
9013
9027
  color: rgba(255,255,255,0.2);
@@ -9715,7 +9729,7 @@ function OrderPanel({
9715
9729
  orderPlacedSuccess,
9716
9730
  lastOrderDetails,
9717
9731
  tokenQuantity,
9718
- feeInTokens,
9732
+ feeInUsd,
9719
9733
  orderTotal,
9720
9734
  sliderValue,
9721
9735
  manualOrderAmount,
@@ -9752,17 +9766,17 @@ function OrderPanel({
9752
9766
  };
9753
9767
  const handleReceiveBlur = () => {
9754
9768
  setIsReceiveInputFocused(false);
9755
- const parsed = parseFloat(receiveInputValue) || 0;
9756
- const newOrderTotal = Math.round(parsed * tokenPrice);
9757
- if (newOrderTotal <= 0) {
9769
+ const units = Math.floor(parseInt(receiveInputValue.replace(/[^0-9]/g, ""), 10) || 0);
9770
+ const spend = units * tokenPrice;
9771
+ if (units <= 0) {
9758
9772
  setManualOrderAmount(null);
9759
9773
  setSliderValue(0);
9760
- } else if (newOrderTotal >= availableBalance) {
9774
+ } else if (spend >= availableBalance) {
9761
9775
  setManualOrderAmount(null);
9762
9776
  setSliderValue(100);
9763
9777
  } else {
9764
- setManualOrderAmount(newOrderTotal);
9765
- const ratio = availableBalance === 0 ? 0 : Math.round(Math.max(0, newOrderTotal / availableBalance * 100));
9778
+ setManualOrderAmount(spend);
9779
+ const ratio = availableBalance === 0 ? 0 : Math.round(Math.max(0, spend / availableBalance * 100));
9766
9780
  setSliderValue(ratio);
9767
9781
  }
9768
9782
  };
@@ -9884,12 +9898,12 @@ function OrderPanel({
9884
9898
  "input",
9885
9899
  {
9886
9900
  type: "text",
9887
- inputMode: "decimal",
9888
- value: isReceiveInputFocused ? receiveInputValue : tokenQuantity.toFixed(2),
9901
+ inputMode: "numeric",
9902
+ value: isReceiveInputFocused ? receiveInputValue : tokenQuantity.toString(),
9889
9903
  style: { color: "#0ecb81" },
9890
9904
  onFocus: (e) => {
9891
9905
  setIsReceiveInputFocused(true);
9892
- setReceiveInputValue(tokenQuantity.toFixed(2));
9906
+ setReceiveInputValue(tokenQuantity.toString());
9893
9907
  e.target.select();
9894
9908
  },
9895
9909
  onBlur: handleReceiveBlur,
@@ -9916,7 +9930,7 @@ function OrderPanel({
9916
9930
  /* @__PURE__ */ jsxRuntime.jsxs(SummaryRow, { children: [
9917
9931
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Buying" }),
9918
9932
  /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
9919
- tokenQuantity.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }),
9933
+ tokenQuantity.toLocaleString(),
9920
9934
  " ",
9921
9935
  tokenSymbol
9922
9936
  ] })
@@ -9928,9 +9942,9 @@ function OrderPanel({
9928
9942
  "%)"
9929
9943
  ] }),
9930
9944
  /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
9931
- feeInTokens.toFixed(2),
9932
- " ",
9933
- tokenSymbol
9945
+ "$",
9946
+ feeInUsd.toFixed(2),
9947
+ " USD"
9934
9948
  ] })
9935
9949
  ] }),
9936
9950
  /* @__PURE__ */ jsxRuntime.jsxs(SummaryTotal, { children: [
@@ -11282,6 +11296,55 @@ var ButtonRow2 = styled24__default.default.div`
11282
11296
  box-shadow: 0 4px 12px rgba(14,203,129,0.3);
11283
11297
  }
11284
11298
  `;
11299
+
11300
+ // src/components/property-buy/constants.ts
11301
+ var allNewsItems = [
11302
+ { id: 1, title: "RBA signals potential rate cut in Q1 2026 - property stocks rally", type: "market" },
11303
+ { id: 2, title: "Sydney unemployment drops to 3.1% - Eastern suburbs lead recovery", type: "market" },
11304
+ { id: 3, title: "Musgrave heritage listing confirmed - protects architectural value", type: "property" },
11305
+ { id: 4, title: "Mosman Council approves DA for Musgrave restoration works", type: "property" },
11306
+ { id: 5, title: "Nearby 12 Mcleod St sells for $18.5M - sets new street record", type: "market" },
11307
+ { id: 6, title: "Eastern suburbs rental yields reach 3.8% - highest in 5 years", type: "market" },
11308
+ { id: 7, title: "Musgrave pool resurfacing completed - heritage sandstone preserved", type: "property" },
11309
+ { id: 8, title: "Mosman median house price hits $7.2M - up 9% YoY", type: "market" },
11310
+ { id: 9, title: "Musgrave gardens featured in Heritage NSW annual report", type: "property" },
11311
+ { id: 10, title: "Lower North Shore vacancy rates drop to 1.2% - rental demand surges", type: "market" },
11312
+ { id: 11, title: "Musgrave structural inspection complete - excellent condition confirmed", type: "property" },
11313
+ { id: 12, title: "Sydney harbour views premium reaches 35% - Mosman leads growth", type: "market" },
11314
+ { id: 13, title: "New security system installed at Musgrave - smart home integration", type: "property" },
11315
+ { id: 14, title: "Heritage property demand up 22% - pre-Federation homes most sought", type: "market" }
11316
+ ];
11317
+ var musgraveGalleryImages = [
11318
+ { src: "/properties/Musgrave/ExteriorFront_Musgrave_Loafmarkets.jpg", title: "Exterior Front", subtitle: "Grand entrance" },
11319
+ { src: "/properties/Musgrave/ExteriorDusk_Musgrave_Loafmarkets.jpg", title: "Exterior Dusk", subtitle: "Evening ambiance" },
11320
+ { src: "/properties/Musgrave/LivingRoom_Musgrave_Loafmarkets.jpg", title: "Living Room", subtitle: "Spacious living" },
11321
+ { src: "/properties/Musgrave/Kitchen_Musgrave_Loafmarkets.jpg", title: "Kitchen", subtitle: "Modern design" },
11322
+ { src: "/properties/Musgrave/DiningRoom_Musgrave_Loafmarkets.jpg", title: "Dining Room", subtitle: "Elegant dining" },
11323
+ { src: "/properties/Musgrave/BreakfastRoom_Musgrave_Loafmarkets.jpg", title: "Breakfast Room", subtitle: "Morning light" },
11324
+ { src: "/properties/Musgrave/MainBedroom_Musgrave_Loafmarkets.jpg", title: "Main Bedroom", subtitle: "Master suite" },
11325
+ { src: "/properties/Musgrave/GuestBedroom_Musgrave_Loafmarkets.jpg", title: "Guest Bedroom", subtitle: "Comfortable stay" },
11326
+ { src: "/properties/Musgrave/Bathroom_Musgrave_Loafmarkets.jpg", title: "Bathroom", subtitle: "Luxury finishes" },
11327
+ { src: "/properties/Musgrave/PoolArea_Musgrave_Loafmarkets.jpg", title: "Pool Area", subtitle: "Resort living" },
11328
+ { src: "/properties/Musgrave/GardenView_Musgrave_Loafmarkets.jpg", title: "Garden View", subtitle: "Lush gardens" },
11329
+ { src: "/properties/Musgrave/SideGarden_Musgrave_Loafmarkets.jpg", title: "Side Garden", subtitle: "Private retreat" },
11330
+ { src: "/properties/Musgrave/AerialView_Musgrave_Loafmarkets.jpg", title: "Aerial View", subtitle: "Property overview" },
11331
+ { src: "/properties/Musgrave/AerialLocation_Musgrave_Loafmarkets.jpg", title: "Aerial Location", subtitle: "Neighborhood" },
11332
+ { src: "/properties/Musgrave/Floorplan_Musgrave_Loafmarkets.jpg", title: "Floorplan", subtitle: "Layout" }
11333
+ ];
11334
+ var galleryCategories = [
11335
+ { name: "Exterior", startIndex: 0 },
11336
+ { name: "Living", startIndex: 2 },
11337
+ { name: "Bedrooms", startIndex: 6 },
11338
+ { name: "Outdoor", startIndex: 9 },
11339
+ { name: "Aerial", startIndex: 12 },
11340
+ { name: "Floorplan", startIndex: 14 }
11341
+ ];
11342
+ var STATUS_COLOR2 = {
11343
+ PENDING: "#D4AF37",
11344
+ LIVE: "#0ecb81",
11345
+ CLOSED: "#848e9c",
11346
+ CANCELLED: "#f6465d"
11347
+ };
11285
11348
  function PropertyBuy({
11286
11349
  propertyName = "Loaf Property",
11287
11350
  propertyLocation: propertyLocationLabel = "Sydney, NSW",
@@ -11302,10 +11365,12 @@ function PropertyBuy({
11302
11365
  recentOrders = [],
11303
11366
  ordersAllocated = 0,
11304
11367
  subscribers = 0,
11368
+ selectorItems,
11369
+ onSelectorSelect,
11305
11370
  portfolioActivity
11306
11371
  }) {
11307
11372
  const [sliderValue, setSliderValue] = React5.useState(0);
11308
- const [availableBalance, setAvailableBalance] = React5.useState(walletUsdcBalance ?? 125e3);
11373
+ const [availableBalance, setAvailableBalance] = React5.useState(walletUsdcBalance ?? 0);
11309
11374
  const [manualOrderAmount, setManualOrderAmount] = React5.useState(null);
11310
11375
  const [ownedTokens, setOwnedTokens] = React5.useState(0);
11311
11376
  const [displayedOwnedTokens, setDisplayedOwnedTokens] = React5.useState(0);
@@ -11335,11 +11400,10 @@ function PropertyBuy({
11335
11400
  const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
11336
11401
  const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
11337
11402
  const displayStatusColor = isPrivateClient && ipoStatus !== "LIVE" ? "#D4AF37" : statusColor;
11338
- const totalSpend = manualOrderAmount !== null ? manualOrderAmount : Math.round(sliderValue / 100 * availableBalance);
11339
- const grossTokens = totalSpend / tokenPrice;
11340
- const feeInTokens = grossTokens * feeRate;
11341
- const tokenQuantity = grossTokens - feeInTokens;
11342
- const orderTotal = totalSpend;
11403
+ const rawSpend = manualOrderAmount !== null ? manualOrderAmount : Math.round(sliderValue / 100 * availableBalance);
11404
+ const tokenQuantity = Math.floor(rawSpend / tokenPrice);
11405
+ const feeInUsd = tokenQuantity * tokenPrice * feeRate;
11406
+ const orderTotal = tokenQuantity * tokenPrice + feeInUsd;
11343
11407
  const estExposure = (tokenQuantity / supplyToSell * 100).toFixed(4);
11344
11408
  const hasInsufficientFunds = orderTotal > availableBalance;
11345
11409
  React5.useEffect(() => {
@@ -11379,16 +11443,20 @@ function PropertyBuy({
11379
11443
  return false;
11380
11444
  };
11381
11445
  const confirmOrder = async () => {
11382
- setShowOrderConfirmModal(false);
11383
11446
  const tokenAmountInt = Math.floor(tokenQuantity);
11384
- if (tokenAmountInt <= 0) return;
11447
+ if (tokenAmountInt <= 0) {
11448
+ setShowOrderConfirmModal(false);
11449
+ return;
11450
+ }
11385
11451
  if (onPurchase) {
11386
11452
  try {
11387
11453
  await onPurchase(tokenAmountInt);
11388
11454
  } catch {
11455
+ setShowOrderConfirmModal(false);
11389
11456
  return;
11390
11457
  }
11391
11458
  }
11459
+ setShowOrderConfirmModal(false);
11392
11460
  if (walletUsdcBalance == null) {
11393
11461
  setAvailableBalance((prev) => prev - orderTotal);
11394
11462
  }
@@ -11440,7 +11508,10 @@ function PropertyBuy({
11440
11508
  {
11441
11509
  propertyName,
11442
11510
  tokenPrice,
11443
- offeringValuation
11511
+ offeringValuation,
11512
+ currentTokenName: tokenName,
11513
+ selectorItems,
11514
+ onSelect: onSelectorSelect
11444
11515
  }
11445
11516
  ) }),
11446
11517
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -11489,7 +11560,7 @@ function PropertyBuy({
11489
11560
  orderPlacedSuccess,
11490
11561
  lastOrderDetails,
11491
11562
  tokenQuantity,
11492
- feeInTokens,
11563
+ feeInUsd,
11493
11564
  orderTotal,
11494
11565
  sliderValue,
11495
11566
  manualOrderAmount,