Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions frontend-challenge/tennis-courts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# dependencies
node_modules/

# Expo
.expo/
dist/
web-build/
expo-env.d.ts

# Native
.kotlin/
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision

# Metro
.metro-health-check*

# debug
npm-debug.*
yarn-debug.*
yarn-error.*

# macOS
.DS_Store
*.pem

# local env files
.env*.local

# typescript
*.tsbuildinfo

# generated native folders
/ios
/android
49 changes: 49 additions & 0 deletions frontend-challenge/tennis-courts/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { StatusBar } from 'expo-status-bar';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { CourtListScreen } from './src/screens/CourtListScreen';
import { CourtDetailScreen } from './src/screens/CourtDetailScreen';
import { RootStackParamList } from './src/types/Court';

const Stack = createNativeStackNavigator<RootStackParamList>();

export default function App() {
return (
<NavigationContainer>
<StatusBar style="dark" />
<Stack.Navigator
initialRouteName="Courts"
screenOptions={{
headerStyle: {
backgroundColor: '#FFF',
},
headerTintColor: '#222',
headerTitleStyle: {
fontWeight: 'bold',
fontSize: 18,
},
contentStyle: {
backgroundColor: '#F8F9FA',
},
}}
>
<Stack.Screen
name="Courts"
component={CourtListScreen}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="CourtDetail"
component={CourtDetailScreen}
options={{
title: 'Court Details',
headerBackTitle: 'Back',
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
89 changes: 89 additions & 0 deletions frontend-challenge/tennis-courts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Tennis Courts Review App

A mobile-first React Native application for browsing and reviewing tennis courts. Built with Expo and TypeScript.

## Features

- 55+ tennis courts with search functionality
- Court detail views with ratings and reviews
- Add review capability with star ratings
- Modern, mobile-optimized UI
- Full TypeScript implementation

## Installation

```bash
cd tennis-courts
npm install
npx expo start
```

## Running the App

- **Mobile**: Scan QR code with Expo Go app
- **Web**: Press `w` or visit http://localhost:8081

## Project Structure

```
src/
├── types/Court.ts # TypeScript interfaces
├── data/courts.ts # Mock data (55 courts)
├── components/ # Reusable UI components
└── screens/ # Main screens (List, Detail)
```

## Technologies

- React Native + Expo SDK 54
- TypeScript
- React Navigation v6

## AI-Assisted Development

This project leveraged GitHub Copilot to accelerate development while maintaining full architectural control. AI was used strategically for scaffolding, mock data generation, and debugging guidance.

### Prompts Used

**Prompt 1:**
```
I'm building a mobile-first React Native app for a tennis court review flow. I already have the architecture in mind, but I want a clean implementation pattern for a searchable court list and a court detail screen where users can read and add reviews. The app uses mock data (50+ courts) and only needs local state. Please provide guidance consistent with Expo + TypeScript best practices.
```

**Prompt 2:**
```
Generate a simple and well-organized Expo TypeScript project setup using React Navigation with two screens. I only want the essential scaffolding so I can layer in the feature work myself.
```

**Prompt 3:**
```
Create a mock dataset of around 55 tennis courts with predictable structure, including id, name, location, an Unsplash image URL, indoor/outdoor information, surface type, and a few sample reviews per court. Keep the output clean and easy to integrate with TypeScript types.
```

**Prompt 4:**
```
I need a quick reference implementation for the core UI pieces: a reusable SearchBar, a CourtCard for list rendering, a ReviewItem, and a simple AddReviewForm. Keep the implementations lightweight and mobile-friendly so I can refine the styling and UX myself.
```

### Approach

AI accelerated initial setup and boilerplate code while I maintained control over:
- Component architecture and state management
- UI/UX refinements and styling decisions
- Performance optimizations (FlatList, useMemo)
- Debugging React Native Fabric compatibility issues

## Challenge Compliance

✅ Mobile-first design
✅ Two-page app (List + Detail)
✅ Search functionality
✅ Court detail view with reviews
✅ Add review capability
✅ React Native (preferred framework)
✅ 55 courts (> 50 bonus)
✅ All AI prompts documented

---

*Built by Aditya Bhuran for BYOB Sports Frontend Challenge (December 2024)*
30 changes: 30 additions & 0 deletions frontend-challenge/tennis-courts/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"expo": {
"name": "tennis-courts",
"slug": "tennis-courts",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"newArchEnabled": true,
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend-challenge/tennis-courts/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions frontend-challenge/tennis-courts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { registerRootComponent } from 'expo';

import App from './App';

// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
Loading