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

Feature/fetch and display region specific restaurants on home view #33

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
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
46 changes: 30 additions & 16 deletions src/backend/functions/src/system/fakeDataPopulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import * as faker from 'faker';

// enable short hand for console.log()
function log(message: string) { console.log(`FakeDataPopulator | ${message}`); }

const FAKE_REGION_NAME = 'cape-town'
const NUMBER_OF_FAKE_MERCHANTS = 10
const NUMBER_OF_FAKE_PRODUCTS_PER_MERCHANTS = 30
const MERCHANTS_COLLECTION = 'merchants'
const REGIONS_COLLECTION = 'regions'
const PRODUCTS_COLLECTION = 'products'
/**
* A class that helps with populating a local firestore database
*/
Expand Down Expand Up @@ -35,33 +40,42 @@ export class FakeDataPopulator {
private async generateRegions() {
log('generateRegions');

await this.firestoreDatabase.collection('regions').doc('cape-town').set({});
await this.firestoreDatabase.collection(REGIONS_COLLECTION).doc(FAKE_REGION_NAME).set({});
}

private async generateMerchants() {
log('generateMerchants');

for (let index = 0; index < 30; index++) {
for (let index = 0; index < NUMBER_OF_FAKE_MERCHANTS; index++) {
let merchant = {
'name': faker.commerce.productName(),
'image': faker.image.imageUrl(640, 640, 'food'),
'images': [
faker.image.imageUrl(1024, 640, 'food', true),
faker.image.imageUrl(1024, 640, 'food', true),
faker.image.imageUrl(1024, 640, 'food', true),
],
'categories': [
faker.commerce.department(),
faker.commerce.department()
],
'rating': faker.datatype.float(2),
'rating': faker.datatype.float({
min: 0,
max: 5,
precision: 2
}),
'numberOfRatings': faker.datatype.number(200),
};

let merchantId = await this.createMerchantDocument(merchant);
let merchantId =
await this.createMerchantDocumentForSpecificRegion(merchant, FAKE_REGION_NAME);
await this.generateMerchantsProducts(merchantId);
}
}

private async generateMerchantsProducts(merchatId: string) {
log(`generateMerchantsProducts merchatId:${merchatId}`);
private async generateMerchantsProducts(merchantId: string) {
log(`generateMerchantsProducts merchatId:${merchantId}`);

for (let index = 0; index < 30; index++) {
for (let index = 0; index < NUMBER_OF_FAKE_PRODUCTS_PER_MERCHANTS; index++) {
let product = {
'name': faker.commerce.productName(),
'description': faker.lorem.paragraph(2),
Expand All @@ -70,17 +84,16 @@ export class FakeDataPopulator {
'price': faker.datatype.number(8999),
};

await this.createMerchantProduct(merchatId, product);
await this.createMerchantProduct(merchantId, product);
}
}

private async createMerchantProduct(merchantId: string, product: any) {
await this.firestoreDatabase.collection('merchants').doc(merchantId).collection('products').add(product);
private async createMerchantDocumentForSpecificRegion(merchant: any, regionId: string): Promise<string> {
let documentReference = await this.firestoreDatabase.collection(REGIONS_COLLECTION).doc(regionId).collection(MERCHANTS_COLLECTION).add(merchant);
return documentReference.id;
}

private async createMerchantDocument(merchant: any): Promise<string> {
let documentReference = await this.firestoreDatabase.collection('merchants').add(merchant);
return documentReference.id;
private async createMerchantProduct(merchantId: string, product: any) {
await this.firestoreDatabase.collection(REGIONS_COLLECTION).doc(FAKE_REGION_NAME).collection(MERCHANTS_COLLECTION).doc(merchantId).collection(PRODUCTS_COLLECTION).add(product)
}

private async createGenerateDocument(): Promise<void> {
Expand All @@ -91,4 +104,5 @@ export class FakeDataPopulator {
private getGenerateDocument(): firestore.DocumentReference {
return this.firestoreDatabase.collection('data').doc('generate');
}

}
35 changes: 35 additions & 0 deletions src/clients/box_ui/example/lib/example_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,46 @@ class ExampleView extends StatelessWidget {
...buttonWidgets,
...textWidgets,
...inputFields,
...largeRestaurantItems,
],
),
);
}

List<Widget> get largeRestaurantItems => [
verticalSpaceLarge,
BoxText.headline('LargeMerchantItem'),
verticalSpaceMedium,
LargeMerchantItem(
name: 'McDonald',
images: [
'https://baconmockup.com/640/360',
'https://baconmockup.com/641/360',
'https://baconmockup.com/639/360',
'https://baconmockup.com/638/360'
],
categories: ['Arabic', 'Turkish', 'Chinese'],
deliveryCost: 4.2,
deliveryInMinutes: 26,
rating: 3.4,
numberOfRatings: 41,
),
verticalSpaceMedium,
LargeMerchantItem(
name: 'McDonald',
images: [
'https://baconmockup.com/640/360',
'https://baconmockup.com/641/360',
'https://baconmockup.com/639/360',
'https://baconmockup.com/638/360'
],
categories: ['Arabic', 'Turkish', 'Chinese'],
deliveryCost: 0,
deliveryInMinutes: 26,
rating: 3.4,
numberOfRatings: 41,
)
];
List<Widget> get textWidgets => [
BoxText.headline('Text Styles'),
verticalSpaceMedium,
Expand Down
1 change: 1 addition & 0 deletions src/clients/box_ui/lib/box_ui.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export 'src/widgets/box_text.dart';
export 'src/widgets/box_button.dart';
export 'src/widgets/box_input_field.dart';
export 'src/widgets/autocomplete_listItem.dart';
export 'src/widgets/large_merchants_item.dart';

// Colors Export
export 'src/shared/app_colors.dart';
Expand Down
2 changes: 2 additions & 0 deletions src/clients/box_ui/lib/src/shared/app_colors.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';

const Color kcPrimaryColor = Color(0xff22A45D);
const Color kcDeepGreyColor = Color(0xff010F07);
const Color kcMediumGreyColor = Color(0xff868686);
const Color kcSemiLightColor = Color(0xffD8D8D8);
const Color kcLightGreyColor = Color(0xffe5e5e5);
const Color kcVeryLightGreyColor = Color(0xfff2f2f2);
3 changes: 2 additions & 1 deletion src/clients/box_ui/lib/src/shared/ui_helpers.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Horizontal Spacing
import 'package:flutter/material.dart';

const Widget horizontalSpaceTiny = SizedBox(width: 5.0);
Expand All @@ -23,3 +22,5 @@ double screenHeightPercentage(BuildContext context, {double percentage = 1}) =>

double screenWidthPercentage(BuildContext context, {double percentage = 1}) =>
screenWidth(context) * percentage;

const double screenHorizontalPadding = 16;
96 changes: 96 additions & 0 deletions src/clients/box_ui/lib/src/widgets/large_merchants_item.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import 'package:box_ui/box_ui.dart';
import 'package:box_ui/src/shared/styles.dart';
import 'package:flutter/material.dart';

import 'large_merchants_item_images_carousel.dart';

class LargeMerchantItem extends StatelessWidget {
final List<String> images;
final String name;
final List<String> categories;
final double? rating;
final int? numberOfRatings;
final int? deliveryInMinutes;
final double? deliveryCost;
final bool isClosed;

const LargeMerchantItem(
{Key? key,
required this.images,
required this.name,
required this.categories,
this.deliveryInMinutes,
this.deliveryCost,
this.rating,
this.numberOfRatings,
this.isClosed = false})
: super(key: key);

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LargeMerchantsItemImagesCarousel(
images: images,
),
verticalSpaceSmall,
BoxText.subheading(name),
verticalSpaceTiny,
BoxText.body(
categories.join(' • '),
color: kcMediumGreyColor,
),
verticalSpaceSmall,
Row(
children: [
if (rating != null) ...[
BoxText.caption(
rating.toString(),
),
horizontalSpaceTiny,
Icon(
Icons.star_rounded,
color: kcPrimaryColor,
size: 15,
),
horizontalSpaceTiny,
BoxText.caption(
numberOfRatings.toString() + ' Ratings',
),
horizontalSpaceTiny,
],
if (deliveryInMinutes != null) ...[
Icon(
Icons.watch_later_rounded,
color: Colors.black.withOpacity(0.6),
size: 15,
),
horizontalSpaceTiny,
BoxText.caption(
deliveryInMinutes.toString() + ' Min',
),
horizontalSpaceTiny,
],
if (deliveryCost != null) ...[
BoxText.body(
'•',
color: kcMediumGreyColor.withOpacity(0.5),
),
horizontalSpaceTiny,
Icon(
Icons.attach_money_rounded,
color: kcMediumGreyColor,
size: 15,
),
horizontalSpaceTiny,
BoxText.caption(
deliveryCost == 0.0 ? 'Free' : deliveryCost.toString(),
),
]
],
)
],
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import 'package:box_ui/src/shared/app_colors.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';

class LargeMerchantsItemImagesCarousel extends StatefulWidget {
final List<String> images;
const LargeMerchantsItemImagesCarousel({Key? key, required this.images})
: super(key: key);

@override
_LargeMerchantsItemImagesCarouselState createState() =>
_LargeMerchantsItemImagesCarouselState();
}

class _LargeMerchantsItemImagesCarouselState
extends State<LargeMerchantsItemImagesCarousel> {
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(20),
child: CarouselSlider(
items: widget.images
.map((image) => Container(
width: double.infinity,
color: kcLightGreyColor,
child: Image.network(
image,
fit: BoxFit.cover,
),
))
.toList(),
options: CarouselOptions(
aspectRatio: 1.8,
viewportFraction: 1,
onPageChanged: (currentPageIndex, _) {
setState(() {
_currentIndex = currentPageIndex;
});
})),
),
_CarouselCustomIndexWidget(
currentIndex: _currentIndex,
images: widget.images,
)
],
);
}
}

class _CarouselCustomIndexWidget extends StatelessWidget {
final List<String> images;
final int currentIndex;
const _CarouselCustomIndexWidget(
{Key? key, required this.currentIndex, required this.images})
: super(key: key);

@override
Widget build(BuildContext context) {
return Positioned(
bottom: 20,
right: 20,
child: Row(
children: [
...images.asMap().entries.map((map) => Container(
margin: const EdgeInsets.only(right: 8),
width: 8,
height: 5,
decoration: BoxDecoration(
color: Colors.white
.withOpacity(currentIndex == map.key ? 1 : 0.3),
borderRadius: BorderRadius.circular(32)),
))
],
),
);
}
}
2 changes: 1 addition & 1 deletion src/clients/box_ui/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ environment:
dependencies:
flutter:
sdk: flutter

carousel_slider: ^4.0.0
dev_dependencies:
flutter_test:
sdk: flutter
Expand Down
Loading