@@ -281,35 +316,58 @@ export default function ListingDetail() {
if (!listing) return null;
+ const statusLabel = listing.status?.status
+ ? listing.status.status.charAt(0).toUpperCase() + listing.status.status.slice(1)
+ : null;
+
const data = [
- { key: 'Price', value: `${listing.price} €`, Icon:
},
+ {
+ key: 'Price',
+ value: `${listing.price} €`,
+ Icon:
,
+ helpText: 'The asking price of this listing, as reported by the provider.',
+ },
{
key: 'Size',
value: listing.size ? `${listing.size} m²` : 'N/A',
Icon:
,
+ helpText: 'Living space of the listing in square meters.',
},
{
key: 'Rooms',
value: listing.rooms ? `${listing.rooms} Rooms` : 'N/A',
Icon:
,
+ helpText: 'Number of rooms in the listing.',
},
{
key: 'Job',
value: listing.job_name,
Icon:
,
+ helpText: 'The Fredy job that found this listing.',
},
{
key: 'Provider',
value: listing.provider ? listing.provider.charAt(0).toUpperCase() + listing.provider.slice(1) : 'Unknown',
Icon:
,
+ helpText: 'The real estate portal where this listing was scraped from.',
},
{
key: 'Added',
value: timeService.format(listing.created_at),
Icon:
,
+ helpText: 'When Fredy first added this listing to your database.',
},
];
+ if (statusLabel) {
+ data.push({
+ key: 'Status',
+ value: listing.status?.setAt ? `${statusLabel} (set ${timeService.format(listing.status.setAt)})` : statusLabel,
+ Icon:
,
+ helpText: 'The status you marked for this listing and when you set it.',
+ });
+ }
+
return (
+
+
+
+ Notes
+
+
@@ -389,10 +474,12 @@ export default function ListingDetail() {
{data.map((item, index) => (
-
- {item.Icon}
- {item.value}
-
+
+
+ {item.Icon}
+ {item.value}
+
+
))}
diff --git a/ui/src/views/listings/ListingDetail.less b/ui/src/views/listings/ListingDetail.less
index 3d65a62..b594cd3 100644
--- a/ui/src/views/listings/ListingDetail.less
+++ b/ui/src/views/listings/ListingDetail.less
@@ -89,6 +89,49 @@
}
}
+ &__notes {
+ padding: 1.5rem;
+ border-top: 1px solid var(--semi-color-border);
+ }
+
+ &__notes-title {
+ margin-bottom: 1rem !important;
+ }
+
+ &__notes-actions {
+ margin-top: 0.75rem;
+ width: 100%;
+ justify-content: flex-end;
+ }
+
+ &__notes-textarea {
+ background: #2a2a2a !important;
+ border: 1px solid @color-border-bright !important;
+ border-radius: @radius-input !important;
+ box-shadow: none !important;
+ outline: none !important;
+ transition: border-color @transition-fast, background @transition-fast !important;
+
+ textarea {
+ background: transparent !important;
+ border: 0 !important;
+ box-shadow: none !important;
+ outline: none !important;
+ color: @color-text !important;
+ font-family: @font-ui !important;
+ font-size: @text-base !important;
+ }
+
+ &.semi-input-textarea-focus,
+ &:focus,
+ &:focus-within {
+ border-color: @color-accent !important;
+ box-shadow: none !important;
+ outline: none !important;
+ background: #2f2f2f !important;
+ }
+ }
+
&__watch-btn {
color: @color-muted !important;
border: 1px solid @color-border-bright !important;
@@ -128,6 +171,13 @@
padding: 1.5rem;
}
+ &__details-item {
+ cursor: help;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ }
+
&__map-container {
height: 400px;
width: 100%;
diff --git a/ui/src/views/listings/Listings.jsx b/ui/src/views/listings/Listings.jsx
index b9d744b..fa835d8 100644
--- a/ui/src/views/listings/Listings.jsx
+++ b/ui/src/views/listings/Listings.jsx
@@ -6,11 +6,15 @@
import ListingsOverview from '../../components/listings/ListingsOverview.jsx';
import Headline from '../../components/headline/Headline.jsx';
-export default function Listings() {
+/**
+ * @param {{ mode?: 'all' | 'watchlist' }} props
+ */
+export default function Listings({ mode = 'all' }) {
+ const title = mode === 'watchlist' ? 'Watchlist' : 'Listings';
return (
<>
-
-
+
+
>
);
}