Your Favorites
Saved spaces synced to your personal collection.
No favorites yet
Save spaces from cards or detail views to build your personal collection.
import { useEffect, useMemo, useState } from 'react'; import { useCollection, useReactions, share } from '@deplixo/sdk'; import { SpaceDirectory } from './components/SpaceDirectory.jsx'; import { SpaceMap } from './components/SpaceMap.jsx'; import { SpaceDetail } from './components/SpaceDetail.jsx'; import { AddSpaceForm } from './components/AddSpaceForm.jsx'; function App() { const [activeTab, setActiveTab] = useState('list'); const [selectedSpace, setSelectedSpace] = useState(null); const [showAddForm, setShowAddForm] = useState(false); const [filters, setFilters] = useState({ amenities: [], priceRange: 'all', search: '', nearMe: false, sortBy: 'relevance', favoritesOnly: false }); const [userLocation, setUserLocation] = useState(null); const [locationStatus, setLocationStatus] = useState('idle'); const [locationError, setLocationError] = useState(''); const [shareStatus, setShareStatus] = useState(''); const { items: favoriteItems, loading: favoritesLoading, add: addFavoriteRecord, remove: removeFavoriteRecord, search: searchFavorites, } = useCollection('space-favorites', { personal: true }); useEffect(() => { if (!navigator.geolocation) { setLocationStatus('unsupported'); return; } setLocationStatus('locating'); navigator.geolocation.getCurrentPosition( (position) => { const nextLocation = { lat: position.coords.latitude, lng: position.coords.longitude }; if (nextLocation && typeof nextLocation.lat === 'number' && typeof nextLocation.lng === 'number') { setUserLocation(nextLocation); setLocationStatus('ready'); setLocationError(''); } else { setLocationStatus('error'); setLocationError('Unable to determine your location.'); } }, (error) => { setLocationStatus('error'); setLocationError(error && error.message ? error.message : 'Unable to determine your location.'); }, { enableHighAccuracy: true, timeout: 10000, maximumAge: 300000 } ); }, []); const tabs = [ { id: 'list', label: '📋 Directory', icon: '📋' }, { id: 'map', label: '🗺️ Map View', icon: '🗺️' }, { id: 'favorites', label: '⭐ Favorites', icon: '⭐' }, ]; const favoriteIds = useMemo(() => { return new Set( (favoriteItems || []) .map((item) => item?.spaceId || item?.targetId || item?.id || item?.space?.id) .filter(Boolean) .map(String) ); }, [favoriteItems]); const isFavorite = (spaceId) => favoriteIds.has(String(spaceId)); const favoriteSpace = async (space) => { if (!space || !space.id || isFavorite(space.id)) return; await addFavoriteRecord({ spaceId: space.id, spaceSnapshot: space, createdAt: new Date().toISOString(), }); }; const unfavoriteSpace = async (space) => { if (!space || !space.id) return; const match = (favoriteItems || []).find((item) => String(item?.spaceId || item?.targetId || item?.space?.id || item?.id) === String(space.id)); if (match?.id) { await removeFavoriteRecord(match.id); return; } const bySearch = await searchFavorites(String(space.id)); const fallbackMatch = (bySearch || []).find((item) => String(item?.spaceId || item?.targetId || item?.space?.id || item?.id) === String(space.id)); if (fallbackMatch?.id) { await removeFavoriteRecord(fallbackMatch.id); } }; const handleToggleFavorite = async (space) => { if (isFavorite(space?.id)) { await unfavoriteSpace(space); } else { await favoriteSpace(space); } }; const favoriteSpaces = useMemo(() => { return (favoriteItems || []) .map((item) => item?.spaceSnapshot || item?.space || item) .filter((space) => space && space.id); }, [favoriteItems]); const buildSharePayload = (space) => { if (!space?.id) return null; const title = space.name || 'Recommended coworking space'; const url = typeof window !== 'undefined' ? `${window.location.origin}${window.location.pathname}?space=${encodeURIComponent(space.id)}` : `?space=${encodeURIComponent(space.id)}`; const summary = `${title}${space.address ? ` • ${space.address}` : ''}`; const payload = { title, text: summary, url, spaceId: space.id, space, }; return payload; }; const shareSpace = async (space) => { const payload = buildSharePayload(space); if (!payload) return; try { if (navigator.share) { await navigator.share({ title: payload.title, text: payload.text, url: payload.url, }); setShareStatus(`Shared ${payload.title}`); return; } const shareText = `${payload.title}\n${payload.text}\n${payload.url}`; if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(shareText); setShareStatus(`Share link copied for ${payload.title}`); return; } window.prompt('Copy this share link:', shareText); setShareStatus(`Share payload ready for ${payload.title}`); } catch (error) { setShareStatus(error?.message ? error.message : 'Unable to share this space right now.'); } }; const handleShareRecommended = async (spaces) => { const recommended = Array.isArray(spaces) ? spaces.filter(Boolean) : []; if (!recommended.length) return; if (recommended.length === 1) { await shareSpace(recommended[0]); return; } const topSpace = recommended[0]; const payload = { title: `Top recommended spaces: ${recommended.slice(0, 3).map((space) => space.name).filter(Boolean).join(', ')}`, text: recommended.slice(0, 3).map((space, index) => `${index + 1}. ${space.name || 'Untitled space'}${space.address ? ` — ${space.address}` : ''}`).join('\n'), url: typeof window !== 'undefined' ? `${window.location.origin}${window.location.pathname}?space=${encodeURIComponent(topSpace.id)}` : `?space=${encodeURIComponent(topSpace.id)}`, spaces: recommended.map((space) => ({ id: space.id, name: space.name, address: space.address })), }; try { if (navigator.share) { await navigator.share({ title: payload.title, text: payload.text, url: payload.url, }); setShareStatus('Shared recommended spaces'); return; } const shareText = `${payload.title}\n\n${payload.text}\n\n${payload.url}`; if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(shareText); setShareStatus('Recommended spaces share link copied'); return; } window.prompt('Copy this share payload:', shareText); setShareStatus('Recommended spaces share payload ready'); } catch (error) { setShareStatus(error?.message ? error.message : 'Unable to share recommendations right now.'); } }; return (
Your co-working space directory
Saved spaces synced to your personal collection.
Save spaces from cards or detail views to build your personal collection.