A React Native app that helps Victorian residents find waste collection information for their addresses. Simply search for your address and get up-to-date bin collection dates for landfill, recycling, food & garden waste, glass, and hard waste services.
- 🔍 Address Search: Search for any Victorian address using Google Places Autocomplete with location restriction
- 📅 Collection Dates: View upcoming collection dates for all waste types with "Today" and "Tomorrow" highlighting
- 🏛️ Council Support: Currently supports 33 Victorian councils with more being added
- 📱 Cross-Platform: Works on iOS, Android, and web browsers
- 🌓 Dark Mode: Automatic theme switching based on device preferences
- ✨ Smooth Animations: Polished UI with React Native Reanimated
- 🎯 Smart Search: Distance-based result selection for accurate address matching
Currently supporting the following Victorian councils:
- Alpine Shire
- Banyule City
- Baw Baw Shire
- Bayside City
- Campaspe Shire
- City of Ballarat
- City of Kingston
- City of Monash
- City of Whittlesea
- Colac Otway Shire
- Gannawarra Shire
- Greater Dandenong City
- Greater Shepparton City
- Hume City
- Loddon Shire
- Macedon Ranges Shire
- Mansfield Shire
- Maribyrnong City
- Maroondah City
- Melton City
- Mildura Rural City
- Moorabool Shire
- Mornington Peninsula Shire
- Mount Alexander Shire
- Moyne Shire
- Nillumbik Shire
- Pyrenees Shire
- Stonnington City
- Surf Coast Shire
- Swan Hill Rural City
- Wangaratta Rural City
- Yarra Ranges Shire
More councils are being added regularly!
- Frontend: React Native 0.79.5 with Expo SDK 53
- Navigation: Expo Router v5 (file-based routing)
- Backend: Convex 1.25.2 (serverless functions)
- Language: TypeScript 5.8.3 (strict mode)
- State Management: Zustand 5.0.2
- Animations: React Native Reanimated 3.17.4
- Date Handling: Luxon 3.7.1
- Styling: React Native StyleSheet with theme support
- Code Quality: ESLint + Biome
- External APIs: Google Places API, Council waste APIs
- Node.js 18+ and Bun installed
- Expo CLI (
bun add -g expo) - iOS Simulator (Mac only) or Android Emulator
- Convex account for backend services
- Google Cloud account with Places API enabled
-
Clone the repository:
git clone https://github.com/yourusername/bin-day.git cd bin-day -
Install dependencies:
bun install
-
Set up environment variables:
Create a
.env.localfile with:EXPO_PUBLIC_CONVEX_URL=your_convex_deployment_url
-
Set up Convex environment variables:
In your Convex dashboard, add:
GOOGLE_PLACES_API_KEY- Your Google Places API key
-
Start the development server:
bun run start
After starting the development server, you can:
- Press
ito open in iOS Simulator - Press
ato open in Android Emulator - Press
wto open in web browser - Scan the QR code with Expo Go app on your physical device
bin-day/
├── app/ # Expo Router screens and layouts
│ ├── _layout.tsx # Root layout with providers
│ ├── index.tsx # Main home screen
│ └── +not-found.tsx # 404 screen
├── components/ # Reusable React components
│ ├── address/ # Address display components
│ ├── common/ # Common UI components
│ ├── search/ # Search-related components
│ ├── ui/ # Platform-specific UI components
│ └── waste/ # Waste collection components
├── convex/ # Backend functions
│ ├── councils/ # Council implementations
│ │ ├── core/ # Shared utilities and types
│ │ ├── providers/ # Third-party API integrations
│ │ │ ├── granicus/ # Granicus API (most councils)
│ │ │ └── whatbinday/ # WhatBinDay API
│ │ └── implementations/ # Individual council APIs
│ ├── councilServices.ts # Main orchestrator
│ └── googlePlaces.ts # Google Places integration
├── constants/ # App constants and theme colors
├── hooks/ # Custom React hooks
├── lib/ # Utility functions
├── stores/ # Zustand state management
├── types/ # TypeScript type definitions
├── utils/ # Helper functions
└── CLAUDE.md # AI assistant instructions
bun run start # Start Expo dev server
bun run android # Run on Android
bun run ios # Run on iOS
bun run web # Run in browser
bun run lint # Run ESLint
bun run check:fix # Format and lint with Biome
bun run check-types # TypeScript type checking
bun run build:simulator:ios # Build for iOS simulatorThe project uses:
- ESLint with Expo config for linting
- Biome for formatting (tab indentation, double quotes)
- TypeScript in strict mode with path aliases
- GitHub Actions for automated PR reviews with Claude
- Pre-configured VSCode settings for optimal development
- State Management: Zustand with separate slices for search, address, and council data
- Animation System: Unified animation management with consistent bezier curves
- Error Handling: Standardized error classes and user-friendly error messages
- Performance: Optimized FlatList rendering, debounced search, and proper memoization
- Type Safety: Strict TypeScript with generated Convex types
- Platform-Specific: Separate implementations for iOS/Android where needed
-
Identify API Provider:
- Check if the council uses Granicus (most common - look for
/api/v1/myarea/searchendpoints) - Check if the council uses WhatBinDay
- Determine if custom implementation is needed
- Check if the council uses Granicus (most common - look for
-
Create Implementation in
convex/councils/implementations/[councilName].ts -
For Granicus councils (most common):
import type { GooglePlaceDetails } from "@/types/googlePlaces"; import { COUNCIL_NAMES } from "../core"; import { processGranicusCouncilData, type WasteTypeRegexPatterns, } from "../providers/granicus"; const wastePatterns: WasteTypeRegexPatterns = { landfillWaste: /general-waste[\s\S]*?<div class="next-service">\s*([\s\S]*?)\s*<\/div>/, recycling: /recycling[\s\S]*?<div class="next-service">\s*([\s\S]*?)\s*<\/div>/, foodAndGardenWaste: /green-waste[\s\S]*?<div class="next-service">\s*([\s\S]*?)\s*<\/div>/, }; export async function fetchCouncilData(placeDetails: GooglePlaceDetails) { return processGranicusCouncilData( placeDetails, COUNCIL_NAMES.COUNCIL_NAME, { searchApiUrl: "https://council.vic.gov.au/api/v1/myarea/search", wasteServicesUrl: "https://council.vic.gov.au/ocapi/Public/myarea/wasteservices", wasteTypePatterns: wastePatterns, } ); }
-
For WhatBinDay councils:
import type { GooglePlaceDetails } from "@/types/googlePlaces"; import { COUNCIL_NAMES } from "../core"; import { processWhatBinDayCouncilData } from "../providers/whatbinday"; export async function fetchCouncilData(placeDetails: GooglePlaceDetails) { return processWhatBinDayCouncilData(placeDetails, COUNCIL_NAMES.COUNCIL_NAME); }
Note: Add the council's API key to
WHATBINDAY_API_KEYSinconvex/councils/providers/whatbinday/constants.ts -
Add the council name to
COUNCIL_NAMESinconvex/councils/core/types.ts -
Register the handler in
convex/councilServices.ts -
Update the Convex schema with the new council literal
-
Test with real addresses from the council area
-
Update this README with the new council
All councils return waste collection data in this standardized format:
{
landfillWaste: number | null; // Unix timestamp
recycling: number | null; // Unix timestamp
foodAndGardenWaste: number | null; // Unix timestamp
hardWaste: number | null; // Unix timestamp
glass: number | null; // Unix timestamp
}Contributions are welcome! Please:
- Fork the repository
- Create a feature branch following the naming convention:
feat/for new featuresfix/for bug fixeschore/for maintenancedocs/for documentation
- Ensure all checks pass (type checking, linting, formatting)
- Commit your changes with clear messages
- Push to your branch and open a Pull Request
- Use the
@/*import alias for all internal imports - Follow existing component patterns with React.memo for performance
- Add proper TypeScript types for all props and state
- Include accessibility props (labels, hints) on interactive elements
- Test on both iOS and Android platforms
- Ensure animations are smooth and properly cleaned up
EXPO_PUBLIC_CONVEX_URL- Your Convex deployment URL
GOOGLE_PLACES_API_KEY- Google Places API key with Places API enabled
- Address not found: Ensure the address is within Victoria, Australia
- Council not supported: Check the supported councils list above
- No collection dates: Some councils may not provide all waste types
- API errors: Check your Google Places API key and quotas
To enable detailed logging, you can use the Expo development menu and enable "Debug Remote JS" for Chrome DevTools debugging.
This project is licensed under the MIT License - see the LICENSE.md file for details.
- Built with Expo and React Native
- Backend powered by Convex
- Address search by Google Places API
- Council data from respective Victorian council APIs
- State management by Zustand
- Animations by React Native Reanimated
- Date handling by Luxon
For questions, bug reports, or feature requests, please open an issue on GitHub.