Places is a web application for browsing property listings on a map of Dubai. The core idea is to make map exploration, search, and sorting fast, shareable, and practical for large datasets.
Places provides a split experience:
- a map with interactive pins and popups
- a virtualized sidebar list for mapped/unmapped properties
- URL-driven search and sorting so state is shareable/bookmarkable
- Next.js 15.1.12 + React 19.2.1: Server Components + client interactivity.
- nuqs: URL query parameters as the main UI state store.
- React Hook Form + Zod: Typed form state and validation.
- Tailwind CSS v4: Utility-first styling.
- DaisyUI 5.5.18 (stable): UI primitives built on Tailwind.
- @vis.gl/react-maplibre + maplibre-gl: Interactive map rendering.
- @tanstack/react-virtual: Efficient rendering for long property lists.
- Supabase: Primary data store.
- Next.js server functions/actions: Property query and mutation boundaries.
- Vitest + Testing Library + jsdom: Behavior-oriented unit/component testing.
- Interactive Map: Property markers with selection and contextual popup cards.
- Sidebar Property List: Mapped and unmapped tabs with virtualized rendering.
- Search: URL-driven query state.
- Sort: URL-driven sorting by property name, community, and subcommunity.
- Add/Edit Property: Drawer-based editing flow with validated form inputs.
- Responsive Layout: Desktop split-pane + mobile drawer experience.
The app keeps map/list state in URL params so users can share and restore exact UI state:
- selected property
- map coordinates/zoom
- search query
- sorting options
Zod schemas validate URL state for predictable behavior.
The project now follows a clear component boundary pattern:
ui/components focus on rendering and compositionmodel/hooks/owns interaction and state orchestrationmodel/helpers/contains pure model-support logicconfig/stores constants and UI tokens
This keeps components presentational while making behavior easy to test.
src/components/
map/
ui/
model/
hooks/
helpers/
config/
__tests__/
properties/
ui/
model/
hooks/
helpers/
config/
__tests__/
Supabase clients are split by runtime:
- browser client (
src/utils/supabase/client.ts) - server client (
src/utils/supabase/server.ts) - request/session refresh flow through
proxy.ts+updateSession
Environment key resolution is compatibility-first and checks:
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEYNEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYNEXT_PUBLIC_SUPABASE_ANON_KEY
The app keeps a schema-first mapping pipeline:
- validate external data with Zod
- normalize DTO shapes
- map into render-friendly RTOs
This keeps UI resilient when data quality is inconsistent.
- Upgraded and stabilized UI/tooling stack (DaisyUI stable, latest Supabase SSR libs).
- Improved sort behavior for direction-only URL states.
- Fixed dropdown placement/padding and active-state readability.
- Fixed modal drawer id collisions that caused incorrect dialog behavior.
- Improved query failure diagnostics and development fallback handling.
- Expanded test coverage for extracted hooks/helpers and sort/dropdown behavior.
To address the React Server Components security advisory, this project is pinned to patched versions:
next@15.1.12react@19.2.1react-dom@19.2.1
Run tests:
npm run testWatch mode:
npm run test:watchCoverage:
npm run test:coverage- Geocoding: Replace fallback/random coordinate behavior with deterministic geocoding.
- Data quality contracts: Tighten schema guarantees for production data.
- Search depth: Add richer search dimensions beyond current text fields.
- Mutation UX: Continue polishing add/edit flows and edge-case handling.
-
Install dependencies:
npm install
-
Create
.env.localwith Supabase values:NEXT_PUBLIC_SUPABASE_URL=... NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY=...
(Alternative key names are supported by the app, but the above is the current default in this repo.)
-
Start development server:
npm run dev
Optional Turbopack mode:
npm run dev:turbo
-
Build for production:
npm run build
-
Start production server:
npm start
Places remains focused on practical, map-first property browsing, now with clearer component boundaries, stronger runtime resilience, improved dropdown/modal behavior, and broader automated test coverage.




