diff --git a/frontend-challenge/App.js b/frontend-challenge/App.js
new file mode 100644
index 000000000..73784011f
--- /dev/null
+++ b/frontend-challenge/App.js
@@ -0,0 +1,28 @@
+import React, { useState } from 'react';
+import { NavigationContainer } from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import CourtListScreen from './CourtListScreen';
+import CourtDetailScreen from './CourtDetailScreen';
+
+const Stack = createNativeStackNavigator();
+
+export default function App() {
+ const [reviewsByCourt, setReviewsByCourt] = useState({});
+
+ return (
+
+
+
+
+ {props => (
+
+ )}
+
+
+
+ );
+}
diff --git a/frontend-challenge/CourtDetailScreen.js b/frontend-challenge/CourtDetailScreen.js
new file mode 100644
index 000000000..a57d79d93
--- /dev/null
+++ b/frontend-challenge/CourtDetailScreen.js
@@ -0,0 +1,43 @@
+import React, { useState } from 'react';
+import { View, Text, TextInput, Button, FlatList } from 'react-native';
+
+export default function CourtDetailScreen({ route, reviewsByCourt, setReviewsByCourt }) {
+ const { court } = route.params;
+ const [text, setText] = useState('');
+
+ const reviews = reviewsByCourt[court.id] || [];
+
+ const addReview = () => {
+ if (!text) return;
+
+ setReviewsByCourt(prev => ({
+ ...prev,
+ [court.id]: [...(prev[court.id] || []), text]
+ }));
+
+ setText('');
+ };
+
+ return (
+
+ {court.name}
+
+
+
+
+
+ i.toString()}
+ renderItem={({ item }) => (
+ {item}
+ )}
+ />
+
+ );
+}
diff --git a/frontend-challenge/CourtListScreen.js b/frontend-challenge/CourtListScreen.js
new file mode 100644
index 000000000..96eec5a07
--- /dev/null
+++ b/frontend-challenge/CourtListScreen.js
@@ -0,0 +1,40 @@
+import React, { useState } from 'react';
+import { View, Text, FlatList, TextInput, TouchableOpacity } from 'react-native';
+
+const COURTS = [
+ { id: '1', name: 'Court A' },
+ { id: '2', name: 'Court B' },
+ { id: '3', name: 'Court C' },
+];
+
+export default function CourtListScreen({ navigation }) {
+ const [search, setSearch] = useState('');
+
+ const filtered = COURTS.filter(c =>
+ c.name.toLowerCase().includes(search.toLowerCase())
+ );
+
+ return (
+
+
+
+ item.id}
+ renderItem={({ item }) => (
+ navigation.navigate('CourtDetail', { court: item })}
+ style={{ padding: 12, borderBottomWidth: 1 }}
+ >
+ {item.name}
+
+ )}
+ />
+
+ );
+}
diff --git a/frontend-challenge/README.md b/frontend-challenge/README.md
index 266b1d439..50f1fbecb 100644
--- a/frontend-challenge/README.md
+++ b/frontend-challenge/README.md
@@ -1,26 +1,6 @@
-# UI Code Challenge!
+```
+npm install
+expo install react-native-web
+```
-This small assignment will help evaluate your front end development capabilities. You will be evaluated on design choices (friction, scalability, etc), efficient and effective coding, and style.
-
-## Challenge
-
-Create a mobile first, two page app for reviewing tennis courts. A user should be able to see a display of courts, search for a specific court, select a court detail view, and leave a review.
-
-## Rules
-
-1. Pull this repo locally and work on your own branch
-2. Maximum time is 4 hours
-3. You will only be evaluated on how it looks on mobile device sizes
-4. No backend, all data will be mocked
-5. You do not need to write tests for this exercise given the time limit
-6. When you are done, submit a PR to this repo.
-
-## Hints
-
-- Do not use frameworks outside of the JavaScript/Typescript ecosystem
-- Submissions using React Native are preferred but React, Next, or pure JavaScript are acceptable
-- Bonus points if you mock > 50 courts as this will let you show off your scalable design skills
-- You can use coding assistants, but include every prompt you used in your PR
-- Your job is to delight users
-
-Good luck!
+Press w to view in browser
diff --git a/frontend-challenge/package.json b/frontend-challenge/package.json
new file mode 100644
index 000000000..4d1b05ebd
--- /dev/null
+++ b/frontend-challenge/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "tennis-courts-app",
+ "version": "1.0.0",
+ "private": true,
+ "main": "node_modules/expo/AppEntry.js",
+ "scripts": {
+ "start": "expo start",
+ "android": "expo start --android",
+ "ios": "expo start --ios",
+ "web": "expo start --web"
+ },
+ "dependencies": {
+ "expo": "~48.0.18",
+ "react": "18.2.0",
+ "react-dom": "18.2.0",
+ "react-native": "0.71.8",
+ "@react-navigation/native": "^6.1.6",
+ "@react-navigation/native-stack": "^6.9.12",
+ "react-native-screens": "~3.20.0",
+ "@expo/webpack-config": "^18.0.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.20.0"
+ }
+}