diff --git a/.fvmrc b/.fvmrc
new file mode 100644
index 00000000..6108f14a
--- /dev/null
+++ b/.fvmrc
@@ -0,0 +1,4 @@
+{
+ "flutter": "3.13.9",
+ "flavors": {}
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 6c2ea7c9..296ed068 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,6 @@ If you're a VScode user link the new Flutter SDK path in your settings
}
```
-
@@ -65,9 +64,14 @@ Go to `Preferences > Languages & Frameworks > Flutter` and set the Flutter SDK p
-## Requirements
+## App Structure
+
+### Design
+
+The app is based on the following [Figma File](https://www.figma.com/file/KsEhQUp66m9yeVkvQ0hSZm/Flutter-Test?node-id=0%3A1). Improvements and new features are welcolme as long as they follow the same visual aspect of the initial design
-### App Structure
+![List View](screenshots/listview.png)
+![Detail View](screenshots/detailview.png)
#### Restaurant List Page
@@ -96,88 +100,65 @@ Go to `Preferences > Languages & Frameworks > Flutter` and set the Flutter SDK p
- User image
- Review Text (These are just snippets of the full review, usually like 3-4 lines long)
-#### Misc.
+### Architechture
-- Clear documentation on the structure and architecture of your application.
-- Clear and logical commit messages.
- - We suggest following [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
+The project follows a Domain based architecture, a less rigid form of Clean Architecture. On the domain, sets of features may share same widgets, repositories and logic to acomplish the desired tasks. So far, the only domain is the Restaurant itself since it's a small app, therefore dependencies are declared right on top of widget tree, the top of the domain, and injected when needed through the usage of RepositoryProvider and BlocProvider.
-## Test Coverage
+- Restaurant domain
+ - data
+ - Restaurant models
+ - Yelp Repository
+ - logic
+ - FavouriteRestaurantsBloc
+ - RestaurantReviewsCubit
+ - RestaurantsBloczz
+ - presentation
+ - All Restaurants
+ - Favourite Restaurants
+ - Restaurant details
-To demonstrate your experience writing different types of tests in Flutter please do the following:
+This organization also aims to protect core models from change and make the view dependent on models and logic in a way that make the view reflect the desired business rules of the project.
-- Choose ONE portion of your state management and write a unit test.
-- Choose ONE widget and write a widget test.
+### Presentation
-Feel free to add more tests as you see fit but the above is the minimum requirement.
+The presentation widgets are splited into two different folders
+- common, where widgets used across the Restaurants domain are stored
+- views, where widgets representing bigger/complete screen vies are stored
-## Design
+Common and View widgets both may have widget folders within, where minor widgets are stored to enhance code splitting. This helps improve maintainance, code readability and testing.
-- See this [Figma File](https://www.figma.com/file/KsEhQUp66m9yeVkvQ0hSZm/Flutter-Test?node-id=0%3A1) for design information related to the overall look and feel of the application. We do not expect pixel-perfection but would like the application to visually be close to what is specified in the Figma file.
+Whenever view or common widgets get bigger, consider spliting into smaller parts within widgets folder.
-![List View](screenshots/listview.png)
-![Detail View](screenshots/detailview.png)
+### Data
+
+Data folder contains models and repositories that will dictate the domain main data types and how the application interacts with the source of data.
-## API
+#### Yelp API
-The [Yelp GraphQL API](https://www.yelp.com/developers/graphql/guides/intro) is used as the API for this Application. We have provided the boilerplate of the API requests and backing data models to save you some time. To successfully make a request to the Yelp GraphQL API, please follow these steps:
+The [Yelp GraphQL API](https://www.yelp.com/developers/graphql/guides/intro) is used as the API for this Application. To successfully make a request to the Yelp GraphQL API, please follow these steps:
1. Please go to https://www.yelp.com/signup and sign up for a developer account.
1. Once signed up, navigate to https://www.yelp.com/developers/v3/manage_app.
1. Create a new app by filling out the required information.
1. Once your app is created, scroll down and join the `Developer Beta`. This allows you to use the GraphQL API.
-1. Copy your API Key from your app page and paste it on `line 5` [yelp_repository.dart](app/lib/yelp_repository.dart) replacing the `` with your key.
-1. Run the app and tap the `Fetch Restaurants` button. If you see a log like `Fetched x restaurants` you are all set!
-
-## Technical Requirements
-
-### State Management
-
-Please restrict your usage of state management or dependency injection to the following options:
-
-1. [provider](https://pub.dev/packages/provider)
-2. [Riverpod](https://pub.dev/packages/riverpod)
-3. [bloc](https://pub.dev/packages/bloc)
-4. [get_it](https://pub.dev/packages/get_it)/[get_it_mixins](https://pub.dev/packages/get_it_mixin)
-5. [Mobx](https://pub.dev/packages/mobx)
-
-We ask this because this challenge values consistency and efficiency over ingenuity. Using commonly used libraries ensures that we can review your code in a timely manner and allows us to provide better feedback.
-
-## Coding Values
-
-At **Superformula** we strive to build applications that have
-
-- Consistent architecture
-- Extensible, clean code
-- Solid testing
-- Good security & performance best practices
-
-### Clear, consistent architecture
-
-Approach your submission as if it were a real world app. This includes Use any libraries that you would normally choose.
-
-_Please note: we're interested in your code & the way you solve the problem, not how well you can use a particular library or feature._
-
-### Easy to understand
-
-Writing boring code that is easy to follow is essential at **Superformula**.
-
-We're interested in your method and how you approach the problem just as much as we're interested in the end result.
+1. Copy your API Key from your app page and paste it on `line 5` [yelp_repository.dart](./lib/data/repositories/yelp_repository.dart) replacing the `` with your key.
-### Solid testing approach
+#### Yelp Repository
-While the purpose of this challenge is not to gauge whether you can achieve 100% test coverage, we do seek to evaluate whether you know how & what to test.
+This repository uses Dio and GraphQl notation to fetch data from Yelp GraphQL API. Response models from models folder are used to handle response parsing.
-## Q&A
+#### Favourite Restaurants
-> Where should I send back the result when I'm done?
+Due to the simplicity of data, local storage of favourite restaurants is being handled under the hood by HydratedBloc. No repository is necessary to handle this source of data.
-Please fork this repo and then send us a pull request to our repo when you think you are done. There is no deadline for this task unless otherwise noted to you directly.
+### State management / Logic
-> What if I have a question?
+The logic folder contains the BLoC files to handle the logic and state of the application. BLoC was chosen to better define the desired states and the transition between them, and also HydratedBloc provided a built-in way to handle local storage of states. There are 3 BLoCs, all of them making use of Yelp Repository:
-Just create a new issue in this repo and we will respond and get back to you quickly.
+- FavouriteRestaurantsBloc
+- RestaurantReviewsCubit
+- RestaurantsBloc
-## Review
+## Misc.
-The coding challenge is a take-home test upon which we'll be conducting a thorough code review once complete. The review will consist of meeting some more of our mobile engineers and giving a review of the solution you have designed. Please be prepared to share your screen and run/demo the application to the group. During this process, the engineers will be asking questions.
+- This project follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) guidelines
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index 24047dce..6bfb6ff0 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.kotlin_version = '1.3.50'
+ ext.kotlin_version = '1.6.0'
repositories {
google()
mavenCentral()
@@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
-task clean(type: Delete) {
+tasks.register("clean", Delete) {
delete rootProject.buildDir
}
diff --git a/assets/yelp_rest_status_response.json b/assets/yelp_rest_status_response.json
new file mode 100644
index 00000000..a9407da6
--- /dev/null
+++ b/assets/yelp_rest_status_response.json
@@ -0,0 +1,12 @@
+{
+ "data": {
+ "business": {
+ "id": "syhA1ugJpyNLaB0MiP19VA",
+ "hours": [
+ {
+ "is_open_now": true
+ }
+ ]
+ }
+ }
+}
diff --git a/assets/yelp_restaurants_response.json b/assets/yelp_restaurants_response.json
new file mode 100644
index 00000000..36c13660
--- /dev/null
+++ b/assets/yelp_restaurants_response.json
@@ -0,0 +1,1185 @@
+{
+ "data": {
+ "search": {
+ "total": 6244,
+ "business": [
+ {
+ "id": "vHz2RLtfUMVRPFmd7VBEHA",
+ "name": "Gordon Ramsay Hell's Kitchen",
+ "price": "$$$",
+ "rating": 4.4,
+ "photos": [
+ "https://s3-media2.fl.yelpcdn.com/bphoto/q771KjLzI5y638leJsnJnQ/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "5dBlSgczLAtrmNiVo0EnCg",
+ "rating": 5,
+ "user": {
+ "id": "37h0s9CsU_wNQSYVDoOszQ",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/ki33wK6EbEk6t7e3CjLUwQ/o.jpg",
+ "name": "Gregory B."
+ }
+ },
+ {
+ "id": "VzJIMZRW-8lwoFJzk0jAXw",
+ "rating": 5,
+ "user": {
+ "id": "i2dS47auJ-9-OW4xZSPxAA",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/M2AsmeEgwVwpjyaE1lFtIA/o.jpg",
+ "name": "White R."
+ }
+ },
+ {
+ "id": "H85bnGMvTx0ACssHvyCyug",
+ "rating": 5,
+ "user": {
+ "id": "3xfzp3cOhKICnLn0D9ZheA",
+ "image_url": null,
+ "name": "Molly S."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "New American",
+ "alias": "newamerican"
+ },
+ {
+ "title": "Seafood",
+ "alias": "seafood"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3570 Las Vegas Blvd S\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "faPVqws-x-5k2CQKDNtHxw",
+ "name": "Yardbird",
+ "price": "$$",
+ "rating": 4.5,
+ "photos": [
+ "https://s3-media1.fl.yelpcdn.com/bphoto/xYJaanpF3Dl1OovhmpqAYw/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "uIeZrx9X1W0XPKqDicXZew",
+ "rating": 5,
+ "user": {
+ "id": "nvcvPpKYpq-nT7wwAexGYw",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/2_pHFKGZ3-SlBq_HTXp8wg/o.jpg",
+ "name": "Tanner D."
+ }
+ },
+ {
+ "id": "V8KFADRFJnsGUvQ3iRtnig",
+ "rating": 5,
+ "user": {
+ "id": "R_PPnsl0gsIvzhq9JHRCXQ",
+ "image_url": null,
+ "name": "Misha Z."
+ }
+ },
+ {
+ "id": "ZJH4k4Z5eKIZED24mwMNbw",
+ "rating": 5,
+ "user": {
+ "id": "kEjqfvnMVol-m0l-7BCuiA",
+ "image_url": "https://s3-media3.fl.yelpcdn.com/photo/HR7uSBjp0wVFqCLzpcnzPQ/o.jpg",
+ "name": "Andy C."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Southern",
+ "alias": "southern"
+ },
+ {
+ "title": "New American",
+ "alias": "newamerican"
+ },
+ {
+ "title": "Cocktail Bars",
+ "alias": "cocktailbars"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3355 Las Vegas Blvd S\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "syhA1ugJpyNLaB0MiP19VA",
+ "name": "888 Japanese BBQ",
+ "price": "$$$",
+ "rating": 4.8,
+ "photos": [
+ "https://s3-media1.fl.yelpcdn.com/bphoto/V_zmwCUG1o_vR29xfkb-ng/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "CfkhNXxjrmAG3Rqth2S8PA",
+ "rating": 5,
+ "user": {
+ "id": "Lh3eh4seBFvfTgybYXL1uw",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/oztzeYdcy2lE6edfoXhapQ/o.jpg",
+ "name": "Christine X."
+ }
+ },
+ {
+ "id": "BVXWtpN-Xn4eIjMe2eceQg",
+ "rating": 5,
+ "user": {
+ "id": "azjuxjks4tfg_HCt1D5zqQ",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/dD5Mtong507Zkt91BLKLNQ/o.jpg",
+ "name": "Lexie P."
+ }
+ },
+ {
+ "id": "OqxFOKP3qvm3jnnZJaxOUw",
+ "rating": 5,
+ "user": {
+ "id": "-DG-God4RyXPOsaGmPNDcg",
+ "image_url": null,
+ "name": "Leilani S."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Barbeque",
+ "alias": "bbq"
+ },
+ {
+ "title": "Japanese",
+ "alias": "japanese"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3550 S Decatur Blvd\nLas Vegas, NV 89103"
+ }
+ },
+ {
+ "id": "QXV3L_QFGj8r6nWX2kS2hA",
+ "name": "Nacho Daddy",
+ "price": "$$",
+ "rating": 4.4,
+ "photos": [
+ "https://s3-media4.fl.yelpcdn.com/bphoto/pu9doqMplB5x5SEs8ikW6w/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "IdfbvfvfdqIIvOe6knwz-g",
+ "rating": 5,
+ "user": {
+ "id": "GjP-6ynX_-7Xz5CT_TEeIg",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/sPaIWyv52m1rJ47H7npE3Q/o.jpg",
+ "name": "Angel T."
+ }
+ },
+ {
+ "id": "ZRJNeoKFkVnjWFv7uiUBSg",
+ "rating": 5,
+ "user": {
+ "id": "VtXtUlnnTX78cMQrQJYfJQ",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/gpd9sy4O0ng7HOvfsyn5tA/o.jpg",
+ "name": "Montse C."
+ }
+ },
+ {
+ "id": "31ss_mS7gZ-n87m9WtiO4Q",
+ "rating": 5,
+ "user": {
+ "id": "moPMSTcAmuXV1gGOmrSxCA",
+ "image_url": null,
+ "name": "Samuel B."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "New American",
+ "alias": "newamerican"
+ },
+ {
+ "title": "Mexican",
+ "alias": "mexican"
+ },
+ {
+ "title": "Breakfast & Brunch",
+ "alias": "breakfast_brunch"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3663 Las Vegas Blvd\nSte 595\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "JPfi__QJAaRzmfh5aOyFEw",
+ "name": "Shang Artisan Noodle",
+ "price": "$$",
+ "rating": 4.6,
+ "photos": [
+ "https://s3-media3.fl.yelpcdn.com/bphoto/TqV2TDWH-7Wje5B9Oh1EZw/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "MlbzJT2UhcebcoXtq0kczA",
+ "rating": 5,
+ "user": {
+ "id": "HVwq3FtsOuxQV9DvoPa4RA",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/qptBQ1iGo9kY9wDGF8bFHA/o.jpg",
+ "name": "Jasmine B."
+ }
+ },
+ {
+ "id": "0AG_FlfYBfxlEIQKepSktw",
+ "rating": 5,
+ "user": {
+ "id": "Cco2owhvdzfZ-UAS4tPwKw",
+ "image_url": null,
+ "name": "Audrey D."
+ }
+ },
+ {
+ "id": "RqBtpBhgvoDmnmRGPPn0Tg",
+ "rating": 5,
+ "user": {
+ "id": "VPYPKuOJ3Q0VVik7w4ee-w",
+ "image_url": null,
+ "name": "Jason B."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Noodles",
+ "alias": "noodles"
+ },
+ {
+ "title": "Chinese",
+ "alias": "chinese"
+ },
+ {
+ "title": "Soup",
+ "alias": "soup"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "4983 W Flamingo Rd\nSte B\nLas Vegas, NV 89103"
+ }
+ },
+ {
+ "id": "3kdSl5mo9dWC4clrQjEDGg",
+ "name": "Egg & I",
+ "price": "$$",
+ "rating": 4.5,
+ "photos": [
+ "https://s3-media1.fl.yelpcdn.com/bphoto/z4rdxoc6xaM4dmdPovPBDg/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "I85RxcLOx2GZnPPhpRAq_g",
+ "rating": 5,
+ "user": {
+ "id": "NaYTgedWshzhFpbIcUbbQA",
+ "image_url": null,
+ "name": "Dolly C."
+ }
+ },
+ {
+ "id": "swI8g0sD0RdG__4-81_58w",
+ "rating": 5,
+ "user": {
+ "id": "rgGshDHeoe88kaLVeNFYRA",
+ "image_url": null,
+ "name": "Nathaniel H."
+ }
+ },
+ {
+ "id": "kJWWyoCHIWIAv869vyu7WQ",
+ "rating": 5,
+ "user": {
+ "id": "rzSlggVUz7zsshFZrcqdwQ",
+ "image_url": "https://s3-media3.fl.yelpcdn.com/photo/la2EgCbJX4oNNe_qMMz3Dw/o.jpg",
+ "name": "Dana J."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Breakfast & Brunch",
+ "alias": "breakfast_brunch"
+ },
+ {
+ "title": "Burgers",
+ "alias": "burgers"
+ },
+ {
+ "title": "American",
+ "alias": "tradamerican"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "4533 W Sahara Ave\nSte 5\nLas Vegas, NV 89102"
+ }
+ },
+ {
+ "id": "4JNXUYY8wbaaDmk3BPzlWw",
+ "name": "Mon Ami Gabi",
+ "price": "$$$",
+ "rating": 4.2,
+ "photos": [
+ "https://s3-media2.fl.yelpcdn.com/bphoto/cZ75DtuiHsOU-4W3vLsFKA/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "rsFWnc3wXsDeFXa2ATFZiQ",
+ "rating": 5,
+ "user": {
+ "id": "L6TIKUDGuzGRkfvP56-tKA",
+ "image_url": null,
+ "name": "Deneen M."
+ }
+ },
+ {
+ "id": "cQXxvSa57Tj781NBinYeuQ",
+ "rating": 5,
+ "user": {
+ "id": "nLmugYJe1dSyGhpsKKWDlw",
+ "image_url": null,
+ "name": "Maryann H."
+ }
+ },
+ {
+ "id": "bPYqNEvJaQxkAeZDmXRCug",
+ "rating": 5,
+ "user": {
+ "id": "4G8bg7wdu_WHezo1c1EYgA",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/jzQtjP49LXCkTH9ANt04KQ/o.jpg",
+ "name": "Rabindra A."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "French",
+ "alias": "french"
+ },
+ {
+ "title": "Steakhouses",
+ "alias": "steak"
+ },
+ {
+ "title": "Breakfast & Brunch",
+ "alias": "breakfast_brunch"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3655 Las Vegas Blvd S\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "2iTsRqUsPGRH1li1WVRvKQ",
+ "name": "Carson Kitchen",
+ "price": "$$",
+ "rating": 4.5,
+ "photos": [
+ "https://s3-media2.fl.yelpcdn.com/bphoto/LhaPvLHIrsHu8ZMLgV04OQ/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "59ewmBp3j19Ud3T7Lz4-Ow",
+ "rating": 4,
+ "user": {
+ "id": "7DQSAc84ydnYEP2UMWG0oQ",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/xV_gdMBDART7WwHp8KPlkA/o.jpg",
+ "name": "Shannon P."
+ }
+ },
+ {
+ "id": "SLncTZbrWzvn4QMiOb1brA",
+ "rating": 5,
+ "user": {
+ "id": "RB_lfittmnIRVL-m-4Q5YQ",
+ "image_url": null,
+ "name": "Suanne K."
+ }
+ },
+ {
+ "id": "VgtVupmMq2SRy071gm1vRA",
+ "rating": 5,
+ "user": {
+ "id": "c-E9FzfTwAAZkGwyTD6_dw",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/Oifp2BV_QHNZtpGqR0Zg0Q/o.jpg",
+ "name": "Ruby Q."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "New American",
+ "alias": "newamerican"
+ },
+ {
+ "title": "Desserts",
+ "alias": "desserts"
+ },
+ {
+ "title": "Cocktail Bars",
+ "alias": "cocktailbars"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "124 S 6th St\nSte 100\nLas Vegas, NV 89101"
+ }
+ },
+ {
+ "id": "RESDUcs7fIiihp38-d6_6g",
+ "name": "Bacchanal Buffet",
+ "price": "$$$$",
+ "rating": 3.8,
+ "photos": [
+ "https://s3-media2.fl.yelpcdn.com/bphoto/oqUpQ_W-8ZrbZKpDh7lYEw/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "pWMF4T4ISMnLL2uavTcFsA",
+ "rating": 5,
+ "user": {
+ "id": "V3Qh4p-i0q6RyO77qS7llA",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/3vFUAEkl29V7GbcnqgvO9w/o.jpg",
+ "name": "Livnat A."
+ }
+ },
+ {
+ "id": "0zzdPNrVUDImxCKvlP7kHQ",
+ "rating": 5,
+ "user": {
+ "id": "X55cCZntLJ93t5AqLV8Vmg",
+ "image_url": null,
+ "name": "Phuc N."
+ }
+ },
+ {
+ "id": "SFp74_nmffcW3zIvQpDw4w",
+ "rating": 5,
+ "user": {
+ "id": "QwaMGDUcwaIoWOE6QGriHw",
+ "image_url": "https://s3-media3.fl.yelpcdn.com/photo/6n6DIYSQ9KI-aXe9CBmheg/o.jpg",
+ "name": "Gilbert M."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Buffets",
+ "alias": "buffets"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3570 Las Vegas Blvd S\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "-1m9o3vGRA8IBPNvNqKLmA",
+ "name": "Bavette's Steakhouse & Bar",
+ "price": "$$$$",
+ "rating": 4.5,
+ "photos": [
+ "https://s3-media2.fl.yelpcdn.com/bphoto/pgcnYRHtbw_x_-OG8K4xVg/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "F8tEzjNcVF778CANn9tkLA",
+ "rating": 5,
+ "user": {
+ "id": "zK4R5IFl5aBqePPEd0fvxw",
+ "image_url": "https://s3-media3.fl.yelpcdn.com/photo/rBt0S0z6NESBswiuaELa8w/o.jpg",
+ "name": "McKenzie S."
+ }
+ },
+ {
+ "id": "I7Ip9foJiDllocxBRGeiSQ",
+ "rating": 5,
+ "user": {
+ "id": "YoaQY0EZmhYCgTLtz5sd2w",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/jgHQJrMrP7kzfbK26guJmg/o.jpg",
+ "name": "Kim l."
+ }
+ },
+ {
+ "id": "np5mM9znAoxH7kad8OzG2w",
+ "rating": 1,
+ "user": {
+ "id": "dK15g-WQtEt_1tz2jIXs2g",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/JXfhN9yAGAb03WYWg4v4OQ/o.jpg",
+ "name": "Terry G."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Steakhouses",
+ "alias": "steak"
+ },
+ {
+ "title": "Bars",
+ "alias": "bars"
+ },
+ {
+ "title": "New American",
+ "alias": "newamerican"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3770 Las Vegas Blvd S\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "awI4hHMfa7H0Xf0-ChU5hg",
+ "name": "The Palace Station Oyster Bar",
+ "price": "$$",
+ "rating": 4.4,
+ "photos": [
+ "https://s3-media1.fl.yelpcdn.com/bphoto/7Rx_j6r85ufd8nOFc7u_fA/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "i6niYOziXhW2NJA1LroBmg",
+ "rating": 5,
+ "user": {
+ "id": "4hSqVWaqVoHSSemocLN8ig",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/YuGBE_q0VxMS1-omKLMYfA/o.jpg",
+ "name": "Stephanie R."
+ }
+ },
+ {
+ "id": "cff01cXyaIuBtTarRGO9Cw",
+ "rating": 4,
+ "user": {
+ "id": "D4cnxp6k4eemD98E-kphMw",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/oPVnYh0AYTTgU0yswQ3c-w/o.jpg",
+ "name": "San L."
+ }
+ },
+ {
+ "id": "HUgNoBa6JGcnrek39pc1SQ",
+ "rating": 4,
+ "user": {
+ "id": "BUQKlodE0a6H1SwH_-o2UA",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/Ae6xZxrB-ePk7CVlgX2Haw/o.jpg",
+ "name": "Soo L."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Seafood",
+ "alias": "seafood"
+ },
+ {
+ "title": "Bars",
+ "alias": "bars"
+ },
+ {
+ "title": "Cajun/Creole",
+ "alias": "cajun"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": true
+ }
+ ],
+ "location": {
+ "formatted_address": "2411 W Sahara Ave\nLas Vegas, NV 89102"
+ }
+ },
+ {
+ "id": "_Ad2ZKhUl-krJFpaZ1FI8g",
+ "name": "Nabe Hotpot",
+ "price": "$$",
+ "rating": 4.3,
+ "photos": [
+ "https://s3-media3.fl.yelpcdn.com/bphoto/tkRdqFIfLe1lTwa6XmUPTA/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "0wT3ZCZQ11bNQOV95RgVHQ",
+ "rating": 5,
+ "user": {
+ "id": "3D99jvQficOPttTsSJHe8g",
+ "image_url": null,
+ "name": "Karter T."
+ }
+ },
+ {
+ "id": "pq5ugK0sbm314QyzF_3E8g",
+ "rating": 5,
+ "user": {
+ "id": "zluLxvSPaZnAICWSWkodjg",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/I9yh419iP5joTyay8BzSQg/o.jpg",
+ "name": "Erian R."
+ }
+ },
+ {
+ "id": "cRENEOAoJ9ynXg3w78xAYw",
+ "rating": 4,
+ "user": {
+ "id": "T7ko9V7ceVMJlMFbsihpzw",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/HFGrRFsEVBdUbEAnhPLGXQ/o.jpg",
+ "name": "Susan H."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Hot Pot",
+ "alias": "hotpot"
+ },
+ {
+ "title": "Buffets",
+ "alias": "buffets"
+ },
+ {
+ "title": "Asian Fusion",
+ "alias": "asianfusion"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "4545 Spring Mountain Rd\nSte106\nLas Vegas, NV 89103"
+ }
+ },
+ {
+ "id": "rdE9gg0WB7Z8kRytIMSapg",
+ "name": "Lazy Dog Restaurant & Bar",
+ "price": "$$",
+ "rating": 4.5,
+ "photos": [
+ "https://s3-media2.fl.yelpcdn.com/bphoto/_Wz-fNXawmbBinSf9Ev15g/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "nSRTIxL_xl5m8gykOEq-WQ",
+ "rating": 5,
+ "user": {
+ "id": "zaERxTbPn4TW6f6jynAb_A",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/A7Cov8r811C0tZiVArEn3A/o.jpg",
+ "name": "Kayleene M."
+ }
+ },
+ {
+ "id": "IUYj8Lox9pD1pda-a2rF1w",
+ "rating": 5,
+ "user": {
+ "id": "8ExBbLTrT8Gc1R9r4KhBCg",
+ "image_url": null,
+ "name": "Angelica M."
+ }
+ },
+ {
+ "id": "2rcy8s1va17xnmQut-qkOw",
+ "rating": 5,
+ "user": {
+ "id": "8h9-semB4gW931Q5B1LJ4w",
+ "image_url": null,
+ "name": "mike m."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "New American",
+ "alias": "newamerican"
+ },
+ {
+ "title": "Comfort Food",
+ "alias": "comfortfood"
+ },
+ {
+ "title": "Burgers",
+ "alias": "burgers"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "6509 S Las Vegas Blvd\nLas Vegas, NV 89119"
+ }
+ },
+ {
+ "id": "UidEFF1WpnU4duev4fjPlQ",
+ "name": "Therapy ",
+ "price": "$$",
+ "rating": 4.3,
+ "photos": [
+ "https://s3-media3.fl.yelpcdn.com/bphoto/otaMuPtauoEb6qZzmHlAlQ/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "rFkhUcAd_toiQF5etzOUFw",
+ "rating": 5,
+ "user": {
+ "id": "TgVjm7u8yWeP7E8E8HLi9w",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/mpciVuTs9rLYXIS2T9Jszg/o.jpg",
+ "name": "Jose P."
+ }
+ },
+ {
+ "id": "1l7Amo9ZDgqOrnR_u59XYg",
+ "rating": 5,
+ "user": {
+ "id": "4UMYSQLSd3_rQe8bhqWreg",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/m9tI9Pw5P7u5S4urIZanDg/o.jpg",
+ "name": "Kien H."
+ }
+ },
+ {
+ "id": "pHPIgHpj7DX6s3XrUNvzkA",
+ "rating": 2,
+ "user": {
+ "id": "zwKLl0R9twRbZyU-i52Wbg",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/u00XjQgIK8xu30gJS_ORzw/o.jpg",
+ "name": "Ashleigh A."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Bars",
+ "alias": "bars"
+ },
+ {
+ "title": "New American",
+ "alias": "newamerican"
+ },
+ {
+ "title": "Dance Clubs",
+ "alias": "danceclubs"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "518 Fremont St\nLas Vegas, NV 89101"
+ }
+ },
+ {
+ "id": "gOOfBSBZlffCkQ7dr7cpdw",
+ "name": "CHICA",
+ "price": "$$",
+ "rating": 4.3,
+ "photos": [
+ "https://s3-media2.fl.yelpcdn.com/bphoto/FxmtjuzPDiL7vx5KyceWuQ/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "KpmUpAaEq--1tyGVIOxSwA",
+ "rating": 5,
+ "user": {
+ "id": "a2pHeokH8l7r3T8nXach0A",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/2LLnjIvr0y9yMen135cJKQ/o.jpg",
+ "name": "Kam M."
+ }
+ },
+ {
+ "id": "f0pNMzyz5SE74XSbYMtvkA",
+ "rating": 5,
+ "user": {
+ "id": "8-6HIm7V3MtKjO1VDNeRAw",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/JMuteh6KHCxq8HLrqtG64w/o.jpg",
+ "name": "Stella L."
+ }
+ },
+ {
+ "id": "tNBknDPqGcdl5v_K4ok7Aw",
+ "rating": 4,
+ "user": {
+ "id": "VThvNKX4R6JTn4T4WFroOw",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/0SOLbfun7i8knyGxnoVObQ/o.jpg",
+ "name": "Rayshelys B."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Latin American",
+ "alias": "latin"
+ },
+ {
+ "title": "Breakfast & Brunch",
+ "alias": "breakfast_brunch"
+ },
+ {
+ "title": "Cocktail Bars",
+ "alias": "cocktailbars"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3355 South Las Vegas Blvd\nSte 106\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "XnJeadLrlj9AZB8qSdIR2Q",
+ "name": "Joel Robuchon",
+ "price": "$$$$",
+ "rating": 4.5,
+ "photos": [
+ "https://s3-media4.fl.yelpcdn.com/bphoto/8282ZD9hrsGH9a-kejFzxw/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "8vQVgCgiKQ0HjAG_kXeetA",
+ "rating": 5,
+ "user": {
+ "id": "OIa6ptM1qUts5arovQUAFQ",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/cCb8-5fnQAznL-wz8Cwlew/o.jpg",
+ "name": "Eric B."
+ }
+ },
+ {
+ "id": "EVewlHXfiDa6EW4xf44jog",
+ "rating": 4,
+ "user": {
+ "id": "oEqB6qGiV2K3q8g2A8rfYA",
+ "image_url": "https://s3-media3.fl.yelpcdn.com/photo/50wbYURpTknygA41Gm7bJA/o.jpg",
+ "name": "Gracie J."
+ }
+ },
+ {
+ "id": "GcEYfDEw6KI7Yx6UR8rdMA",
+ "rating": 5,
+ "user": {
+ "id": "Y4iXISephx40OlZGaRjxUw",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/tMExN7NAouyc9NgujptfqQ/o.jpg",
+ "name": "Tom B."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "French",
+ "alias": "french"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3799 Las Vegas Blvd S\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "nUpz0YiBsOK7ff9k3vUJ3A",
+ "name": "Buddy V's Ristorante",
+ "price": "$$",
+ "rating": 4.2,
+ "photos": [
+ "https://s3-media1.fl.yelpcdn.com/bphoto/gLHjQg0bjGjr_Jus-BXqDA/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "XvYKeYfYU2mDODBphOlYXA",
+ "rating": 4,
+ "user": {
+ "id": "Vz5KVB8oq1Yd-yBjjUzq7w",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/H-8KWUKW8ujADR3a-LW3wA/o.jpg",
+ "name": "Teresa L."
+ }
+ },
+ {
+ "id": "aigNWful677P85ArYZRkqw",
+ "rating": 5,
+ "user": {
+ "id": "yhZ-fJdtaImuUL-lW6e9-g",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/1sU9tinpG1SuG4e5h9EE3g/o.jpg",
+ "name": "Nicole T."
+ }
+ },
+ {
+ "id": "4tftZUGS6wSsdLmD8oGIDg",
+ "rating": 4,
+ "user": {
+ "id": "oxQsPh1Glu1wUHBTR4Nhug",
+ "image_url": "https://s3-media3.fl.yelpcdn.com/photo/h46Il-KuGYZXhW3agUW5Zw/o.jpg",
+ "name": "Saturnino C."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Italian",
+ "alias": "italian"
+ },
+ {
+ "title": "American",
+ "alias": "tradamerican"
+ },
+ {
+ "title": "Wine Bars",
+ "alias": "wine_bars"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3327 S Las Vegas Blvd\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "I6EDDi4-Eq_XlFghcDCUhw",
+ "name": "Joe's Seafood Prime Steak & Stone Crab",
+ "price": "$$$",
+ "rating": 4.4,
+ "photos": [
+ "https://s3-media1.fl.yelpcdn.com/bphoto/I1GDdV1mWUJM5HTP1PIX6A/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "6imdz-hd8Mdy6CCHoZ_tww",
+ "rating": 5,
+ "user": {
+ "id": "ZnyskHaWQpv6VyMGdb2xJQ",
+ "image_url": null,
+ "name": "Rob M."
+ }
+ },
+ {
+ "id": "cRJlV2axHBcfcRK-xUrsHg",
+ "rating": 5,
+ "user": {
+ "id": "NOi1ji1AKPhiE1-R9k3LoA",
+ "image_url": null,
+ "name": "Allie M."
+ }
+ },
+ {
+ "id": "UspFMU3KmguqGMihIkH5jA",
+ "rating": 5,
+ "user": {
+ "id": "gYgFW1ZF603FuEbqgUEvzw",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/CxRlXjvcv7Icovk1QIFSiQ/o.jpg",
+ "name": "Elaine L."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Seafood",
+ "alias": "seafood"
+ },
+ {
+ "title": "Steakhouses",
+ "alias": "steak"
+ },
+ {
+ "title": "Wine Bars",
+ "alias": "wine_bars"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "3500 Las Vegas Blvd S\nLas Vegas, NV 89109"
+ }
+ },
+ {
+ "id": "igHYkXZMLAc9UdV5VnR_AA",
+ "name": "Echo & Rig",
+ "price": "$$$",
+ "rating": 4.4,
+ "photos": [
+ "https://s3-media1.fl.yelpcdn.com/bphoto/Q9swks1BO-w-hVskIHrCVg/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "KxB6EqbsUAYcXCbogF0j9A",
+ "rating": 5,
+ "user": {
+ "id": "W3opz1HpIXl2krFLJ53lqg",
+ "image_url": null,
+ "name": "Ming Z."
+ }
+ },
+ {
+ "id": "to14TViy1ksheDKAfHkQ1Q",
+ "rating": 5,
+ "user": {
+ "id": "fe4LgCw7X9TZCocwvr-LTQ",
+ "image_url": "https://s3-media3.fl.yelpcdn.com/photo/JN2tU8aDVk68I3ywHepdkg/o.jpg",
+ "name": "Shane B."
+ }
+ },
+ {
+ "id": "N4t02F-XrnuY_Zf2-tQk1Q",
+ "rating": 4,
+ "user": {
+ "id": "xz81pPXEuon4-7yRg2ptDQ",
+ "image_url": "https://s3-media3.fl.yelpcdn.com/photo/HWfZOqm3rqN8r0QY-4ORzQ/o.jpg",
+ "name": "Grace C."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "Steakhouses",
+ "alias": "steak"
+ },
+ {
+ "title": "Butcher",
+ "alias": "butcher"
+ },
+ {
+ "title": "Tapas/Small Plates",
+ "alias": "tapasmallplates"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "440 S Rampart Blvd\nLas Vegas, NV 89145"
+ }
+ },
+ {
+ "id": "eJKnymd0BywNPrJw1IuXVw",
+ "name": "Nacho Daddy Downtown",
+ "price": "$$",
+ "rating": 4.2,
+ "photos": [
+ "https://s3-media1.fl.yelpcdn.com/bphoto/wceTIo3pRr_-xUTtIJBVdg/o.jpg"
+ ],
+ "reviews": [
+ {
+ "id": "tjpHz85V1TnDzgntWvXOeg",
+ "rating": 5,
+ "user": {
+ "id": "9Qjwa91-0hOtkputU279ig",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/C4lrz8fNoTE8qornQQX_jA/o.jpg",
+ "name": "Richard W."
+ }
+ },
+ {
+ "id": "kaV7U85JFL2vHKMoJjNyAg",
+ "rating": 5,
+ "user": {
+ "id": "aDMLmc5ttBPRZmmO-qI9kQ",
+ "image_url": null,
+ "name": "Ian J."
+ }
+ },
+ {
+ "id": "87iSEJCmfBm8GWIxPW5J8g",
+ "rating": 5,
+ "user": {
+ "id": "MzSbrpAd59sGy6l8FG3JQg",
+ "image_url": "https://s3-media2.fl.yelpcdn.com/photo/jlZR8HYRoyhjbp7gE2Ybmg/o.jpg",
+ "name": "Domonique S."
+ }
+ }
+ ],
+ "categories": [
+ {
+ "title": "New American",
+ "alias": "newamerican"
+ },
+ {
+ "title": "Mexican",
+ "alias": "mexican"
+ },
+ {
+ "title": "Breakfast & Brunch",
+ "alias": "breakfast_brunch"
+ }
+ ],
+ "hours": [
+ {
+ "is_open_now": false
+ }
+ ],
+ "location": {
+ "formatted_address": "121 N 4th St\nLas Vegas, NV 89101"
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/assets/yelp_reviews_response.json b/assets/yelp_reviews_response.json
new file mode 100644
index 00000000..aa3b7907
--- /dev/null
+++ b/assets/yelp_reviews_response.json
@@ -0,0 +1,71 @@
+{
+ "data": {
+ "business": {
+ "review_count": 11265,
+ "reviews": [
+ {
+ "id": "5dBlSgczLAtrmNiVo0EnCg",
+ "rating": 5,
+ "user": {
+ "id": "37h0s9CsU_wNQSYVDoOszQ",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/ki33wK6EbEk6t7e3CjLUwQ/o.jpg",
+ "name": "Gregory B."
+ },
+ "text": "Save the Bees Please ssssssssssss ssssssssss \nOur Food Supply Chain Definitely is in danger"
+ },
+ {
+ "id": "VzJIMZRW-8lwoFJzk0jAXw",
+ "rating": 5,
+ "user": {
+ "id": "i2dS47auJ-9-OW4xZSPxAA",
+ "image_url": "https://s3-media1.fl.yelpcdn.com/photo/M2AsmeEgwVwpjyaE1lFtIA/o.jpg",
+ "name": "White R."
+ },
+ "text": "Amazing!!!! \n\n7 out of 7 !!! I highly recommend.\n\n\n\n\nEvery rabbit stumbles upon a rabbit hole. There are layers to this game. Like dAnte himself said ......."
+ },
+ {
+ "id": "H85bnGMvTx0ACssHvyCyug",
+ "rating": 5,
+ "user": {
+ "id": "3xfzp3cOhKICnLn0D9ZheA",
+ "image_url": null,
+ "name": "Molly S."
+ },
+ "text": "This was the best dining experience I have ever had. I am a professional pastry chef and HUGE Gordon Ramsay fan so Hell's Kitchen was a \"must stop\" and the..."
+ },
+ {
+ "id": "CfkhNXxjrmAG3Rqth2S8PA",
+ "rating": 5,
+ "user": {
+ "id": "Lh3eh4seBFvfTgybYXL1uw",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/oztzeYdcy2lE6edfoXhapQ/o.jpg",
+ "name": "Christine X."
+ },
+ "text": "It's very delicious and tender beef . Salmon sushi also really good , yummy yummy yummy ,\nI will recommend my friend to come , love it ."
+ },
+ {
+ "id": "BVXWtpN-Xn4eIjMe2eceQg",
+ "rating": 5,
+ "user": {
+ "id": "azjuxjks4tfg_HCt1D5zqQ",
+ "image_url": "https://s3-media4.fl.yelpcdn.com/photo/dD5Mtong507Zkt91BLKLNQ/o.jpg",
+ "name": "Lexie P."
+ },
+ "text": "I come here a lot of times, they still maintain their quality of food and service. Highly recommend."
+ },
+ {
+ "id": "OqxFOKP3qvm3jnnZJaxOUw",
+ "rating": 5,
+ "user": {
+ "id": "-DG-God4RyXPOsaGmPNDcg",
+ "image_url": null,
+ "name": "Leilani S."
+ },
+ "text": "1st time here and everything was amazing 10/10\n\nTeyah our server was so sweet and had so many recommendations for us to try (great job management for this..."
+ }
+ ],
+ "id": "vHz2RLtfUMVRPFmd7VBEHA",
+ "name": "Gordon Ramsay Hell's Kitchen"
+ }
+ }
+ }
\ No newline at end of file
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
index 592ceee8..ec97fc6f 100644
--- a/ios/Flutter/Debug.xcconfig
+++ b/ios/Flutter/Debug.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
index 592ceee8..c4855bfe 100644
--- a/ios/Flutter/Release.xcconfig
+++ b/ios/Flutter/Release.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
diff --git a/ios/Podfile b/ios/Podfile
new file mode 100644
index 00000000..fdcc671e
--- /dev/null
+++ b/ios/Podfile
@@ -0,0 +1,44 @@
+# Uncomment this line to define a global platform for your project
+# platform :ios, '11.0'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+ use_modular_headers!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+ target 'RunnerTests' do
+ inherit! :search_paths
+ end
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ end
+end
diff --git a/lib/models/restaurant.dart b/lib/data/models/restaurant.dart
similarity index 70%
rename from lib/models/restaurant.dart
rename to lib/data/models/restaurant.dart
index 87c7aab5..c333ff1f 100644
--- a/lib/models/restaurant.dart
+++ b/lib/data/models/restaurant.dart
@@ -55,11 +55,13 @@ class Review {
final String? id;
final int? rating;
final User? user;
+ final String? text;
const Review({
this.id,
this.rating,
this.user,
+ this.text,
});
factory Review.fromJson(Map json) => _$ReviewFromJson(json);
@@ -135,6 +137,30 @@ class Restaurant {
}
return false;
}
+
+ Restaurant copyWith({
+ String? id,
+ String? name,
+ String? price,
+ double? rating,
+ List? photos,
+ List? categories,
+ List? hours,
+ List? reviews,
+ Location? location,
+ }) {
+ return Restaurant(
+ id: id ?? this.id,
+ name: name ?? this.name,
+ price: price ?? this.price,
+ rating: rating ?? this.rating,
+ photos: photos ?? this.photos,
+ categories: categories ?? this.categories,
+ hours: hours ?? this.hours,
+ reviews: reviews ?? this.reviews,
+ location: location ?? this.location,
+ );
+ }
}
@JsonSerializable()
@@ -153,3 +179,37 @@ class RestaurantQueryResult {
Map toJson() => _$RestaurantQueryResultToJson(this);
}
+
+@JsonSerializable()
+class ReviewQueryResult {
+ @JsonKey(name: 'review_count')
+ final int? total;
+ @JsonKey(name: 'reviews')
+ final List? reviewsList;
+
+ const ReviewQueryResult({
+ this.total,
+ this.reviewsList,
+ });
+
+ factory ReviewQueryResult.fromJson(Map json) =>
+ _$ReviewQueryResultFromJson(json);
+
+ Map toJson() => _$ReviewQueryResultToJson(this);
+}
+
+@JsonSerializable()
+class StatusQueryResult {
+ final String? id;
+ final List? hours;
+
+ const StatusQueryResult({
+ this.id,
+ this.hours,
+ });
+
+ factory StatusQueryResult.fromJson(Map json) =>
+ _$StatusQueryResultFromJson(json);
+
+ Map toJson() => _$StatusQueryResultToJson(this);
+}
diff --git a/lib/models/restaurant.g.dart b/lib/data/models/restaurant.g.dart
similarity index 78%
rename from lib/models/restaurant.g.dart
rename to lib/data/models/restaurant.g.dart
index 3ed33f9a..4fa10886 100644
--- a/lib/models/restaurant.g.dart
+++ b/lib/data/models/restaurant.g.dart
@@ -42,12 +42,14 @@ Review _$ReviewFromJson(Map json) => Review(
user: json['user'] == null
? null
: User.fromJson(json['user'] as Map),
+ text: json['text'] as String?,
);
Map _$ReviewToJson(Review instance) => {
'id': instance.id,
'rating': instance.rating,
'user': instance.user,
+ 'text': instance.text,
};
Location _$LocationFromJson(Map json) => Location(
@@ -107,3 +109,31 @@ Map _$RestaurantQueryResultToJson(
'total': instance.total,
'business': instance.restaurants,
};
+
+ReviewQueryResult _$ReviewQueryResultFromJson(Map json) =>
+ ReviewQueryResult(
+ total: json['review_count'] as int?,
+ reviewsList: (json['reviews'] as List?)
+ ?.map((e) => Review.fromJson(e as Map))
+ .toList(),
+ );
+
+Map _$ReviewQueryResultToJson(ReviewQueryResult instance) =>
+ {
+ 'review_count': instance.total,
+ 'reviews': instance.reviewsList,
+ };
+
+StatusQueryResult _$StatusQueryResultFromJson(Map json) =>
+ StatusQueryResult(
+ id: json['id'] as String?,
+ hours: (json['hours'] as List?)
+ ?.map((e) => Hours.fromJson(e as Map))
+ .toList(),
+ );
+
+Map _$StatusQueryResultToJson(StatusQueryResult instance) =>
+ {
+ 'id': instance.id,
+ 'hours': instance.hours,
+ };
diff --git a/lib/data/repositories/yelp_repository.dart b/lib/data/repositories/yelp_repository.dart
new file mode 100644
index 00000000..4c8ead59
--- /dev/null
+++ b/lib/data/repositories/yelp_repository.dart
@@ -0,0 +1,188 @@
+import 'dart:convert';
+
+import 'package:dio/dio.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/services.dart';
+import 'package:restaurantour/data/models/restaurant.dart';
+
+const _apiKey = '';
+
+class MockResponse {
+ final Map data;
+ MockResponse(this.data);
+}
+
+class YelpRepository {
+ late Dio dio;
+
+ YelpRepository({
+ @visibleForTesting Dio? dio,
+ }) : dio = dio ??
+ Dio(
+ BaseOptions(
+ baseUrl: 'https://api.yelp.com',
+ headers: {
+ 'Authorization': 'Bearer $_apiKey',
+ 'Content-Type': 'application/graphql',
+ },
+ ),
+ );
+
+ Future getRestaurants({int offset = 0}) async {
+ try {
+ final response;
+
+ if (kReleaseMode) {
+ response = await dio.post