CafeQuest is a location-based cafe discovery web application that helps coffee lovers find nearby cafes using real-time data from OpenStreetMap. Built with Next.js 15 and Firebase, it features an interactive Mapbox map, smart filtering options, and the ability to save favorite cafes to a personal dashboard.
- 🗺️ Interactive Mapbox Map with custom cafe markers and real-time user location
- 🔍 Google Places Autocomplete for intelligent location search
- 🎯 Smart Filtering - Hide chains (Tim Hortons, Starbucks) and find late-night cafes (open ≥ 9pm)
- 💾 Personal Dashboard with Firebase Firestore to save and manage favorite cafes
- 🔐 Secure Authentication with Firebase Auth and protected routes
- 📱 Responsive Design with mobile-optimized navigation
- ⚡ Performance Optimized with API request caching and rate limiting
- 📍 Location Search – Google Places autocomplete with fallback to Nominatim API
- 🗺️ Mapbox Integration – Interactive map powered by Mapbox GL JS and react-map-gl
- 📌 GPS Location – Automatic user location detection with geolocation API
- ☕ Real-time Cafe Data – Fetches cafes from OpenStreetMap via Overpass API (5km radius)
- 🔍 Smart Filters:
- Hide Tim Hortons
- Hide Starbucks
- Show only late-night cafes (open ≥ 9pm)
- 💾 Save Cafes – Bookmark cafes with name, address, and opening hours
- 🗑️ Manage Favorites – Delete cafes from your saved list
- 📊 Cafe Details – View address, opening hours, and link to Google Maps
- 🔒 Protected Routes – Dashboard and profile require authentication
- 🎨 Chakra UI – Modern component library with dark mode support
- ⚡ API Optimization:
- Request caching (30-minute expiration)
- Rate limiting (1 request/second)
- Debounced search input (400ms)
- 🔔 Toast Notifications – User feedback for all actions
- 📱 Responsive UI – Mobile menu with Avatar dropdown
- 🎭 Loading States – Spinners for async operations
- 🔥 Firebase Integration:
- Email/password authentication
- Firestore for user data and saved cafes
- Security rules for data protection
- 📈 Vercel Analytics – Built-in analytics tracking
- Next.js 15 – React framework with App Router
- React 18 – UI library
- Chakra UI – Component library with built-in dark mode
- Mapbox GL JS + react-map-gl – Interactive maps
- react-icons – Icon library (FaHeart for save button)
- Custom Fonts – Geist Sans & Geist Mono (local fonts)
- Firebase Auth – User authentication (email/password)
- Firestore – NoSQL database for user profiles and saved cafes
- Google Places API – Location autocomplete
- Nominatim API – Fallback geocoding service
- Overpass API – Query OpenStreetMap for cafe data
- Mapbox API – Map tiles and rendering
- Vercel Analytics – Usage tracking
- axios – HTTP client for API requests
- lodash.debounce – Debounce search input
- use-places-autocomplete – Google Places autocomplete hook
- Jest – Testing framework
- @testing-library/react – Component testing
- Babel – JavaScript compiler for tests
- ESLint – Code linting
- Node.js 18+ (Download)
- Firebase Project with Firestore and Authentication enabled (Setup Guide)
- Google Maps API Key with Places API enabled (Get API Key)
- Mapbox Access Token (Sign up)
- Clone the repository
git clone https://github.com/imRanDan/cafequest.git
cd cafequest- Install dependencies
npm install- Configure environment variables
Create a .env.local file in the root directory:
# Firebase Configuration
NEXT_PUBLIC_FIREBASE_API_KEY=your_firebase_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=your_measurement_id
# Google Maps API Key
NEXT_PUBLIC_GOOGLE_API_KEY=your_google_maps_api_key
# Mapbox Access Token
NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=your_mapbox_token- Set up Firebase Firestore Security Rules
In your Firebase Console, navigate to Firestore Database > Rules and add:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// User documents
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
// Saved cafes subcollection
match /savedCafes/{cafeId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
// Visited cafes subcollection (passport)
match /visitedCafes/{cafeId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
// Cafe votes collection - community voting system
match /cafeVotes/{cafeId} {
// Allow anyone to read votes (for displaying aggregated results)
allow read: if true;
// Votes subcollection
match /votes/{userId} {
// Users can read all votes (for aggregation)
allow read: if true;
// Users can only write their own vote
allow create, update: if request.auth != null && request.auth.uid == userId;
// Users can delete their own vote
allow delete: if request.auth != null && request.auth.uid == userId;
}
}
}
}-
Enable Authentication in Firebase
- Go to Firebase Console > Authentication
- Enable "Email/Password" sign-in method
-
Run the development server
npm run devOpen http://localhost:3000 in your browser.
Run the test suite:
npm testCurrent test coverage includes:
Map.test.jsx– Map component rendering and interactionsSearchBar.test.jsx– Search functionality
cafequest/
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── dashboard/ # User dashboard (protected)
│ │ │ └── page.jsx # Displays saved cafes as cards
│ │ ├── profile/ # User profile (protected)
│ │ │ └── page.jsx # User info and logout
│ │ ├── login/ # Login page
│ │ │ └── page.jsx # Email/password login
│ │ ├── signup/ # Sign up page
│ │ │ └── page.jsx # User registration with Firestore
│ │ ├── layout.js # Root layout with Navbar, Footer, Providers
│ │ ├── page.js # Homepage with map and filters
│ │ └── globals.css # Global styles
│ ├── components/ # React components
│ │ ├── Map.jsx # Mapbox map with markers & popups
│ │ ├── CafeCard.jsx # Cafe card for dashboard
│ │ ├── LocationSearchInput.jsx # Google Places autocomplete
│ │ ├── Navbar.jsx # Navigation with auth state
│ │ ├── Footer.jsx # Footer component
│ │ ├── LoadingSpinner.jsx # Loading indicator
│ │ └── ... # Other UI components
│ ├── config/ # Configuration files
│ │ └── firebase.js # Firebase initialization
│ ├── utils/ # Utility functions
│ │ ├── AuthProvider.js # Auth context provider
│ │ └── ThemeProvider.js # Theme context provider
│ ├── providers/ # Context providers
│ │ └── Providers.jsx # Combines all providers
│ └── styles/ # Additional styles
├── images/ # Screenshots
├── jest.config.js # Jest configuration
├── jest.setup.js # Jest setup file
├── package.json # Dependencies
└── README.md
- User types in the search box (powered by Google Places autocomplete)
- User selects a location or clicks "Search"
- Location is geocoded to latitude/longitude
- Overpass API fetches cafes within 5km radius
- Results are cached for 30 minutes
- Markers appear on the Mapbox map
- Hide Tim Hortons/Starbucks: Filters by cafe name
- Open Late: Parses
opening_hourstag from OSM data, excludes cafes closing before 9pm
- User clicks marker on map → popup appears
- User clicks "Save" button
- Checks if user is logged in (Firebase Auth)
- Saves to Firestore:
users/{userId}/savedCafes/{cafeId} - Toast notification confirms save
- Cafe appears on dashboard
-
Browse Cafes
- Visit homepage
- Allow location access or search for a city/postal code
- Click "Show cafes near me" or use the search bar
-
Filter Results
- Toggle switches to hide Tim Hortons or Starbucks
- Enable "Open late" to find cafes open past 9pm
-
Create Account
- Click "Sign Up"
- Enter full name, email, and password
- Account is created in Firebase
-
Save Cafes
- Click any cafe marker on the map
- View details in the popup
- Click "Save" (requires login)
- Access saved cafes from Dashboard
-
Manage Favorites
- Navigate to Dashboard
- View all saved cafes as cards
- Click "Delete" to remove
- Mapbox integration with custom markers
- Google Places autocomplete search
- GPS location detection
- Smart filters (chains, late-night)
- User authentication with Firebase
- Save cafes to Firestore
- User dashboard with cafe cards
- Delete saved cafes
- Responsive mobile design
- API caching and rate limiting
- Search/filter within saved cafes
- Cafe photos from Google Places API
- User reviews and ratings
- Share cafes with friends
- PWA support for offline access
- Email verification
- Password reset functionality
Contributions are welcome! Please follow these steps:
- Fork the project
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.
Danyal Imran
- Portfolio: danyalimran.com
- GitHub: @imRanDan
- LinkedIn: Danyal Imran
- Next.js – React framework
- Chakra UI – Component library
- Mapbox – Map tiles and API
- OpenStreetMap – Cafe data source
- Firebase – Authentication and database
- Google Maps Platform – Places API
- Vercel – Deployment and hosting
This project implements several optimizations:
- Caching: API responses cached for 30 minutes
- Rate Limiting: Max 1 request per second to Overpass API
- Debouncing: Search input debounced to 400ms
- Request Limiting: Display limit of 10 markers initially, loads more on map movement
Made with ☕ by Danyal Imran
⭐ Star this repo if you found it helpful!


