@loafmarkets/ui 0.1.35 → 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.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: [
@@ -10470,9 +10484,15 @@ function PortfolioActivityPanel({
10470
10484
  ] })
10471
10485
  ] }),
10472
10486
  /* @__PURE__ */ jsxRuntime.jsxs(HoldingsQuantity, { children: [
10473
- pos.quantity.toFixed(2),
10474
- " ",
10475
- pos.tokenName
10487
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
10488
+ pos.quantity.toFixed(2),
10489
+ " ",
10490
+ pos.tokenName
10491
+ ] }),
10492
+ /* @__PURE__ */ jsxRuntime.jsxs(HoldingsAvgEntry, { children: [
10493
+ "Avg ",
10494
+ formatCurrency5(pos.averageEntryPrice)
10495
+ ] })
10476
10496
  ] }),
10477
10497
  /* @__PURE__ */ jsxRuntime.jsxs(HoldingsPnL, { children: [
10478
10498
  /* @__PURE__ */ jsxRuntime.jsxs(PnLAmount, { $positive: isPositive, children: [
@@ -10858,10 +10878,18 @@ var HoldingsPortfolio = styled24__default.default.div`
10858
10878
  }
10859
10879
  `;
10860
10880
  var HoldingsQuantity = styled24__default.default.div`
10881
+ display: flex;
10882
+ flex-direction: column;
10883
+ align-items: center;
10884
+ gap: 0.15rem;
10861
10885
  font-size: 0.85rem;
10862
10886
  font-weight: 500;
10863
10887
  color: #fff;
10864
- text-align: center;
10888
+ `;
10889
+ var HoldingsAvgEntry = styled24__default.default.div`
10890
+ font-size: 0.7rem;
10891
+ color: var(--color-accent, #E6C87E);
10892
+ font-weight: 500;
10865
10893
  `;
10866
10894
  var HoldingsPnL = styled24__default.default.div`
10867
10895
  display: flex;
@@ -11268,6 +11296,55 @@ var ButtonRow2 = styled24__default.default.div`
11268
11296
  box-shadow: 0 4px 12px rgba(14,203,129,0.3);
11269
11297
  }
11270
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
+ };
11271
11348
  function PropertyBuy({
11272
11349
  propertyName = "Loaf Property",
11273
11350
  propertyLocation: propertyLocationLabel = "Sydney, NSW",
@@ -11288,10 +11365,12 @@ function PropertyBuy({
11288
11365
  recentOrders = [],
11289
11366
  ordersAllocated = 0,
11290
11367
  subscribers = 0,
11368
+ selectorItems,
11369
+ onSelectorSelect,
11291
11370
  portfolioActivity
11292
11371
  }) {
11293
11372
  const [sliderValue, setSliderValue] = React5.useState(0);
11294
- const [availableBalance, setAvailableBalance] = React5.useState(walletUsdcBalance ?? 125e3);
11373
+ const [availableBalance, setAvailableBalance] = React5.useState(walletUsdcBalance ?? 0);
11295
11374
  const [manualOrderAmount, setManualOrderAmount] = React5.useState(null);
11296
11375
  const [ownedTokens, setOwnedTokens] = React5.useState(0);
11297
11376
  const [displayedOwnedTokens, setDisplayedOwnedTokens] = React5.useState(0);
@@ -11321,11 +11400,10 @@ function PropertyBuy({
11321
11400
  const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
11322
11401
  const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
11323
11402
  const displayStatusColor = isPrivateClient && ipoStatus !== "LIVE" ? "#D4AF37" : statusColor;
11324
- const totalSpend = manualOrderAmount !== null ? manualOrderAmount : Math.round(sliderValue / 100 * availableBalance);
11325
- const grossTokens = totalSpend / tokenPrice;
11326
- const feeInTokens = grossTokens * feeRate;
11327
- const tokenQuantity = grossTokens - feeInTokens;
11328
- 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;
11329
11407
  const estExposure = (tokenQuantity / supplyToSell * 100).toFixed(4);
11330
11408
  const hasInsufficientFunds = orderTotal > availableBalance;
11331
11409
  React5.useEffect(() => {
@@ -11365,16 +11443,20 @@ function PropertyBuy({
11365
11443
  return false;
11366
11444
  };
11367
11445
  const confirmOrder = async () => {
11368
- setShowOrderConfirmModal(false);
11369
11446
  const tokenAmountInt = Math.floor(tokenQuantity);
11370
- if (tokenAmountInt <= 0) return;
11447
+ if (tokenAmountInt <= 0) {
11448
+ setShowOrderConfirmModal(false);
11449
+ return;
11450
+ }
11371
11451
  if (onPurchase) {
11372
11452
  try {
11373
11453
  await onPurchase(tokenAmountInt);
11374
11454
  } catch {
11455
+ setShowOrderConfirmModal(false);
11375
11456
  return;
11376
11457
  }
11377
11458
  }
11459
+ setShowOrderConfirmModal(false);
11378
11460
  if (walletUsdcBalance == null) {
11379
11461
  setAvailableBalance((prev) => prev - orderTotal);
11380
11462
  }
@@ -11426,7 +11508,10 @@ function PropertyBuy({
11426
11508
  {
11427
11509
  propertyName,
11428
11510
  tokenPrice,
11429
- offeringValuation
11511
+ offeringValuation,
11512
+ currentTokenName: tokenName,
11513
+ selectorItems,
11514
+ onSelect: onSelectorSelect
11430
11515
  }
11431
11516
  ) }),
11432
11517
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -11475,7 +11560,7 @@ function PropertyBuy({
11475
11560
  orderPlacedSuccess,
11476
11561
  lastOrderDetails,
11477
11562
  tokenQuantity,
11478
- feeInTokens,
11563
+ feeInUsd,
11479
11564
  orderTotal,
11480
11565
  sliderValue,
11481
11566
  manualOrderAmount,