// DEPLOY_CONFIG: {"triggers": [{"name": "notify_seller_on_buyer_interest", "on": "collection.add", "collection": "buyer_interests", "actions": [{"type": "email", "to": "{{seller.email}}", "subject": "A buyer is interested in your listing: {{listing.title}}", "body": "A buyer marked interest in your listing.\n\nListing: {{listing.title}}\nListing ID: {{listing.id}}\nPrice: {{listing.price}}\nLocation: {{listing.location}}\n\nBuyer details:\nName: {{buyer.name}}\nEmail: {{buyer.email}}\nPhone: {{buyer.phone}}\n\nPlease follow up with the buyer as soon as possible."}]}]} import { useMemo, useState } from 'react'; import { useCollection, useIdentity } from '@deplixo/sdk'; import { ListingsBoard } from './components/ListingsBoard.jsx'; import { MapView } from './components/MapView.jsx'; import { ListingForm } from './components/ListingForm.jsx'; import { ListingDetail } from './components/ListingDetail.jsx'; function App() { const [activeTab, setActiveTab] = useState('browse'); const [showForm, setShowForm] = useState(false); const [selectedListing, setSelectedListing] = useState(null); const [selectedCategory, setSelectedCategory] = useState('all'); const [selectedPriceRange, setSelectedPriceRange] = useState('all'); const collection = useCollection('listings', { personal: true }); const { user } = useIdentity(); const tabs = [ { id: 'browse', label: 'π·οΈ Browse', icon: 'π·οΈ' }, { id: 'map', label: 'πΊοΈ Map', icon: 'πΊοΈ' }, { id: 'my-items', label: 'π¦ My Items', icon: 'π¦' } ]; const displayName = useMemo(() => { if (!user) return 'Seller'; return user.name || user.username || user.handle || user.email || 'Seller'; }, [user]); const handleCloseForm = () => setShowForm(false); const handleSelectListing = (listing) => { setSelectedListing(listing); }; const getListingCategory = (listing) => { const category = listing?.category || listing?.type || listing?.kind || 'Other'; return String(category).trim() || 'Other'; }; const getListingPrice = (listing) => { const rawPrice = listing?.price; if (typeof rawPrice === 'number') return rawPrice; if (typeof rawPrice === 'string') { const parsed = Number(rawPrice.replace(/[^0-9.-]+/g, '')); return Number.isFinite(parsed) ? parsed : 0; } return 0; }; const getListingId = (listing) => listing?.id || listing?._id || listing?.uuid; const categories = useMemo(() => { const items = collection?.items || []; const set = new Set(); items.forEach((item) => set.add(getListingCategory(item))); return ['all', ...Array.from(set).sort((a, b) => a.localeCompare(b))]; }, [collection?.items]); const priceRanges = [ { id: 'all', label: 'All prices', min: null, max: null }, { id: 'under-25', label: 'Under $25', min: 0, max: 25 }, { id: '25-100', label: '$25 - $100', min: 25, max: 100 }, { id: '100-250', label: '$100 - $250', min: 100, max: 250 }, { id: '250-plus', label: '$250+', min: 250, max: null } ]; const filteredItems = useMemo(() => { const items = collection?.items || []; const priceRange = priceRanges.find((range) => range.id === selectedPriceRange) || priceRanges[0]; return items.filter((listing) => { const category = getListingCategory(listing); const price = getListingPrice(listing); const categoryMatch = selectedCategory === 'all' || category.toLowerCase() === selectedCategory.toLowerCase(); const minMatch = priceRange.min === null || price >= priceRange.min; const maxMatch = priceRange.max === null || price < priceRange.max; return categoryMatch && minMatch && maxMatch; }); }, [collection?.items, selectedCategory, selectedPriceRange]); const filteredCollection = useMemo(() => { return { ...collection, items: filteredItems }; }, [collection, filteredItems]); const selectedListingWithShare = useMemo(() => { if (!selectedListing) return null; const listingId = getListingId(selectedListing); const shareUrl = listingId ? `${window.location.origin}${window.location.pathname}#listing=${encodeURIComponent(listingId)}` : window.location.href; return { ...selectedListing, shareUrl }; }, [selectedListing]); return (
Your neighborhood garage sale hub