Skip to content

fdhima/out-work

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

207 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

OutWork

OutWork is a mobile app for discovering and reviewing remote-work-friendly venues β€” cafes, co-working spaces, libraries, and more. Users can explore spots on a map, check real-time crowd levels, write reviews, and earn XP and badges through a gamification system.

This is an Expo project built with React Native, targeting iOS and Android.

Download on iOS


Architecture

Tech Stack

Layer Technology
Framework Expo (React Native) with Expo Router (file-based routing)
Language TypeScript (strict)
Backend Supabase (Postgres + Auth + Storage + Edge Functions)
Maps react-native-maps with Apple Maps (default provider)
Animations react-native-reanimated + react-native-gesture-handler
Images expo-image (optimized caching)
Auth storage expo-secure-store (native)

Directory Structure

/
β”œβ”€β”€ app/                          # Expo Router screens (file-based routing)
β”‚   β”œβ”€β”€ _layout.tsx               # Root layout β€” wraps everything in ThemeProvider, AuthProvider, FavoritesProvider
β”‚   β”œβ”€β”€ index.tsx                 # Entry redirect
β”‚   β”œβ”€β”€ (tabs)/                   # Main tab navigator (auth-gated)
β”‚   β”‚   β”œβ”€β”€ _layout.tsx           # Tab bar config, auth guard (redirects to signin if no session)
β”‚   β”‚   β”œβ”€β”€ index.tsx             # Map/Explore β€” fullscreen map with bottom sheet and cluster markers
β”‚   β”‚   β”œβ”€β”€ home.tsx              # Home β€” ranked card feed of places
β”‚   β”‚   β”œβ”€β”€ favorites.tsx         # Saved/favorited places list
β”‚   β”‚   β”œβ”€β”€ explore.tsx           # Post β€” form to submit a new workspace
β”‚   β”‚   β”œβ”€β”€ passport.tsx          # Gamification hub: XP, rank, badges, passport stamps, leaderboard
β”‚   β”‚   └── settings.tsx          # Profile & account settings
β”‚   β”œβ”€β”€ auth/                     # Auth screens (unauthenticated)
β”‚   β”‚   β”œβ”€β”€ signin.tsx
β”‚   β”‚   β”œβ”€β”€ signup.tsx
β”‚   β”‚   β”œβ”€β”€ reset-password.tsx
β”‚   β”‚   └── callback.tsx          # OAuth redirect handler
β”‚   β”œβ”€β”€ place/
β”‚   β”‚   └── [id].tsx              # Dynamic place detail screen
β”‚   β”œβ”€β”€ components/               # Screen-level components
β”‚   β”‚   β”œβ”€β”€ AirbnbBottomSheet.tsx # Draggable 3-state sheet (collapsed/half/full)
β”‚   β”‚   β”œβ”€β”€ ClusterMarker.tsx     # Map cluster bubble
β”‚   β”‚   β”œβ”€β”€ CrowdLevelModal.tsx   # Crowd report submission modal
β”‚   β”‚   β”œβ”€β”€ FilterModal.tsx       # Category/filter picker
β”‚   β”‚   β”œβ”€β”€ FloatingCard.tsx      # Preview card that slides up on map pin tap
β”‚   β”‚   β”œβ”€β”€ MapHeader.tsx         # Search bar + category chips pinned at top of map
β”‚   β”‚   β”œβ”€β”€ MapMarker.tsx         # Custom map pin showing rating
β”‚   β”‚   β”œβ”€β”€ PlaceDetailed.tsx     # Full place detail view (images, reviews, crowd stats)
β”‚   β”‚   β”œβ”€β”€ ReviewForm.tsx        # Star-rating + sub-rating review form
β”‚   β”‚   β”œβ”€β”€ ReviewsList.tsx       # Paginated reviews list
β”‚   β”‚   β”œβ”€β”€ ListingCard.tsx       # Compact place card
β”‚   β”‚   β”œβ”€β”€ ListingCardDetailed.tsx
β”‚   β”‚   β”œβ”€β”€ ListingRow.tsx        # Horizontal scrollable place row
β”‚   β”‚   β”œβ”€β”€ ImageCarousel.tsx
β”‚   β”‚   └── gamification/        # Gamification UI overlays
β”‚   β”‚       β”œβ”€β”€ BadgeAwardedSheet.tsx
β”‚   β”‚       β”œβ”€β”€ BadgeDetailSheet.tsx
β”‚   β”‚       β”œβ”€β”€ RankUpModal.tsx
β”‚   β”‚       └── XpToast.tsx
β”‚   β”œβ”€β”€ feedback.tsx
β”‚   β”œβ”€β”€ help.tsx
β”‚   β”œβ”€β”€ modal.tsx
β”‚   └── report-nsfw.tsx
β”‚
β”œβ”€β”€ components/                   # Shared primitive UI components
β”‚   └── ui/                       # Auth container, inputs, gallery, gradient button, icon symbols
β”‚
β”œβ”€β”€ context/                      # Global React context providers
β”‚   β”œβ”€β”€ AuthContext.tsx           # Session state + signOut; listens to supabase.auth.onAuthStateChange
β”‚   β”œβ”€β”€ FavoritesContext.tsx      # Favorites list with local + remote sync
β”‚   └── ThemeContext.tsx          # Light/dark mode
β”‚
β”œβ”€β”€ hooks/
β”‚   β”œβ”€β”€ useClusters.ts            # Geo-clustering logic for map markers (supercluster)
β”‚   └── use-color-scheme.ts       # Respects system preference + ThemeContext override
β”‚
β”œβ”€β”€ services/                     # All Supabase data access (no business logic in screens)
β”‚   β”œβ”€β”€ places.ts                 # CRUD for places; supports category filter + text search
β”‚   β”œβ”€β”€ reviews.ts                # Review CRUD
β”‚   β”œβ”€β”€ crowd.ts                  # Crowd reports: insert + aggregate by Β±2-hour window
β”‚   β”œβ”€β”€ favorites.ts              # User favorites persistence
β”‚   β”œβ”€β”€ gamification.ts           # XP grants, badge checks, passport stamps, leaderboard
β”‚   β”œβ”€β”€ images.ts                 # Image upload to Supabase Storage
β”‚   β”œβ”€β”€ categories.ts             # Workspace category lookup
β”‚   β”œβ”€β”€ places_categories.ts      # Many-to-many place↔category
β”‚   β”œβ”€β”€ profiles.ts               # User profile read/update
β”‚   └── users.ts                  # Auth user helpers
β”‚
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ supabase.ts               # Supabase client (SecureStore adapter on native, cookie on web)
β”‚   β”œβ”€β”€ auth/social.ts            # Google/Apple OAuth helpers
β”‚   β”œβ”€β”€ date.ts                   # Date formatting utilities
β”‚   └── imagePicker.ts            # Expo ImagePicker wrapper
β”‚
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ workingHours.ts           # Open/closed status calculation from working_hours JSON
β”‚   β”œβ”€β”€ location.ts               # Geolocation helpers
β”‚   └── transitions.ts            # Shared animation presets
β”‚
β”œβ”€β”€ constants/
β”‚   └── theme.ts                  # Brand colours, category list, shared style tokens
β”‚
β”œβ”€β”€ supabase/
β”‚   └── functions/
β”‚       └── delete-account/       # Deno Edge Function β€” deletes auth user via service-role key
β”‚
└── .eas/workflows/               # EAS CI/CD workflow definitions (preview, build, deploy)

Data Flow

Screen / Component
      β”‚
      β–Ό
  services/*          ← thin async functions, call supabase directly
      β”‚
      β–Ό
  lib/supabase.ts     ← single shared Supabase client
      β”‚
      β–Ό
  Supabase (Postgres + Auth + Storage)

Context providers (AuthContext, FavoritesContext) sit between the root layout and all screens, providing global state without prop-drilling. Individual screens call services/* directly for data fetching β€” there is no intermediate state management library (no Redux/Zustand).


Key Screens

Map screen ((tabs)/index.tsx) β€” The primary discovery surface. Renders a fullscreen MapView with custom MapMarker pins (show rating) and ClusterMarker bubbles for dense areas. A MapHeader floats at the top with a search input and horizontally-scrollable category chips. An Airbnb-style draggable bottom sheet (collapsed / half / full) contains a carousel of place cards. Tapping a pin hides the sheet and shows a FloatingCard preview; tapping the card navigates to the place detail screen.

Passport screen ((tabs)/passport.tsx) β€” Gamification hub. Displays the user's current rank (with animated rank badge), XP progress bar, earned badges grid, passport stamp map, and a weekly leaderboard.

Place detail (place/[id].tsx) β€” Full detail view with image carousel, open/closed status from working hours, crowd level indicator (with hourly bar chart), star rating breakdown, reviews list, and a crowd report submission modal.


Gamification System

Defined in services/gamification.ts:

Action XP
Write a review +50
Review with all sub-ratings filled +20
First ever review of a place +30
Submit a crowd report +15
Add a new place +100

Ranks (6 levels): Desk Lurker β†’ Coffee Scout β†’ WiFi Wanderer β†’ Office Nomad β†’ WorkNomad Pro β†’ Workspace Legend.

Badges are checked after every XP-granting action and inserted into user_badges when conditions are met (e.g. 10 crowd reports = "Crowd Whisperer", first review = "First Steps"). Neighborhood-completion badges are generated dynamically based on stamping every approved place in a city neighborhood.

Passport stamps are issued when a user submits a review for a place they haven't reviewed before, creating a geographic "visited" log displayed on the Passport screen.


Authentication

  • Email/password sign-up and sign-in via Supabase Auth
  • Google, Apple and Github OAuth (lib/auth/social.ts)
  • Session token persisted in expo-secure-store on native, browser cookies on web
  • AuthContext subscribes to onAuthStateChange and drives the tab navigator's auth guard
  • Account deletion handled by a Supabase Deno Edge Function (delete-account) using the service-role key so the user's auth record is fully removed

Crowd Level System

Users submit reports via services/crowd.ts with { place_id, day_of_week, time_bucket, crowd_level }. The current crowd level for a place is computed as the mode of all reports within a Β±2-hour window for the current day and hour. Confidence is "high" when β‰₯ 10 reports exist, "low" otherwise. A separate hourly bar chart query shows typical busy times for the current day of the week.


Get started

To start the app, in your terminal run:

npm run start

In the output, you'll find options to open the app in:

You can start developing by editing the files inside the app directory. This project uses file-based routing.

Workflows

This project is configured to use EAS Workflows to automate some development and release processes. These commands are set up in package.json and can be run using NPM scripts in your terminal.

Previews

Run npm run draft to publish a preview update of your project, which can be viewed in Expo Go or in a development build.

Development Builds

Run npm run development-builds to create a development build. Note - you'll need to follow the Prerequisites to ensure you have the correct emulator setup on your machine.

Production Deployments

Run npm run deploy to deploy to production. Note - you'll need to follow the Prerequisites to ensure you're set up to submit to the Apple and Google stores.

Hosting

Expo offers hosting for websites and API functions via EAS Hosting. See the Getting Started guide to learn more.

Get a fresh project

When you're ready, run:

npm run reset-project

This command will move the starter code to the app-example directory and create a blank app directory where you can start developing.

Learn more

To learn more about developing your project with Expo, look at the following resources:

Join the community

Join our community of developers creating universal apps.

About

OutWork's source code

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors