Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flutter Challenge - Camilo Rodriguez #19

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f2a1294
feat(app): initialize flutter project - env variable
kmil0 Sep 14, 2024
6155a12
chore(app): configure folder structure for clean architecture
kmil0 Sep 14, 2024
05a309a
feat(app): add models, usecases, domain and infrastructure layer
kmil0 Sep 14, 2024
dd3afb6
test(repository): add test for the gateway and domain layer
kmil0 Sep 15, 2024
f0f8277
feat(state): add provider package and create restaurant provider
kmil0 Sep 16, 2024
c4de698
feat(ui) add ui colors,sizes, typography and restructure folders
kmil0 Sep 16, 2024
8a0aece
feat(ui) add home page and homeappbar, update colors palette
kmil0 Sep 16, 2024
ca44256
feat(ui) add availability, image and rating widget
kmil0 Sep 16, 2024
30a0068
test(ui) add test to availability widget
kmil0 Sep 16, 2024
92d9c16
feat(ui) add restaurant list page
kmil0 Sep 16, 2024
6a0db6c
test(ui): add test to restaurant list widget
kmil0 Sep 16, 2024
57d46a6
feat(ui): restaurant detail page layout
kmil0 Sep 16, 2024
bf904e6
feat(ui): add review list widget and refactor restaurant detail page …
kmil0 Sep 16, 2024
0736d12
feat(favorites): add provider for storing favorite restaurants client…
kmil0 Sep 16, 2024
905f02e
test(providers): add tests for favorites and restaurant providers
kmil0 Sep 16, 2024
6594086
feat(ui): implement favorite restaurant provider
kmil0 Sep 16, 2024
bfd8e74
chore: add coverage ignore for constants and models
kmil0 Sep 16, 2024
b0ceaac
feat: add shared_preferences package for local storage
kmil0 Sep 16, 2024
a618559
test(golden): add golden test for UI home and restaurant pages
kmil0 Sep 16, 2024
1e7e543
test(integration): add integration test for navigating to RestaurantD…
kmil0 Sep 17, 2024
2f2ec57
Remove .env from Git tracking and add to .gitignore
kmil0 Sep 17, 2024
187c88f
add assets to readme
kmil0 Sep 17, 2024
baf0c11
refactor(provider): update FavoritesProvider to use LocalStorageGateway
kmil0 Sep 17, 2024
0b8a55c
Update README.md
kmil0 Sep 17, 2024
431a26a
refactor: add pagination to restaurant list
kmil0 Sep 17, 2024
d99cc28
add. env to gitignore
kmil0 Sep 17, 2024
2c0ae54
Merge branch 'feature/code_challenge' of github.com:kmil0/flutter_tes…
kmil0 Sep 17, 2024
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
Prev Previous commit
Next Next commit
feat(app): add models, usecases, domain and infrastructure layer
  • Loading branch information
kmil0 committed Sep 14, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 05a309ad6f4fa9bf6d93f28689295504c79a087c
11 changes: 11 additions & 0 deletions lib/domain/exception/app_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
enum FetchAppError { notFound, serverError, unknowError, networkError }

class AppException implements Exception {
final FetchAppError error;
final String message;

AppException(this.error, this.message);

@override
String toString() => 'AppException: $message';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:restaurant_tour/domain/models/restaurant/gateway/restaurant.dart';

abstract class LocalStorageGatewayInterface {
Future<List<Restaurant>?> getFavoriteRestaurants();
Future<void> addFavoriteRestaurant();
Future<void> deleteFavoriteRestaurant();
}
27 changes: 27 additions & 0 deletions lib/domain/models/restaurant/gateway/restaurant.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:restaurant_tour/infrastructure/helpers/mappers/restaurant.dart';

///Entity defining the data
class Restaurant {
final String? id;
final String? name;
final String? price;
final double? rating;
final List<String>? photos;
final List<Category>? categories;
final List<Hours>? hours;
final List<Review>? reviews;
final Location? location;
final bool? isFavorite;
Restaurant({
required this.id,
required this.name,
required this.price,
required this.rating,
required this.photos,
required this.categories,
required this.hours,
required this.reviews,
required this.location,
required this.isFavorite,
});
}
6 changes: 6 additions & 0 deletions lib/domain/models/restaurant/gateway/restaurant_gateway.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'package:restaurant_tour/infrastructure/helpers/mappers/restaurant.dart';

abstract class RestaurantGateway {
Future<List<Restaurant>?> getRestaurants({int offset = 0});
Future<Restaurant?> getRestaurant(String id);
}
20 changes: 20 additions & 0 deletions lib/domain/usecase/restaurant/local_storage_use_case.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:restaurant_tour/domain/models/restaurant/gateway/local_storage_gateway.dart';
import 'package:restaurant_tour/domain/models/restaurant/gateway/restaurant.dart';

class LocalStorageUseCase {
final LocalStorageGatewayInterface localStorageGatewayInterface;

LocalStorageUseCase({required this.localStorageGatewayInterface});

Future<List<Restaurant>?> getFavoriteRestaurants() {
return localStorageGatewayInterface.getFavoriteRestaurants();
}

Future<void> addFavoriteRestaurant() {
return localStorageGatewayInterface.addFavoriteRestaurant();
}

Future<void> deleteFavoriteRestaurant() {
return localStorageGatewayInterface.deleteFavoriteRestaurant();
}
}
16 changes: 16 additions & 0 deletions lib/domain/usecase/restaurant/restaurant_use_case.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:restaurant_tour/domain/models/restaurant/gateway/restaurant_gateway.dart';
import 'package:restaurant_tour/infrastructure/helpers/mappers/restaurant.dart';

class RestaurantUseCase {
final RestaurantGateway restaurantGateway;

RestaurantUseCase({required this.restaurantGateway});

Future<List<Restaurant>?> getRestaurants() {
return restaurantGateway.getRestaurants();
}

Future<Restaurant?> getRestaurant(String id) {
return restaurantGateway.getRestaurant(id);
}
}
44 changes: 44 additions & 0 deletions lib/infrastructure/driven_adapters/api/restaurant_api.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:restaurant_tour/domain/exception/app_exception.dart';
import 'package:restaurant_tour/domain/models/restaurant/gateway/restaurant_gateway.dart';
import 'package:restaurant_tour/infrastructure/helpers/mappers/restaurant.dart';
import 'package:restaurant_tour/infrastructure/helpers/mappers/restaurant_data_to_restaurants.dart';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:restaurant_tour/utils/restaurants_query.dart';

class RestaurantApi extends RestaurantGateway {
late Dio dio;
@override
Future<Restaurant> getRestaurant(String id) {
// TODO: implement getRestaurant

throw UnimplementedError();
}

@override
Future<List<Restaurant>?> getRestaurants({int offset = 0}) async {
try {
final response = await dio.post('/v3/graphql', data: restaurantsQuery(offset));
if (response.statusCode == 200) {
final restaurantsData = RestaurantQueryResult.fromJson(
jsonDecode(response.data!)['data']['search'],
);
return restaurantDataToRestaurants(restaurantsData)
.where((restaurant) => restaurant != null)
.cast<Restaurant>()
.toList();
} else {
switch (response.statusCode) {
case 404:
throw AppException(FetchAppError.notFound, 'Restaurants not found');
case 500:
throw AppException(FetchAppError.serverError, 'Server error');
default:
throw AppException(FetchAppError.unknowError, 'Unknown error occurred');
}
}
} catch (e) {
throw AppException(FetchAppError.networkError, 'Error fetching restaurants: $e');
}
}
}
70 changes: 70 additions & 0 deletions lib/infrastructure/driven_adapters/api/restaurant_fake.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import 'package:restaurant_tour/domain/models/restaurant/gateway/restaurant_gateway.dart';
import 'package:restaurant_tour/infrastructure/helpers/mappers/restaurant.dart';

class RestaurantFake extends RestaurantGateway {
@override
Future<Restaurant?> getRestaurant(String id) {
return Future.value(
Restaurant(
id: '',
name: '',
price: '',
rating: 5,
categories: [],
hours: [],
location: Location(),
photos: [],
reviews: [],
),
);
}

@override
Future<List<Restaurant>?> getRestaurants({int offset = 0}) {
return Future.value([
Restaurant.fromJson(
{
"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": "la_qZrx85d4b3WkeWBdbJA",
"rating": 5,
"text":
"Returned to celebrate our 20th Wedding Anniversary and was best ever! Anthony F. is exceptional! His energy amazing and recommendations on the ale's is...",
"user": {"id": "VHG6QeWwufacGY0M1ohJ3A", "image_url": null, "name": "Cheryl K."},
},
{
"id": "n5R8ulxap3NlVvFI9Jpt7g",
"rating": 5,
"text":
"Amazing food. Super yummy drinks. Great deals. All around great place to bring yourself, your family, and your doggies!! Always get excellent service....",
"user": {"id": "mpHWQc0QfftpIJ8BK9pQlQ", "image_url": null, "name": "Michelle N."},
},
{
"id": "-725DOCli9uaE4AmByHwLA",
"rating": 5,
"text":
"Absolutely amazing desert! The food was super good too! Alexia and Ursula were wonderful and super kind and responsive! Great staff and a very nice manager!...",
"user": {"id": "eUhgwQHJN1h1_JkNrfPN4w", "image_url": null, "name": "Alex B."},
}
],
"categories": [
{"title": "New American", "alias": "newamerican"},
{"title": "Comfort Food", "alias": "comfortfood"},
{"title": "Burgers", "alias": "burgers"},
],
"hours": [
{"is_open_now": true},
],
"location": {
"formatted_address": "6509 S Las Vegas Blvd\nLas Vegas, NV 89119",
},
},
),
]);
}
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:restaurant_tour/infrastructure/helpers/mappers/restaurant.dart';

List<Restaurant?> restaurantDataToRestaurants(RestaurantQueryResult restaurantsData) {
final restaurantsDataList = restaurantsData.restaurants ?? [];
return restaurantsDataList;
}

Restaurant? restaurantDataToRestaurant(RestaurantQueryResult restaurantData, String id) {
return restaurantData.restaurants?.firstWhere(
(restaurant) => restaurant.id == id,
);
}