https://github.com/teeldinho/places
Places is a Next.js 15 web application that allows users to browse property listings on an interactive map, with features for filtering, sorting, and viewing property details. It utilizes Supabase for data storage, nuqs for URL-based state management, and Maplibre GL JS for map rendering.
https://github.com/teeldinho/places
maplibre maps next15 nuqs supabase zod
Last synced: 3 months ago
JSON representation
Places is a Next.js 15 web application that allows users to browse property listings on an interactive map, with features for filtering, sorting, and viewing property details. It utilizes Supabase for data storage, nuqs for URL-based state management, and Maplibre GL JS for map rendering.
- Host: GitHub
- URL: https://github.com/teeldinho/places
- Owner: Teeldinho
- Created: 2025-02-11T21:14:30.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2025-02-13T10:08:04.000Z (over 1 year ago)
- Last Synced: 2025-02-13T10:32:57.422Z (over 1 year ago)
- Topics: maplibre, maps, next15, nuqs, supabase, zod
- Language: TypeScript
- Homepage: https://places.teeldinho.co.za
- Size: 9.97 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Places
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.
## Project Overview
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

## Tech Stack
### Frontend
- **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.
### Backend
- **Supabase**: Primary data store.
- **Next.js server functions/actions**: Property query and mutation boundaries.
### Testing
- **Vitest + Testing Library + jsdom**: Behavior-oriented unit/component testing.
## Key Features
- **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.
## Architectural Decisions
### URL as State Store (`nuqs`)
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.
### Separation of Concerns
The project now follows a clear component boundary pattern:
- `ui/` components focus on rendering and composition
- `model/hooks/` owns interaction and state orchestration
- `model/helpers/` contains pure model-support logic
- `config/` stores constants and UI tokens
This keeps components presentational while making behavior easy to test.
### Current Component Structure (non-FSD, pragmatic)
```text
src/components/
map/
ui/
model/
hooks/
helpers/
config/
__tests__/
properties/
ui/
model/
hooks/
helpers/
config/
__tests__/
```
### Supabase SSR Integration
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:
1. `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY`
2. `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`
3. `NEXT_PUBLIC_SUPABASE_ANON_KEY`
### Data Flow
The app keeps a schema-first mapping pipeline:
1. validate external data with Zod
2. normalize DTO shapes
3. map into render-friendly RTOs
This keeps UI resilient when data quality is inconsistent.
## Recent Improvements
- 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.
## Security Note (React RSC Advisory)
To address the React Server Components security advisory, this project is pinned to patched versions:
- `next@15.1.12`
- `react@19.2.1`
- `react-dom@19.2.1`
## Testing
Run tests:
```bash
npm run test
```
Watch mode:
```bash
npm run test:watch
```
Coverage:
```bash
npm run test:coverage
```
## Areas of Improvement
- **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.
## Getting Started
1. Install dependencies:
```bash
npm install
```
2. Create `.env.local` with Supabase values:
```bash
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.)
3. Start development server:
```bash
npm run dev
```
Optional Turbopack mode:
```bash
npm run dev:turbo
```
4. Build for production:
```bash
npm run build
```
5. Start production server:
```bash
npm start
```
## Screenshots





## Conclusion
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.