From 008ad0ccaf07753de14129579c5dcfd20a6eb53b Mon Sep 17 00:00:00 2001 From: IT20611088 Date: Sun, 29 Oct 2023 13:52:01 +0530 Subject: [PATCH 01/12] comments added to item user site --- backend/src/__tests__/item.test.ts | 22 ++++++++++++++++ backend/src/__tests__/site.test.ts | 26 +++++++++++++++++++ backend/src/__tests__/user-management.test.ts | 18 +++++++++++++ 3 files changed, 66 insertions(+) diff --git a/backend/src/__tests__/item.test.ts b/backend/src/__tests__/item.test.ts index 3d992f9..2f3de50 100644 --- a/backend/src/__tests__/item.test.ts +++ b/backend/src/__tests__/item.test.ts @@ -27,6 +27,10 @@ export const userPayload = { contactNumber: "0712345678", }; + +/** + * Main test suite + */ describe("site", () => { beforeAll(async () => { const mongoServer = await MongoMemoryServer.create(); @@ -37,8 +41,13 @@ describe("site", () => { await mongoose.disconnect(); await mongoose.connection.close(); }); + + /** + * Sub test suite 1 - POST operation + */ describe("create item route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const { statusCode } = await supertest(app).post("/api/items"); @@ -46,6 +55,7 @@ describe("site", () => { }); }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 200 and create the item", async () => { const jwt = signJwt(userPayload); @@ -60,14 +70,20 @@ describe("site", () => { }); }); }); + + /** + * Sub test suite 2 - GET operation (all) + */ describe("get item list route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const { statusCode } = await supertest(app).get("/api/items"); expect(statusCode).toBe(403); }); }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 200 and get the item list", async () => { const jwt = signJwt(userPayload); @@ -81,8 +97,13 @@ describe("site", () => { }); }); }); + + /** + * Sub test suite 3 - update site + */ describe("update item route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const oldItem = await createItem(itemPayload); const { statusCode } = await supertest(app).put( @@ -93,6 +114,7 @@ describe("site", () => { }); }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 200 and update the item", async () => { const jwt = signJwt(userPayload); diff --git a/backend/src/__tests__/site.test.ts b/backend/src/__tests__/site.test.ts index 7c3e153..4607609 100644 --- a/backend/src/__tests__/site.test.ts +++ b/backend/src/__tests__/site.test.ts @@ -27,6 +27,10 @@ export const userPayload = { contactNumber: "0712345678", }; + +/** + * Main test suite + */ describe("site", () => { beforeAll(async () => { const mongoServer = await MongoMemoryServer.create(); @@ -37,8 +41,14 @@ describe("site", () => { await mongoose.disconnect(); await mongoose.connection.close(); }); + + + /** + * Sub test suite 1 - POST operation + */ describe("create site route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const { statusCode } = await supertest(app).post("/api/sites"); @@ -47,6 +57,7 @@ describe("site", () => { }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 200 and create the site", async () => { const jwt = signJwt(userPayload); @@ -62,8 +73,12 @@ describe("site", () => { }); }); + /** + * Sub test suite 2 - GET operation (all) + */ describe("get sites list route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const { statusCode } = await supertest(app).get("/api/sites"); @@ -72,6 +87,7 @@ describe("site", () => { }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 200 and the sites", async () => { const jwt = signJwt(userPayload); @@ -92,8 +108,12 @@ describe("site", () => { }); }); + /** + * Sub test suite 3 - GET operation (particular site) + */ describe("get site by id route", () => { describe("given the site does not exist", () => { + /* failure scenario */ it("should return a 404", async () => { const siteId = "site-123"; const jwt = signJwt(userPayload); @@ -106,6 +126,7 @@ describe("site", () => { }); describe("given the site does exist", () => { + /* success scenario */ it("should return a 200 status and the site", async () => { const site = await createSite(sitePayload); const jwt = signJwt(userPayload); @@ -121,8 +142,12 @@ describe("site", () => { }); }); + /** + * Sub test suite 4 - update site + */ describe("update site route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const site = await createSite(sitePayload); const { statusCode } = await supertest(app).put( @@ -133,6 +158,7 @@ describe("site", () => { }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 200 and update the site", async () => { const site = await createSite(sitePayload); const jwt = signJwt(userPayload); diff --git a/backend/src/__tests__/user-management.test.ts b/backend/src/__tests__/user-management.test.ts index 1837900..afa4b4d 100644 --- a/backend/src/__tests__/user-management.test.ts +++ b/backend/src/__tests__/user-management.test.ts @@ -28,6 +28,9 @@ const userInput: CreateUserInput["body"] = { contactNumber: "0712345678", }; +/** + * Main test suite + */ describe("user-management", () => { beforeAll(async () => { const mongoServer = await MongoMemoryServer.create(); @@ -38,8 +41,12 @@ describe("user-management", () => { await mongoose.connection.close(); }); + /** + * Sub test suite 1 - POST operation + */ describe("create user route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const { statusCode } = await supertest(app).post( "/api/user-management" @@ -50,6 +57,7 @@ describe("user-management", () => { }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 201 and create the user", async () => { const jwt = signJwt(userPayload); @@ -65,8 +73,12 @@ describe("user-management", () => { }); }); + /** + * Sub test suite 2 - GET operation (all) + */ describe("get user list route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const { statusCode } = await supertest(app).get("/api/user-management"); @@ -75,6 +87,7 @@ describe("user-management", () => { }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 200 and the users", async () => { const jwt = signJwt(userPayload); @@ -89,8 +102,12 @@ describe("user-management", () => { }); }); + /** + * Sub test suite 4 - update user + */ describe("update user route", () => { describe("given the user is not logged in", () => { + /* failure scenario */ it("should return a 403", async () => { const { statusCode } = await supertest(app).put( `/api/user-management/${userPayload.userId}` @@ -101,6 +118,7 @@ describe("user-management", () => { }); describe("given the user is logged in", () => { + /* success scenario */ it("should return a 200 and update the user", async () => { const jwt = signJwt(userPayload); From 5067e418f419198fc26b4c3dad9e51ac0558dc12 Mon Sep 17 00:00:00 2001 From: shavindaL Date: Sun, 29 Oct 2023 16:00:56 +0530 Subject: [PATCH 02/12] display all orders --- flutter_client/lib/blocs/cart/cart_bloc.dart | 1 + .../lib/blocs/order/order_bloc.dart | 14 ++ .../lib/blocs/order/order_event.dart | 4 + .../lib/blocs/order/order_state.dart | 14 ++ flutter_client/lib/models/order.dart | 31 ++-- flutter_client/lib/models/order_product.dart | 6 +- flutter_client/lib/procument_mobile_app.dart | 6 - .../repositiories/order/order_repository.dart | 57 ++++-- .../create_requisition_order_page.dart | 1 - .../lib/screens/delivery_details_screen.dart | 142 ++++++++------- .../lib/screens/my_orders_screen.dart | 170 +++++------------- .../lib/screens/order_sucess_screen.dart | 42 +++++ .../lib/widgets/my_orders_card.dart | 148 +++++++++------ .../lib/widgets/supplier_details_card.dart | 1 + 14 files changed, 359 insertions(+), 278 deletions(-) create mode 100644 flutter_client/lib/screens/order_sucess_screen.dart diff --git a/flutter_client/lib/blocs/cart/cart_bloc.dart b/flutter_client/lib/blocs/cart/cart_bloc.dart index fd17a79..008ae68 100644 --- a/flutter_client/lib/blocs/cart/cart_bloc.dart +++ b/flutter_client/lib/blocs/cart/cart_bloc.dart @@ -104,6 +104,7 @@ class CartBloc extends Bloc { void _clearCartHandler(ClearCartEvent event, Emitter emit) { cart.clear(); + _temporaryProducts.clear(); emit(ProductCartUpdated(orderProducts: cart, cartTotal: 0)); } diff --git a/flutter_client/lib/blocs/order/order_bloc.dart b/flutter_client/lib/blocs/order/order_bloc.dart index fabc984..c0014a0 100644 --- a/flutter_client/lib/blocs/order/order_bloc.dart +++ b/flutter_client/lib/blocs/order/order_bloc.dart @@ -13,6 +13,20 @@ class OrderBloc extends Bloc { final AuthRepository _authRepository = AuthRepository(); OrderBloc() : super(const OrderInitial()) { on(_onCreateOrderHandler); + on(_onGetOrdersHandler); + } + + void _onGetOrdersHandler( + GetOrdersEvent event, + Emitter emit, + ) async { + emit(GettingOrders()); + try { + List orders = await _orderRepository.getOrders(); + emit(OrdersRetrieved(orders: orders)); + } catch (e) { + emit(ErrorRetrievingOrders(message: e.toString())); + } } void _onCreateOrderHandler( diff --git a/flutter_client/lib/blocs/order/order_event.dart b/flutter_client/lib/blocs/order/order_event.dart index 31e6faf..db12ba5 100644 --- a/flutter_client/lib/blocs/order/order_event.dart +++ b/flutter_client/lib/blocs/order/order_event.dart @@ -10,3 +10,7 @@ class CreateOrderEvent extends OrderEvent { const CreateOrderEvent({required this.order}); } + +class GetOrdersEvent extends OrderEvent { + const GetOrdersEvent(); +} diff --git a/flutter_client/lib/blocs/order/order_state.dart b/flutter_client/lib/blocs/order/order_state.dart index 3e77369..f3e77c7 100644 --- a/flutter_client/lib/blocs/order/order_state.dart +++ b/flutter_client/lib/blocs/order/order_state.dart @@ -19,3 +19,17 @@ class OrderNotCreated extends OrderInitial { const OrderNotCreated({required this.message}); } + +class GettingOrders extends OrderInitial {} + +class OrdersRetrieved extends OrderInitial { + final List orders; + + const OrdersRetrieved({required this.orders}); +} + +class ErrorRetrievingOrders extends OrderInitial { + final String message; + + const ErrorRetrievingOrders({required this.message}); +} diff --git a/flutter_client/lib/models/order.dart b/flutter_client/lib/models/order.dart index c289177..f15d3d8 100644 --- a/flutter_client/lib/models/order.dart +++ b/flutter_client/lib/models/order.dart @@ -7,6 +7,8 @@ class Order { final String siteId; final String? siteManagerId; final List products; + final String? status; + final double? total; Order({ required this.supplierId, @@ -14,26 +16,33 @@ class Order { required this.dateToBeDelivered, required this.siteId, this.siteManagerId, + this.status, required this.products, + this.total, }); - set setSupplierId(String supplierId) { - supplierId = supplierId; + factory Order.fromJson(Map json) { + return Order( + supplierId: json['supplier']['_id'], + orderId: json['orderId'], + dateToBeDelivered: + DateTime.now(), //DateTime.parse(json['dateToBeDelivered']), + siteId: json['site']['_id'], + siteManagerId: json['siteManager']['_id'], + products: (json['items'] as List).map((product) { + return OrderProduct.fromJson(product); + }).toList(), + status: json['status'], + total: int.parse(json['total'].toString()).toDouble(), + ); } set setProducts(List products) { products = products; } - factory Order.fromJson(Map json) { - return Order( - supplierId: json['supplier'], - orderId: json['orderId'], - dateToBeDelivered: DateTime.parse(json['dateToBeDelivered']), - siteId: json['site'], - siteManagerId: json['siteManager'], - products: [], - ); + set setSupplierId(String supplierId) { + supplierId = supplierId; } Map toJson() { diff --git a/flutter_client/lib/models/order_product.dart b/flutter_client/lib/models/order_product.dart index 859ddf0..92f2047 100644 --- a/flutter_client/lib/models/order_product.dart +++ b/flutter_client/lib/models/order_product.dart @@ -23,10 +23,10 @@ class OrderProduct { factory OrderProduct.fromJson(Map json) { return OrderProduct( - productId: json['item'], + productId: json['item']['itemId'], quantity: json['quantity'], - price: json['price'], - title: json['name'], + price: double.parse((json['item']['price']).toString()), + title: json['item']['name'], ); } diff --git a/flutter_client/lib/procument_mobile_app.dart b/flutter_client/lib/procument_mobile_app.dart index af7d2e7..77ed1a2 100644 --- a/flutter_client/lib/procument_mobile_app.dart +++ b/flutter_client/lib/procument_mobile_app.dart @@ -6,12 +6,7 @@ import 'package:flutter_client/blocs/auth/auth_bloc.dart'; import 'package:flutter_client/constants.dart'; import 'package:flutter_client/repositiories/auth/auth_repository.dart'; -import 'package:flutter_client/screens/delivery_details.dart'; -import 'package:flutter_client/screens/done.dart'; -import 'package:flutter_client/screens/home_screen.dart'; import 'package:flutter_client/screens/login_screen.dart'; -import 'package:flutter_client/screens/my_order_details.dart'; -import 'package:flutter_client/screens/my_orders.dart'; import 'package:flutter_client/screens/main_screen.dart'; @@ -93,7 +88,6 @@ class _ProcumentMobileAppState extends State { ), // home: _isTokenAvailable ? const HomeScreen() : const LoginScreen(), home: _isTokenAvailable ? const MainScreen() : const LoginScreen(), - ), ); } diff --git a/flutter_client/lib/repositiories/order/order_repository.dart b/flutter_client/lib/repositiories/order/order_repository.dart index 174494e..24fdf01 100644 --- a/flutter_client/lib/repositiories/order/order_repository.dart +++ b/flutter_client/lib/repositiories/order/order_repository.dart @@ -17,6 +17,7 @@ class OrderRepository extends BaseOrderRepository { final headers = { 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', }; // send request to get all suppliers @@ -35,16 +36,16 @@ class OrderRepository extends BaseOrderRepository { }, ); - developer.log("body: ${requestBody.toString()}", name: "OrderRepository"); final responseBody = await http.post(orderURL, headers: headers, body: requestBody); - // .then((response) => response.body) - developer.log("responseBody: ${jsonDecode(responseBody.body).toString()}", - name: "OrderRepository"); - developer.log("responseBody: ${responseBody.statusCode}", - name: "OrderRepository"); - return true; + if (responseBody.statusCode == 201) { + return true; + } else { + developer.log(responseBody.body, + name: "OrderRepository", error: responseBody.body); + return false; + } } on TypeError catch (e) { developer.log(e.toString(), stackTrace: e.stackTrace, error: e, name: "OrderRepository"); @@ -81,16 +82,38 @@ class OrderRepository extends BaseOrderRepository { @override Future> getOrders() async { - return [ - Order( - supplierId: '1', - orderId: '1', - dateToBeDelivered: DateTime.now(), - siteId: '1', - siteManagerId: '1', - products: [], - ) - ]; + final Uri orderURL = Uri.https(hostName, orderPath); + // get token from shared preferences + final sharedPreferences = await SharedPreferences.getInstance(); + final token = sharedPreferences.getString('jwt'); + + final headers = { + 'Authorization': 'Bearer $token', + }; + + // send request to get all suppliers + try { + final responseBody = await http.get(orderURL, headers: headers); + if (responseBody.statusCode == 200) { + final List orders = jsonDecode(responseBody.body); + developer.log(orders[0]['items'].toString(), name: "OrderRepository"); + return orders.map((order) => Order.fromJson(order)).toList(); + } else { + developer.log(responseBody.body, + name: "OrderRepository", error: responseBody.body); + return []; + } + } on TypeError catch (e) { + developer.log(e.toString(), + stackTrace: e.stackTrace, error: e, name: "OrderRepository"); + throw Exception(e); + } on FormatException catch (e) { + developer.log(e.message.toString(), error: e, name: "OrderRepository"); + throw Exception(e); + } catch (e) { + developer.log(e.toString(), name: "OrderRepository", error: e); + throw Exception(e); + } } @override diff --git a/flutter_client/lib/screens/create_requisition_order_page.dart b/flutter_client/lib/screens/create_requisition_order_page.dart index 5ec47f4..49cf3a1 100644 --- a/flutter_client/lib/screens/create_requisition_order_page.dart +++ b/flutter_client/lib/screens/create_requisition_order_page.dart @@ -33,7 +33,6 @@ class _CreateRequisitionOrderState extends State { builder: (context, state) { return Scaffold( appBar: AppBar( - // leading: const Icon(Icons.arrow_back_ios), title: Text( 'Create Requisition Order', style: Theme.of(context).textTheme.titleMedium!.copyWith( diff --git a/flutter_client/lib/screens/delivery_details_screen.dart b/flutter_client/lib/screens/delivery_details_screen.dart index 73b58a7..77c7981 100644 --- a/flutter_client/lib/screens/delivery_details_screen.dart +++ b/flutter_client/lib/screens/delivery_details_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter_client/blocs/order/order_bloc.dart'; import 'package:flutter_client/blocs/site/site_bloc.dart'; import 'package:flutter_client/models/order.dart'; import 'package:flutter_client/models/site.dart'; +import 'package:flutter_client/screens/order_sucess_screen.dart'; class DeliveryDetailsScreen extends StatefulWidget { const DeliveryDetailsScreen({super.key}); @@ -63,19 +64,25 @@ class _DeliveryDetailsScreenState extends State { BlocListener( listener: (context, state) { if (state is SiteLoaded) { - setState(() { - _sites.addAll(state.sites); - }); - - _dropdownValue = _sites[0].siteId; + if (state.sites.isNotEmpty) { + setState(() { + _sites.addAll(state.sites); + _dropdownValue = _sites[0].siteId; + _selectedSite = _sites[0].id; + }); + } } }, ), BlocListener( listener: (context, state) { if (state is OrderCreated) { - // BlocProvider.of(context).add(const ClearCartEvent()); - // Navigator.of(context).pop(); + BlocProvider.of(context).add(const ClearCartEvent()); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const OrderSuccessScreen(), + ), + ); } if (state is OrderNotCreated) { @@ -128,9 +135,6 @@ class _DeliveryDetailsScreenState extends State { site.siteId == selectedSite) .first .id; - // _sites.firstWhere( - // (element) => - // element.siteId == newValue); }, ); }, @@ -200,60 +204,74 @@ class _DeliveryDetailsScreenState extends State { const SizedBox( height: 100, ), - ElevatedButton( - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - backgroundColor: - Theme.of(context).colorScheme.primary, - ), - onPressed: () { - BlocProvider.of(context).add( - CreateOrderEvent( - order: Order( - supplierId: - BlocProvider.of(context) - .supplier - .id, - dateToBeDelivered: selectedDate, - siteId: _selectedSite, - products: - BlocProvider.of(context) - .cart, - ), - ), - ); - // Navigator.of(context).pop(); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Total: LKR ${_cartTotal.toStringAsFixed(2)}', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Colors.white, + BlocBuilder( + builder: (context, state) { + return state is! CreatingOrder + ? ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(8.0), + ), + backgroundColor: Theme.of(context) + .colorScheme + .primary, ), - ), - const Spacer(), - Text( - 'Finish', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Colors.white, + onPressed: () { + BlocProvider.of(context) + .add( + CreateOrderEvent( + order: Order( + supplierId: + BlocProvider.of( + context) + .supplier + .id, + dateToBeDelivered: + selectedDate, + siteId: _selectedSite, + products: + BlocProvider.of( + context) + .cart, + ), + ), + ); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Text( + 'Total: LKR ${_cartTotal.toStringAsFixed(2)}', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: Colors.white, + ), + ), + const Spacer(), + Text( + 'Finish', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: Colors.white, + ), + ), + const Icon( + Icons.chevron_right, + color: Colors.white, + ) + ], ), - ), - const Icon( - Icons.chevron_right, - color: Colors.white, - ) - ], - ), + ) + : const Center( + child: CircularProgressIndicator(), + ); + }, ), ], ), diff --git a/flutter_client/lib/screens/my_orders_screen.dart b/flutter_client/lib/screens/my_orders_screen.dart index c952104..0eb1734 100644 --- a/flutter_client/lib/screens/my_orders_screen.dart +++ b/flutter_client/lib/screens/my_orders_screen.dart @@ -1,145 +1,59 @@ -import 'package:flutter_client/constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_client/screens/order_details_screen.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_client/blocs/order/order_bloc.dart'; +import 'package:flutter_client/widgets/my_orders_card.dart'; -class OrderButtonProperties { - final Color color; - final String text; - - OrderButtonProperties(this.color, this.text); -} - -class MyOrders extends StatelessWidget { +class MyOrders extends StatefulWidget { const MyOrders({super.key}); - final String orderState = 'placed'; + @override + State createState() => _MyOrdersState(); +} - OrderButtonProperties getButtonProperties(String state) { - switch (state) { - case 'pending': - return OrderButtonProperties(viewPending, 'Pending'); - case 'approved': - return OrderButtonProperties(approvedAndOrderCompleted, 'Approved'); - case 'declined': - return OrderButtonProperties(declined, 'Declined'); - case 'placed': - return OrderButtonProperties(placed, 'Placed'); - case 'partially delivered': - return OrderButtonProperties(partialyDelivered, 'Partially delivered'); - default: - return OrderButtonProperties(approvedAndOrderCompleted, 'Completed'); - } +class _MyOrdersState extends State { + @override + void initState() { + super.initState(); + BlocProvider.of(context).add(const GetOrdersEvent()); } @override Widget build(BuildContext context) { - final buttonProperties = getButtonProperties(orderState); - return Scaffold( appBar: AppBar( title: const Text('My orders'), ), - body: Center( - child: Padding( - padding: const EdgeInsets.all(25.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InkWell( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const MyOrderDetails(), - ), - ); - }, - child: Card( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.zero), - ), - elevation: 8, - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Create order', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - Text( - 'Date', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 20), - Text( - 'Supplier name', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - Row( - children: [ - Text( - 'Rs.25.000', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.normal, - ), - ), - const Spacer(), - Container( - decoration: BoxDecoration( - color: buttonProperties.color, - borderRadius: BorderRadius.circular(8), - ), - child: TextButton( - onPressed: null, - child: Text( - buttonProperties.text, - style: const TextStyle(color: Colors.white), - ), - ), - ), - ], - ), - ], - ), - ), - ), - ), + body: BlocBuilder( + builder: (context, state) { + if (state is GettingOrders) { + return const Center( + child: CircularProgressIndicator(), + ); + } else if (state is OrdersRetrieved) { + return ListView.separated( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + itemCount: state.orders.length, + itemBuilder: (context, index) { + return MyOrdersCard(order: state.orders[index]); + }, + separatorBuilder: (BuildContext context, int index) => + const SizedBox( + height: 10, ), - ], - ), - ), + ); + } else if (state is ErrorRetrievingOrders) { + return Center( + child: Text(state.message), + ); + } else { + return const Center( + child: Text('Something went wrong'), + ); + } + }, ), ); } diff --git a/flutter_client/lib/screens/order_sucess_screen.dart b/flutter_client/lib/screens/order_sucess_screen.dart new file mode 100644 index 0000000..0274e7b --- /dev/null +++ b/flutter_client/lib/screens/order_sucess_screen.dart @@ -0,0 +1,42 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class OrderSuccessScreen extends StatelessWidget { + const OrderSuccessScreen({super.key}); + + @override + Widget build(BuildContext context) { + Timer(const Duration(seconds: 3), () { + Navigator.of(context).popUntil((route) => route.isFirst); + }); + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + "images/successfully-done.gif", + height: 150, + ), + Text( + "Success!", + style: TextStyle( + fontSize: 19, + fontWeight: FontWeight.w700, + ), + ), + Text( + "Order Created.", + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + ); + } +} diff --git a/flutter_client/lib/widgets/my_orders_card.dart b/flutter_client/lib/widgets/my_orders_card.dart index 7a72ce4..6d4637c 100644 --- a/flutter_client/lib/widgets/my_orders_card.dart +++ b/flutter_client/lib/widgets/my_orders_card.dart @@ -1,70 +1,118 @@ import 'package:flutter/material.dart'; -import 'package:flutter_client/models/user_model.dart'; -import 'package:flutter_client/screens/supplier_products_screen.dart'; +import 'package:flutter_client/constants.dart'; +import 'package:flutter_client/models/order.dart'; +import 'package:flutter_client/screens/my_order_details.dart'; -class MyOrdersCard extends StatelessWidget { - const MyOrdersCard({required this.supplier, super.key}); - final User supplier; +class OrderButtonProperties { + final Color color; + final String text; + + OrderButtonProperties(this.color, this.text); +} +class MyOrdersCard extends StatelessWidget { + const MyOrdersCard({required this.order, super.key}); + final Order order; @override Widget build(BuildContext context) { void ontapHandler() { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => SupplierProductsScreen( - supplier: supplier, + () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const MyOrderDetails(), ), - ), - ); + ); + }; } - return Card( - surfaceTintColor: Colors.white, - elevation: 5, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: ListTile( - selected: true, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - title: Text( - supplier.name, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.w900, + OrderButtonProperties getButtonProperties(String state) { + switch (state) { + case 'pending': + return OrderButtonProperties(viewPending, 'Pending'); + case 'approved': + return OrderButtonProperties(approvedAndOrderCompleted, 'Approved'); + case 'declined': + return OrderButtonProperties(declined, 'Declined'); + case 'placed': + return OrderButtonProperties(placed, 'Placed'); + case 'partially delivered': + return OrderButtonProperties( + partialyDelivered, 'Partially delivered'); + default: + return OrderButtonProperties(approvedAndOrderCompleted, 'Completed'); + } + } + + return InkWell( + onTap: ontapHandler, + child: Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.zero), + ), + elevation: 8, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + order.orderId!, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + const Spacer(), + Text( + order.dateToBeDelivered.toString().split(' ')[0], + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ], ), - ), - subtitle: supplier.products.isNotEmpty - ? Column( + const SizedBox(height: 20), + Text( + order.supplierId, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + Row( children: [ - ...supplier.products.map( - (product) => Row( - children: [ - Icon(Icons.circle, - size: 8.0, color: Colors.grey.shade500), - const SizedBox(width: 4.0), - Text( - product.title, - style: - Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.normal, - color: Colors.black, - ), + Text( + 'LKR ${order.total!.toStringAsFixed(2)}', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.normal, ), - const SizedBox(width: 16.0), - ], + ), + const Spacer(), + Container( + decoration: BoxDecoration( + color: getButtonProperties(order.status!).color, + borderRadius: BorderRadius.circular(8), + ), + child: TextButton( + onPressed: null, + child: Text( + getButtonProperties(order.status!).text, + style: const TextStyle(color: Colors.white), + ), ), ), ], - ) - : null, - trailing: Text( - supplier.contactNumber, - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w900, ), + ], + ), ), - onTap: ontapHandler, ), ), ); diff --git a/flutter_client/lib/widgets/supplier_details_card.dart b/flutter_client/lib/widgets/supplier_details_card.dart index 574c15f..36ff803 100644 --- a/flutter_client/lib/widgets/supplier_details_card.dart +++ b/flutter_client/lib/widgets/supplier_details_card.dart @@ -12,6 +12,7 @@ class SupplierDetailsCard extends StatelessWidget { Widget build(BuildContext context) { void ontapHandler() { BlocProvider.of(context).supplier = supplier; + BlocProvider.of(context).add(const ClearCartEvent()); Navigator.of(context).push( MaterialPageRoute( builder: (context) => SelectedProductsScreen( From ef3b4146c956f5da4b84f189cfa1f7788c2d4cdf Mon Sep 17 00:00:00 2001 From: Sandaru <87793405+IT21001352@users.noreply.github.com> Date: Sun, 29 Oct 2023 16:16:36 +0530 Subject: [PATCH 03/12] delivery view and confirm done --- backend/src/service/deliver.service.ts | 1 + .../goodReceipts/goods_receipt_bloc.dart | 27 +++ .../goodReceipts/goods_receipt_event.dart | 5 + .../goodReceipts/goods_receipt_state.dart | 24 +++ flutter_client/lib/models/goods_receipt.dart | 29 ++- .../base_goods_receipt_repository.dart | 20 ++ flutter_client/lib/repositiories/paths.dart | 1 + .../screens/delivery_advices_list_screen.dart | 63 +++--- .../lib/screens/delivery_confirmation.dart | 140 ------------ .../screens/delivery_confirmation_screen.dart | 201 ++++++++++++++++++ flutter_client/lib/widgets/delivery_card.dart | 92 ++++++-- 11 files changed, 410 insertions(+), 193 deletions(-) delete mode 100644 flutter_client/lib/screens/delivery_confirmation.dart create mode 100644 flutter_client/lib/screens/delivery_confirmation_screen.dart diff --git a/backend/src/service/deliver.service.ts b/backend/src/service/deliver.service.ts index 273d70d..0b033c3 100644 --- a/backend/src/service/deliver.service.ts +++ b/backend/src/service/deliver.service.ts @@ -19,6 +19,7 @@ export async function getDeliveryList( .populate("order") .populate("supplier") .populate("site") + .sort({ createdAt: -1 }) .exec(); } diff --git a/flutter_client/lib/blocs/goodReceipts/goods_receipt_bloc.dart b/flutter_client/lib/blocs/goodReceipts/goods_receipt_bloc.dart index 34c2046..7a23bc1 100644 --- a/flutter_client/lib/blocs/goodReceipts/goods_receipt_bloc.dart +++ b/flutter_client/lib/blocs/goodReceipts/goods_receipt_bloc.dart @@ -12,6 +12,7 @@ class GoodsReceiptBloc extends Bloc { GoodsReceiptBloc() : super(GoodsReceiptInitial()) { on(_getGoodsReceiptsHandler); + on(_markAsReceivedHandler); } // Load products @@ -34,4 +35,30 @@ class GoodsReceiptBloc extends Bloc { }, ); } + + // Mark as received + void _markAsReceivedHandler( + MarkAsReceivedEvent event, Emitter emit) async { + emit( + GoodsReceiptMarkingAsReceived( + goodsReceiptNumber: event.goodsReceiptNumber, + ), + ); + + await _goodsReceiptRepository + .markedAsReceived(event.goodsReceiptNumber) + .then( + (goodsReceipt) { + emit(GoodsReceiptMarkedAsReceived( + goodsReceiptNumber: event.goodsReceiptNumber)); + }, + ).catchError( + (error) { + emit( + const GoodsReceiptMarkedAsReceivedError( + message: "Error marking goods receipt as received."), + ); + }, + ); + } } diff --git a/flutter_client/lib/blocs/goodReceipts/goods_receipt_event.dart b/flutter_client/lib/blocs/goodReceipts/goods_receipt_event.dart index ff3626c..10c4c6f 100644 --- a/flutter_client/lib/blocs/goodReceipts/goods_receipt_event.dart +++ b/flutter_client/lib/blocs/goodReceipts/goods_receipt_event.dart @@ -8,3 +8,8 @@ abstract class GoodsReceiptEvent { class GetGoodsReceiptsEvent extends GoodsReceiptEvent { const GetGoodsReceiptsEvent(); } + +class MarkAsReceivedEvent extends GoodsReceiptEvent { + final String goodsReceiptNumber; + const MarkAsReceivedEvent(this.goodsReceiptNumber); +} diff --git a/flutter_client/lib/blocs/goodReceipts/goods_receipt_state.dart b/flutter_client/lib/blocs/goodReceipts/goods_receipt_state.dart index 7f554d4..07946ea 100644 --- a/flutter_client/lib/blocs/goodReceipts/goods_receipt_state.dart +++ b/flutter_client/lib/blocs/goodReceipts/goods_receipt_state.dart @@ -24,3 +24,27 @@ final class GoodsReceiptsLoaded extends GoodsReceiptState { required this.goodsReceipts, }); } + +final class GoodsReceiptMarkingAsReceived extends GoodsReceiptState { + final String goodsReceiptNumber; + + const GoodsReceiptMarkingAsReceived({ + required this.goodsReceiptNumber, + }); +} + +final class GoodsReceiptMarkedAsReceived extends GoodsReceiptState { + final String goodsReceiptNumber; + + const GoodsReceiptMarkedAsReceived({ + required this.goodsReceiptNumber, + }); +} + +final class GoodsReceiptMarkedAsReceivedError extends GoodsReceiptState { + final String message; + + const GoodsReceiptMarkedAsReceivedError({ + required this.message, + }); +} diff --git a/flutter_client/lib/models/goods_receipt.dart b/flutter_client/lib/models/goods_receipt.dart index ae75811..4144bfe 100644 --- a/flutter_client/lib/models/goods_receipt.dart +++ b/flutter_client/lib/models/goods_receipt.dart @@ -25,6 +25,29 @@ class Supplier { } } +class Site { + final String id; + final String name; + final String address; + final String contactNumber; + + Site({ + required this.id, + required this.name, + required this.address, + required this.contactNumber, + }); + + factory Site.fromJson(Map json) { + return Site( + id: json['_id'], + name: json['name'], + address: json['address'], + contactNumber: json['contactNumber'], + ); + } +} + class GoodsReceiptItem { final Product item; final int quantity; @@ -37,13 +60,13 @@ class GoodsReceiptItem { class GoodsReceipt { final String id; - final String site; final String siteManager; final String goodsReceiptId; final GoodsReceiptStatus status; final List items; final Supplier supplier; final DateTime createdAt; + final Site site; GoodsReceipt({ required this.id, @@ -60,10 +83,10 @@ class GoodsReceipt { return GoodsReceipt( id: json['_id'], supplier: Supplier.fromJson(json['supplier']), - site: json['site'], + site: Site.fromJson(json['site']), siteManager: json['siteManager'], goodsReceiptId: json['goodReceiptId'], - status: json['status'] == 'shipped' + status: json['status'] == 'received' ? GoodsReceiptStatus.received : GoodsReceiptStatus.pendingShipping, items: json['items'] diff --git a/flutter_client/lib/repositiories/goods_receipt/base_goods_receipt_repository.dart b/flutter_client/lib/repositiories/goods_receipt/base_goods_receipt_repository.dart index a5180ab..a264781 100644 --- a/flutter_client/lib/repositiories/goods_receipt/base_goods_receipt_repository.dart +++ b/flutter_client/lib/repositiories/goods_receipt/base_goods_receipt_repository.dart @@ -49,4 +49,24 @@ class GoodsReceiptRepository extends BaseGoodsReceiptRepository { return goodsReceiptList; } + + Future markedAsReceived(String goodsReceiptNumber) async { + final Uri goodsReceiptURL = + Uri.https(hostName, '$markAsReceivedPath/$goodsReceiptNumber/received'); + + final sharedPreferences = await SharedPreferences.getInstance(); + final token = sharedPreferences.getString('jwt'); + + final headers = { + 'Authorization': 'Bearer $token', + }; + + await http + .patch(goodsReceiptURL, headers: headers) + .then((response) => response.body) + .catchError((error) { + developer.log(error); + throw Exception(error); + }); + } } diff --git a/flutter_client/lib/repositiories/paths.dart b/flutter_client/lib/repositiories/paths.dart index 835809b..166c121 100644 --- a/flutter_client/lib/repositiories/paths.dart +++ b/flutter_client/lib/repositiories/paths.dart @@ -4,3 +4,4 @@ const String orderPath = 'api/orders'; const String authPath = 'api/login'; const String sitePath = 'api/sites'; const String getGoodsReceiptPath = '/api/site-manager/deliveries'; +const String markAsReceivedPath = '/api/site-manager/deliveries'; diff --git a/flutter_client/lib/screens/delivery_advices_list_screen.dart b/flutter_client/lib/screens/delivery_advices_list_screen.dart index bd45483..e33b13a 100644 --- a/flutter_client/lib/screens/delivery_advices_list_screen.dart +++ b/flutter_client/lib/screens/delivery_advices_list_screen.dart @@ -3,7 +3,7 @@ import 'package:flutter_client/blocs/goodReceipts/goods_receipt_bloc.dart'; import 'package:flutter_client/constants.dart'; import 'package:flutter/material.dart'; import 'package:flutter_client/models/goods_receipt.dart'; -import 'package:flutter_client/screens/delivery_confirmation.dart'; +import 'package:flutter_client/screens/delivery_confirmation_screen.dart'; import 'package:flutter_client/widgets/delivery_card.dart'; class Deliveryadvice extends StatefulWidget { @@ -24,22 +24,29 @@ class _DeliveryadviceState extends State { @override Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - return Scaffold( - appBar: AppBar( - title: const Text('Delivery Advices'), - ), - body: state is GoodsReceiptLoading || state is GoodsReceiptInitial - ? const Center( - child: CircularProgressIndicator(), - ) - : - // state is GoodsReceiptsLoaded - state is GoodsReceiptsLoaded - ? Padding( - padding: const EdgeInsets.all(25.0), - child: SingleChildScrollView( + return BlocListener( + listener: (context, state) { + if (state is GoodsReceiptMarkedAsReceived) { + BlocProvider.of(context).add( + const GetGoodsReceiptsEvent(), + ); + } + }, + child: BlocBuilder( + builder: (context, state) { + return Scaffold( + appBar: AppBar( + title: const Text('Delivery Advices'), + ), + body: state is GoodsReceiptLoading || state is GoodsReceiptInitial + ? const Center( + child: CircularProgressIndicator(), + ) + : + // state is GoodsReceiptsLoaded + state is GoodsReceiptsLoaded + ? Container( + padding: const EdgeInsets.all(25.0), child: ListView.separated( separatorBuilder: (context, index) => const SizedBox( height: 10, @@ -52,17 +59,17 @@ class _DeliveryadviceState extends State { ); }, ), - ), - ) - : state is GoodsReceiptError - ? const Center( - child: Text('Error'), - ) - : const Center( - child: Text('Error'), - ), - ); - }, + ) + : state is GoodsReceiptError + ? const Center( + child: Text('Error'), + ) + : const Center( + child: Text('Error'), + ), + ); + }, + ), ); } } diff --git a/flutter_client/lib/screens/delivery_confirmation.dart b/flutter_client/lib/screens/delivery_confirmation.dart deleted file mode 100644 index afe1c6b..0000000 --- a/flutter_client/lib/screens/delivery_confirmation.dart +++ /dev/null @@ -1,140 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_client/constants.dart'; - -class DeliveryConfirm extends StatefulWidget { - const DeliveryConfirm({super.key}); - - @override - State createState() => _DeliveryConfirmState(); -} - -class _DeliveryConfirmState extends State { - bool isChecked = false; - - - //check box - void _handleCheckbox(bool? value) { - setState(() { - isChecked = value ?? false; - }); -} - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Delivery confirmation'), - ), - body: Center( - child: Padding( - padding: const EdgeInsets.all(25.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Card( - // shape: const RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(10), - // ), - elevation: 8, - color: kSeedColor, - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Delivery Advice 1', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.white), - ), - ], - ), - ], - ), - ), - ), - ), - const SizedBox(height: 10), - Card( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.zero), - ), - elevation: 8, - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Tokiyo Super Cement - 50KG', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - Checkbox( - value: isChecked, - onChanged: _handleCheckbox, - ), - - ], - ), - // const SizedBox(height: 20), - // Text( - // 'Quantity', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith( - // fontSize: 12, - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox( - // child: Text( - // '50', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith( - // fontSize: 12, - // fontWeight: FontWeight.normal, - // ), - // ), - // ), - // Checkbox( - // value: isChecked, - // onChanged: _handleCheckbox, - // ), - ], - ), - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/flutter_client/lib/screens/delivery_confirmation_screen.dart b/flutter_client/lib/screens/delivery_confirmation_screen.dart new file mode 100644 index 0000000..13c5f81 --- /dev/null +++ b/flutter_client/lib/screens/delivery_confirmation_screen.dart @@ -0,0 +1,201 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_client/blocs/goodReceipts/goods_receipt_bloc.dart'; +import 'package:flutter_client/constants.dart'; +import 'package:flutter_client/models/goods_receipt.dart'; + +class DeliveryConfirm extends StatefulWidget { + final GoodsReceipt goodsReceipt; + const DeliveryConfirm({super.key, required this.goodsReceipt}); + + @override + State createState() => _DeliveryConfirmState(); +} + +class _DeliveryConfirmState extends State { + late List _isChecked; + @override + void initState() { + super.initState(); + if (widget.goodsReceipt.status == GoodsReceiptStatus.received) + _isChecked = List.filled(widget.goodsReceipt.items.length, true); + else + _isChecked = List.filled(widget.goodsReceipt.items.length, false); + } + + @override + Widget build(BuildContext context) { + return BlocListener( + listener: (context, state) { + // TODO: implement listener + if (state is GoodsReceiptMarkedAsReceived) { + Navigator.of(context).pop(); + } + }, + child: BlocBuilder( + builder: (context, state) { + return Scaffold( + appBar: AppBar( + title: const Text('Delivery confirmation'), + ), + body: Center( + child: Padding( + padding: const EdgeInsets.all(25.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Card( + // shape: const RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(10), + // ), + elevation: 8, + color: kSeedColor, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.goodsReceipt.goodsReceiptId, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ], + ), + ], + ), + ), + ), + ), + const SizedBox(height: 10), + ListView.separated( + separatorBuilder: (context, index) => const SizedBox( + height: 10, + ), + shrinkWrap: true, + itemCount: widget.goodsReceipt.items.length, + itemBuilder: (context, index) { + return Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.zero), + ), + elevation: 8, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + widget.goodsReceipt.items[index].item.title, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + const Spacer(), + Text( + 'Qty:', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 14, + fontWeight: FontWeight.w100, + ), + ), + Text( + widget.goodsReceipt.items[index].quantity + .toString(), + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + Checkbox( + value: _isChecked[index], + onChanged: (val) { + setState( + () { + _isChecked[index] = val ?? false; + }, + ); + }, + ), + ], + ), + ), + ), + ); + }, + ), + ], + ), + ), + ), + bottomNavigationBar: widget.goodsReceipt.status == + GoodsReceiptStatus.received + ? null + : Padding( + padding: const EdgeInsets.fromLTRB(25.0, 0, 25.0, 16.0), + child: SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + if (_isChecked.contains(false)) return; + if (state is GoodsReceiptMarkingAsReceived) return; + BlocProvider.of(context).add( + MarkAsReceivedEvent( + widget.goodsReceipt.goodsReceiptId, + ), + ); + }, + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + backgroundColor: _isChecked.contains(false) + ? Colors.grey[200] + : kSeedColor, + ), + child: state is GoodsReceiptMarkingAsReceived + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + color: Colors.white, + ), + ) + : Text('Confirm', + style: TextStyle( + color: _isChecked.contains(false) + ? Colors.black + : Colors.white, + )), + ), + ), + ), + ); + }, + ), + ); + } +} diff --git a/flutter_client/lib/widgets/delivery_card.dart b/flutter_client/lib/widgets/delivery_card.dart index f1488f5..fbdfe99 100644 --- a/flutter_client/lib/widgets/delivery_card.dart +++ b/flutter_client/lib/widgets/delivery_card.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_client/constants.dart'; import 'package:flutter_client/models/goods_receipt.dart'; -import 'package:flutter_client/screens/delivery_confirmation.dart'; +import 'package:flutter_client/screens/delivery_confirmation_screen.dart'; import 'package:intl/intl.dart'; class OrderButtonProperties { @@ -19,12 +19,6 @@ OrderButtonProperties getButtonProperties(String state) { case 'Completed': return OrderButtonProperties( kApprovedAndOrderCompletedColor, 'Completed'); - // case 'Pending': - // return OrderButtonProperties(partialyDelivered, 'Pending'); - // case 'placed': - // return OrderButtonProperties(placed, 'Placed'); - // case 'partially delivered': - // return OrderButtonProperties(partialyDelivered, 'Partially delivered'); default: return OrderButtonProperties(kDeclined, 'Not completed'); } @@ -42,7 +36,9 @@ class DeliveryAdviceCard extends StatelessWidget { onTap: () { Navigator.of(context).push( MaterialPageRoute( - builder: (context) => const DeliveryConfirm(), + builder: (context) => DeliveryConfirm( + goodsReceipt: goodsReceipt, + ), ), ); }, @@ -81,6 +77,13 @@ class DeliveryAdviceCard extends StatelessWidget { ], ), const SizedBox(height: 20), + Text( + 'Supplier: ', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.normal, + ), + ), Text( goodsReceipt.supplier.name, style: Theme.of(context).textTheme.bodyMedium!.copyWith( @@ -93,26 +96,21 @@ class DeliveryAdviceCard extends StatelessWidget { Row( children: [ Text( - 'Site Name: ${goodsReceipt.site}', + 'Site: ', style: Theme.of(context).textTheme.bodyMedium!.copyWith( fontSize: 12, fontWeight: FontWeight.normal, ), ), - const Spacer(), - Container( - decoration: BoxDecoration( - color: buttonProperties.color, - borderRadius: BorderRadius.circular(8), - ), - child: TextButton( - onPressed: null, - child: Text( - buttonProperties.text, - style: const TextStyle(color: Colors.white), - ), - ), + Text( + goodsReceipt.site.name, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + ), ), + const Spacer(), + _statusDisplay(context, goodsReceipt.status), ], ), ], @@ -122,4 +120,54 @@ class DeliveryAdviceCard extends StatelessWidget { ), ); } + + Container _statusDisplay(context, GoodsReceiptStatus status) { + switch (status) { + case GoodsReceiptStatus.pendingShipping: + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: kViewPendingColor.withOpacity(0.9), + ), + padding: const EdgeInsets.all(8), + child: Text( + 'Pending Confirmation', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ); + case GoodsReceiptStatus.received: + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: kApprovedAndOrderCompletedColor.withOpacity(0.2), + ), + padding: const EdgeInsets.all(8), + child: Text( + 'Received', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ); + default: + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: kViewPendingColor, + ), + child: Text( + 'Error', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + color: kDeclined, + ), + ), + ); + } + } } From 9172ecf4587b14d27677fdd52b48517e2a5aed4f Mon Sep 17 00:00:00 2001 From: Sandaru <87793405+IT21001352@users.noreply.github.com> Date: Sun, 29 Oct 2023 16:41:57 +0530 Subject: [PATCH 04/12] padding changes --- flutter_client/lib/screens/delivery_advices_list_screen.dart | 3 ++- flutter_client/lib/screens/delivery_confirmation_screen.dart | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/flutter_client/lib/screens/delivery_advices_list_screen.dart b/flutter_client/lib/screens/delivery_advices_list_screen.dart index e33b13a..492076f 100644 --- a/flutter_client/lib/screens/delivery_advices_list_screen.dart +++ b/flutter_client/lib/screens/delivery_advices_list_screen.dart @@ -46,7 +46,8 @@ class _DeliveryadviceState extends State { // state is GoodsReceiptsLoaded state is GoodsReceiptsLoaded ? Container( - padding: const EdgeInsets.all(25.0), + padding: + const EdgeInsets.fromLTRB(24.0, 8.0, 24.0, 8.0), child: ListView.separated( separatorBuilder: (context, index) => const SizedBox( height: 10, diff --git a/flutter_client/lib/screens/delivery_confirmation_screen.dart b/flutter_client/lib/screens/delivery_confirmation_screen.dart index 13c5f81..5737393 100644 --- a/flutter_client/lib/screens/delivery_confirmation_screen.dart +++ b/flutter_client/lib/screens/delivery_confirmation_screen.dart @@ -40,7 +40,7 @@ class _DeliveryConfirmState extends State { ), body: Center( child: Padding( - padding: const EdgeInsets.all(25.0), + padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, From 5a706fb6766c374f754d60d5ece957fbc137d1b0 Mon Sep 17 00:00:00 2001 From: shavindaL Date: Sun, 29 Oct 2023 16:52:18 +0530 Subject: [PATCH 05/12] display all orders --- flutter_client/lib/blocs/auth/auth_bloc.dart | 2 - flutter_client/lib/blocs/site/site_bloc.dart | 4 - .../lib/screens/delivery_details.dart | 8 +- flutter_client/lib/screens/done.dart | 13 +- flutter_client/lib/screens/home_screen.dart | 1 - .../lib/screens/my_order_details.dart | 176 ++++++------------ flutter_client/lib/screens/my_orders.dart | 10 +- .../lib/screens/my_orders_screen.dart | 1 + .../lib/screens/order_sucess_screen.dart | 8 +- flutter_client/lib/widgets/delivery_card.dart | 2 - .../lib/widgets/my_orders_card.dart | 20 +- .../widgets/order_details_product_card.dart | 62 ++++++ 12 files changed, 146 insertions(+), 161 deletions(-) create mode 100644 flutter_client/lib/widgets/order_details_product_card.dart diff --git a/flutter_client/lib/blocs/auth/auth_bloc.dart b/flutter_client/lib/blocs/auth/auth_bloc.dart index 8c2059d..f09f394 100644 --- a/flutter_client/lib/blocs/auth/auth_bloc.dart +++ b/flutter_client/lib/blocs/auth/auth_bloc.dart @@ -13,8 +13,6 @@ class AuthBloc extends Bloc { } void _loginEventHandeler(LoginEvent event, Emitter emit) async { - - print("wwwwwwwwwwwwwwwwwwwwwwwwwwwwewewewewewewewe"); emit(SigningIn()); AuthRepository authRepository = AuthRepository(); diff --git a/flutter_client/lib/blocs/site/site_bloc.dart b/flutter_client/lib/blocs/site/site_bloc.dart index 576fbf3..5234c03 100644 --- a/flutter_client/lib/blocs/site/site_bloc.dart +++ b/flutter_client/lib/blocs/site/site_bloc.dart @@ -1,5 +1,3 @@ -import 'dart:developer' as developer; - import 'package:bloc/bloc.dart'; import 'package:flutter_client/models/site.dart'; import 'package:flutter_client/repositiories/sites/sites_repository.dart'; @@ -18,10 +16,8 @@ class SiteBloc extends Bloc { void _onGetSiteEventHandler( GetSitesEvent event, Emitter emit) async { emit(SiteLoading()); - developer.log("Sites", name: 'site_bloc'); await _sitesRepository.getSites().then((sites) { - developer.log("Sites: ${sites.length}", name: 'site_bloc'); emit(SiteLoaded(sites)); }).catchError((error) { emit(SiteError(error.toString())); diff --git a/flutter_client/lib/screens/delivery_details.dart b/flutter_client/lib/screens/delivery_details.dart index 0971e29..8d6d03c 100644 --- a/flutter_client/lib/screens/delivery_details.dart +++ b/flutter_client/lib/screens/delivery_details.dart @@ -24,7 +24,6 @@ class _MyAppState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - /// Input field for site location ----------------------------------------->>>>>>>>>>>>>>>>>>>>>>>>>>>>> const Text("Select Site Location"), Container( @@ -40,8 +39,7 @@ class _MyAppState extends State { return DropdownMenuItem( value: item, child: Padding( - padding: const EdgeInsets.all( - 8.0), + padding: const EdgeInsets.all(8.0), child: Text(item), ), ); @@ -58,7 +56,7 @@ class _MyAppState extends State { ), )), const SizedBox(height: 20), - + // date picker input -------------------------------------------------------->>>>>>>>>>>>>> const Text("Expected Delivery Date"), @@ -87,7 +85,7 @@ class _MyAppState extends State { onTap: () { _selectDate(context); }, - child: Icon(Icons.calendar_today), + child: const Icon(Icons.calendar_today), ), ), ], diff --git a/flutter_client/lib/screens/done.dart b/flutter_client/lib/screens/done.dart index d6c3481..94b8bfc 100644 --- a/flutter_client/lib/screens/done.dart +++ b/flutter_client/lib/screens/done.dart @@ -9,29 +9,26 @@ class Done extends StatelessWidget { body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ Image.asset( - "images/successfully-done.gif", - height: 150, + "images/successfully-done.gif", + height: 150, ), - - Text( + const Text( "Success!", style: TextStyle( fontSize: 19, fontWeight: FontWeight.w700, ), ), - - Text( + const Text( "Order Created.", style: TextStyle( fontSize: 15, fontWeight: FontWeight.w400, ), ), - ], ), ), diff --git a/flutter_client/lib/screens/home_screen.dart b/flutter_client/lib/screens/home_screen.dart index d91e2a7..b7dc7a7 100644 --- a/flutter_client/lib/screens/home_screen.dart +++ b/flutter_client/lib/screens/home_screen.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_client/blocs/auth/auth_bloc.dart'; import 'package:flutter_client/screens/create_requisition_order_page.dart'; -import 'package:flutter_client/constants.dart'; import 'package:flutter_client/screens/my_orders_screen.dart'; import 'package:flutter_client/screens/delivery_advices_list_screen.dart'; diff --git a/flutter_client/lib/screens/my_order_details.dart b/flutter_client/lib/screens/my_order_details.dart index d2b2547..05643d8 100644 --- a/flutter_client/lib/screens/my_order_details.dart +++ b/flutter_client/lib/screens/my_order_details.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_client/constants.dart'; +import 'package:flutter_client/models/order.dart'; +import 'package:flutter_client/widgets/order_details_product_card.dart'; class MyOrderDetails extends StatefulWidget { - const MyOrderDetails({super.key}); + const MyOrderDetails({required this.order, super.key}); + final Order order; @override State createState() => _MyOrderDetailsState(); @@ -12,128 +15,63 @@ class _MyOrderDetailsState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text('Home'), - ), - body: Center( - child: Padding( - padding: const EdgeInsets.all(25.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Card( - // shape: const RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(10), - // ), - elevation: 8, - color: kSeedColor, - child: Container( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Order ID', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.white - ), - ), - ], - ), - - - ], - ), + appBar: AppBar( + title: const Text('Order Details'), + ), + body: Center( + child: Padding( + padding: const EdgeInsets.all(25.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), ), - ), - ), - - SizedBox(height: 10), - Card( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.zero), - ), - elevation: 8, - child: Container( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Create order', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - Spacer(), - Text( - 'Price', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - SizedBox(height: 20), - Text( - 'Quantity', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - Container( - child: Text( - '50', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.normal, - - - ), - ), - + elevation: 8, + color: kSeedColor, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.order.orderId!, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ], ), - - ], + ], + ), ), ), ), - ), - ], + const SizedBox(height: 10), + ListView.separated( + shrinkWrap: true, + itemBuilder: (context, index) => OrderDetailsProductCart( + orderProduct: widget.order.products[index], + ), + separatorBuilder: (context, index) => const SizedBox( + height: 10, + ), + itemCount: widget.order.products.length, + ), + ], + ), ), - ), - ) - ); + )); } -} \ No newline at end of file +} diff --git a/flutter_client/lib/screens/my_orders.dart b/flutter_client/lib/screens/my_orders.dart index d80cd07..b3b37d7 100644 --- a/flutter_client/lib/screens/my_orders.dart +++ b/flutter_client/lib/screens/my_orders.dart @@ -53,7 +53,7 @@ class MyOrders extends StatelessWidget { borderRadius: BorderRadius.all(Radius.zero), ), elevation: 8, - child: Container( + child: SizedBox( width: double.infinity, child: Padding( padding: const EdgeInsets.all(16.0), @@ -73,7 +73,7 @@ class MyOrders extends StatelessWidget { fontWeight: FontWeight.bold, ), ), - Spacer(), + const Spacer(), Text( 'Date', style: Theme.of(context) @@ -86,7 +86,7 @@ class MyOrders extends StatelessWidget { ), ], ), - SizedBox(height: 20), + const SizedBox(height: 20), Text( 'Supplier name', style: @@ -107,7 +107,7 @@ class MyOrders extends StatelessWidget { fontWeight: FontWeight.normal, ), ), - Spacer(), + const Spacer(), Container( decoration: BoxDecoration( color: buttonProperties.color, @@ -117,7 +117,7 @@ class MyOrders extends StatelessWidget { onPressed: null, child: Text( buttonProperties.text, - style: TextStyle(color: Colors.white), + style: const TextStyle(color: Colors.white), ), ), ), diff --git a/flutter_client/lib/screens/my_orders_screen.dart b/flutter_client/lib/screens/my_orders_screen.dart index 0eb1734..9d2d6b9 100644 --- a/flutter_client/lib/screens/my_orders_screen.dart +++ b/flutter_client/lib/screens/my_orders_screen.dart @@ -31,6 +31,7 @@ class _MyOrdersState extends State { ); } else if (state is OrdersRetrieved) { return ListView.separated( + shrinkWrap: true, padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, diff --git a/flutter_client/lib/screens/order_sucess_screen.dart b/flutter_client/lib/screens/order_sucess_screen.dart index 0274e7b..a06a1a2 100644 --- a/flutter_client/lib/screens/order_sucess_screen.dart +++ b/flutter_client/lib/screens/order_sucess_screen.dart @@ -7,7 +7,7 @@ class OrderSuccessScreen extends StatelessWidget { @override Widget build(BuildContext context) { - Timer(const Duration(seconds: 3), () { + Timer(const Duration(seconds: 6), () { Navigator.of(context).popUntil((route) => route.isFirst); }); return Scaffold( @@ -17,17 +17,17 @@ class OrderSuccessScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ Image.asset( - "images/successfully-done.gif", + "assets/images/successfully-done.gif", height: 150, ), - Text( + const Text( "Success!", style: TextStyle( fontSize: 19, fontWeight: FontWeight.w700, ), ), - Text( + const Text( "Order Created.", style: TextStyle( fontSize: 15, diff --git a/flutter_client/lib/widgets/delivery_card.dart b/flutter_client/lib/widgets/delivery_card.dart index f1488f5..9ba65cf 100644 --- a/flutter_client/lib/widgets/delivery_card.dart +++ b/flutter_client/lib/widgets/delivery_card.dart @@ -1,6 +1,4 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_client/constants.dart'; import 'package:flutter_client/models/goods_receipt.dart'; import 'package:flutter_client/screens/delivery_confirmation.dart'; diff --git a/flutter_client/lib/widgets/my_orders_card.dart b/flutter_client/lib/widgets/my_orders_card.dart index 2efbef8..65c22f0 100644 --- a/flutter_client/lib/widgets/my_orders_card.dart +++ b/flutter_client/lib/widgets/my_orders_card.dart @@ -15,16 +15,6 @@ class MyOrdersCard extends StatelessWidget { final Order order; @override Widget build(BuildContext context) { - void ontapHandler() { - () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const MyOrderDetails(), - ), - ); - }; - } - OrderButtonProperties getButtonProperties(String state) { switch (state) { case 'pending': @@ -46,7 +36,15 @@ class MyOrdersCard extends StatelessWidget { } return InkWell( - onTap: ontapHandler, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => MyOrderDetails( + order: order, + ), + ), + ); + }, child: Card( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.zero), diff --git a/flutter_client/lib/widgets/order_details_product_card.dart b/flutter_client/lib/widgets/order_details_product_card.dart new file mode 100644 index 0000000..791d946 --- /dev/null +++ b/flutter_client/lib/widgets/order_details_product_card.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_client/models/order_product.dart'; + +class OrderDetailsProductCart extends StatelessWidget { + const OrderDetailsProductCart({required this.orderProduct, super.key}); + final OrderProduct orderProduct; + + @override + Widget build(BuildContext context) { + return Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.zero), + ), + elevation: 8, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + orderProduct.title, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + const Spacer(), + Text( + "LKR ${orderProduct.price.toStringAsFixed(2)}", + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 20), + Text( + 'Quantity', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + Text( + orderProduct.quantity.toString(), + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 12, + fontWeight: FontWeight.normal, + ), + ), + ], + )), + ), + ); + } +} From 558fb5a655b60167ec26321ea47682fe6d0aa021 Mon Sep 17 00:00:00 2001 From: Sandaru <87793405+IT21001352@users.noreply.github.com> Date: Sun, 29 Oct 2023 17:22:26 +0530 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=AA=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screens/delivery_advices_list_screen.dart | 37 +++++++++++-------- flutter_client/lib/screens/home_screen.dart | 4 +- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/flutter_client/lib/screens/delivery_advices_list_screen.dart b/flutter_client/lib/screens/delivery_advices_list_screen.dart index 492076f..30ddf1b 100644 --- a/flutter_client/lib/screens/delivery_advices_list_screen.dart +++ b/flutter_client/lib/screens/delivery_advices_list_screen.dart @@ -45,22 +45,27 @@ class _DeliveryadviceState extends State { : // state is GoodsReceiptsLoaded state is GoodsReceiptsLoaded - ? Container( - padding: - const EdgeInsets.fromLTRB(24.0, 8.0, 24.0, 8.0), - child: ListView.separated( - separatorBuilder: (context, index) => const SizedBox( - height: 10, - ), - shrinkWrap: true, - itemCount: state.goodsReceipts.length, - itemBuilder: (context, index) { - return DeliveryAdviceCard( - goodsReceipt: state.goodsReceipts[index], - ); - }, - ), - ) + ? state.goodsReceipts.isNotEmpty + ? Container( + padding: + const EdgeInsets.fromLTRB(24.0, 8.0, 24.0, 8.0), + child: ListView.separated( + separatorBuilder: (context, index) => + const SizedBox( + height: 10, + ), + shrinkWrap: true, + itemCount: state.goodsReceipts.length, + itemBuilder: (context, index) { + return DeliveryAdviceCard( + goodsReceipt: state.goodsReceipts[index], + ); + }, + ), + ) + : const Center( + child: Text('No Delivery Advices'), + ) : state is GoodsReceiptError ? const Center( child: Text('Error'), diff --git a/flutter_client/lib/screens/home_screen.dart b/flutter_client/lib/screens/home_screen.dart index d91e2a7..b0d572d 100644 --- a/flutter_client/lib/screens/home_screen.dart +++ b/flutter_client/lib/screens/home_screen.dart @@ -144,7 +144,7 @@ class HomeScreen extends StatelessWidget { ), const SizedBox(height: 10), Text( - 'You can access all the orders you have taken.', + 'You can access all the orders you have requested.', style: Theme.of(context) .textTheme .bodyMedium! @@ -202,7 +202,7 @@ class HomeScreen extends StatelessWidget { ), const SizedBox(height: 10), Text( - 'You can indicate whether the delivery advice is completed or not.', + 'You can indicate whether a delivery advice is completed or not.', style: Theme.of(context) .textTheme .bodyMedium! From 3c18fd2f7bc5ad96c4257673f39066906183ef50 Mon Sep 17 00:00:00 2001 From: shavindaL Date: Sun, 29 Oct 2023 17:48:03 +0530 Subject: [PATCH 07/12] some ui changes --- flutter_client/lib/blocs/auth/auth_bloc.dart | 14 +- flutter_client/lib/blocs/auth/auth_event.dart | 4 + flutter_client/lib/blocs/auth/auth_state.dart | 10 + flutter_client/lib/models/order.dart | 3 + .../repositiories/auth/auth_repository.dart | 28 ++ .../repositiories/order/order_repository.dart | 1 - .../create_requisition_order_page.dart | 2 +- .../screens/delivery_advices_list_screen.dart | 10 +- .../screens/delivery_confirmation_screen.dart | 7 +- .../lib/screens/delivery_details_screen.dart | 2 +- flutter_client/lib/screens/home_screen.dart | 363 +++++++++--------- flutter_client/lib/screens/main_screen.dart | 4 +- .../lib/screens/my_order_details.dart | 7 +- flutter_client/lib/screens/my_orders.dart | 7 +- .../lib/screens/my_orders_screen.dart | 7 +- .../lib/screens/order_details_screen.dart | 7 +- .../lib/screens/select_product_screen.dart | 5 +- .../lib/screens/selected_products_screen.dart | 2 +- .../lib/widgets/my_orders_card.dart | 4 +- .../lib/widgets/supplier_details_card.dart | 4 +- 20 files changed, 297 insertions(+), 194 deletions(-) diff --git a/flutter_client/lib/blocs/auth/auth_bloc.dart b/flutter_client/lib/blocs/auth/auth_bloc.dart index f09f394..95b4c36 100644 --- a/flutter_client/lib/blocs/auth/auth_bloc.dart +++ b/flutter_client/lib/blocs/auth/auth_bloc.dart @@ -7,11 +7,24 @@ part 'auth_state.dart'; class AuthBloc extends Bloc { AuthBloc() : super(AuthInitial()) { + on(_getSiteManagerNameEventHandeler); on(_loginEventHandeler); on(_logoutEventHandeler); } } +void _getSiteManagerNameEventHandeler( + GetSiteManagerName event, Emitter emit) async { + emit(SigningIn()); + AuthRepository authRepository = AuthRepository(); + emit(SiteManagerNameLoading()); + await authRepository.siteManagerName.then((siteManagerName) { + emit(SiteManagerName(siteManagerName)); + }).catchError((onError) { + emit(SiteManagerNameLoadFailed()); + }); +} + void _loginEventHandeler(LoginEvent event, Emitter emit) async { emit(SigningIn()); AuthRepository authRepository = AuthRepository(); @@ -32,7 +45,6 @@ void _logoutEventHandeler(SignOut event, Emitter emit) async { AuthRepository authRepository = AuthRepository(); final isLoggedOut = await authRepository.logout(); if (isLoggedOut) { - // authRepository.isTokenAvailable(); emit(SignedOut()); emit(AuthInitial()); } else { diff --git a/flutter_client/lib/blocs/auth/auth_event.dart b/flutter_client/lib/blocs/auth/auth_event.dart index d9147cb..e5fd1d4 100644 --- a/flutter_client/lib/blocs/auth/auth_event.dart +++ b/flutter_client/lib/blocs/auth/auth_event.dart @@ -5,6 +5,10 @@ abstract class AuthEvent { const AuthEvent(); } +class GetSiteManagerName extends AuthEvent { + const GetSiteManagerName(); +} + class LoginEvent extends AuthEvent { final String username; final String password; diff --git a/flutter_client/lib/blocs/auth/auth_state.dart b/flutter_client/lib/blocs/auth/auth_state.dart index 01fc826..9386f3c 100644 --- a/flutter_client/lib/blocs/auth/auth_state.dart +++ b/flutter_client/lib/blocs/auth/auth_state.dart @@ -16,3 +16,13 @@ final class SigningOut extends AuthState {} final class SignedOut extends AuthState {} final class SignOutFailed extends AuthState {} + +final class SiteManagerName extends AuthState { + final String siteManagerName; + + SiteManagerName(this.siteManagerName); +} + +final class SiteManagerNameLoading extends AuthState {} + +final class SiteManagerNameLoadFailed extends AuthState {} diff --git a/flutter_client/lib/models/order.dart b/flutter_client/lib/models/order.dart index f15d3d8..ebdde4f 100644 --- a/flutter_client/lib/models/order.dart +++ b/flutter_client/lib/models/order.dart @@ -9,6 +9,7 @@ class Order { final List products; final String? status; final double? total; + final String? supplierName; Order({ required this.supplierId, @@ -19,11 +20,13 @@ class Order { this.status, required this.products, this.total, + this.supplierName, }); factory Order.fromJson(Map json) { return Order( supplierId: json['supplier']['_id'], + supplierName: json['supplier']['name'], orderId: json['orderId'], dateToBeDelivered: DateTime.now(), //DateTime.parse(json['dateToBeDelivered']), diff --git a/flutter_client/lib/repositiories/auth/auth_repository.dart b/flutter_client/lib/repositiories/auth/auth_repository.dart index 23add08..287a23a 100644 --- a/flutter_client/lib/repositiories/auth/auth_repository.dart +++ b/flutter_client/lib/repositiories/auth/auth_repository.dart @@ -38,6 +38,34 @@ class AuthRepository extends BaseAuthRepository { } } + Future get siteManagerName async { + final SharedPreferences sharedPreferences = + await SharedPreferences.getInstance(); + final token = sharedPreferences.getString('jwt'); + if (token == null) { + throw AuthException('Not logged in'); + } else { + try { + // Verify a token (SecretKey for HMAC & PublicKey for all the others) + final jwt = JWT.verify(token, SecretKey('secret')); + if (jwt.payload['role'] == 'siteManager') { + return jwt.payload['name']; + } else { + throw UnauthorizedException('Failed to login'); + } + } on JWTExpiredException catch (e) { + developer.log(e.message, name: "AuthRepository"); + throw TokenExpiredException(e.message); + } on JWTException catch (ex) { + developer.log(ex.message, name: "AuthRepository"); + throw AuthException(ex.message); // ex: invalid signature + } catch (e) { + developer.log(e.toString(), name: "AuthRepository"); + throw AuthException(e.toString()); + } + } + } + Future isTokenAvailable() async { final SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); diff --git a/flutter_client/lib/repositiories/order/order_repository.dart b/flutter_client/lib/repositiories/order/order_repository.dart index 24fdf01..f1fc6ee 100644 --- a/flutter_client/lib/repositiories/order/order_repository.dart +++ b/flutter_client/lib/repositiories/order/order_repository.dart @@ -96,7 +96,6 @@ class OrderRepository extends BaseOrderRepository { final responseBody = await http.get(orderURL, headers: headers); if (responseBody.statusCode == 200) { final List orders = jsonDecode(responseBody.body); - developer.log(orders[0]['items'].toString(), name: "OrderRepository"); return orders.map((order) => Order.fromJson(order)).toList(); } else { developer.log(responseBody.body, diff --git a/flutter_client/lib/screens/create_requisition_order_page.dart b/flutter_client/lib/screens/create_requisition_order_page.dart index 49cf3a1..30484f1 100644 --- a/flutter_client/lib/screens/create_requisition_order_page.dart +++ b/flutter_client/lib/screens/create_requisition_order_page.dart @@ -35,7 +35,7 @@ class _CreateRequisitionOrderState extends State { appBar: AppBar( title: Text( 'Create Requisition Order', - style: Theme.of(context).textTheme.titleMedium!.copyWith( + style: Theme.of(context).textTheme.titleLarge!.copyWith( fontWeight: FontWeight.w900, ), ), diff --git a/flutter_client/lib/screens/delivery_advices_list_screen.dart b/flutter_client/lib/screens/delivery_advices_list_screen.dart index 492076f..19ceda9 100644 --- a/flutter_client/lib/screens/delivery_advices_list_screen.dart +++ b/flutter_client/lib/screens/delivery_advices_list_screen.dart @@ -1,9 +1,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_client/blocs/goodReceipts/goods_receipt_bloc.dart'; -import 'package:flutter_client/constants.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_client/models/goods_receipt.dart'; -import 'package:flutter_client/screens/delivery_confirmation_screen.dart'; import 'package:flutter_client/widgets/delivery_card.dart'; class Deliveryadvice extends StatefulWidget { @@ -36,7 +33,12 @@ class _DeliveryadviceState extends State { builder: (context, state) { return Scaffold( appBar: AppBar( - title: const Text('Delivery Advices'), + title: Text( + 'Delivery Advices', + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.w900, + ), + ), ), body: state is GoodsReceiptLoading || state is GoodsReceiptInitial ? const Center( diff --git a/flutter_client/lib/screens/delivery_confirmation_screen.dart b/flutter_client/lib/screens/delivery_confirmation_screen.dart index 5737393..6d08f05 100644 --- a/flutter_client/lib/screens/delivery_confirmation_screen.dart +++ b/flutter_client/lib/screens/delivery_confirmation_screen.dart @@ -36,7 +36,12 @@ class _DeliveryConfirmState extends State { builder: (context, state) { return Scaffold( appBar: AppBar( - title: const Text('Delivery confirmation'), + title: Text( + 'Delivery confirmation', + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.w900, + ), + ), ), body: Center( child: Padding( diff --git a/flutter_client/lib/screens/delivery_details_screen.dart b/flutter_client/lib/screens/delivery_details_screen.dart index 77c7981..a4a4161 100644 --- a/flutter_client/lib/screens/delivery_details_screen.dart +++ b/flutter_client/lib/screens/delivery_details_screen.dart @@ -54,7 +54,7 @@ class _DeliveryDetailsScreenState extends State { appBar: AppBar( title: Text( "Delivery Details", - style: Theme.of(context).textTheme.titleMedium!.copyWith( + style: Theme.of(context).textTheme.titleLarge!.copyWith( fontWeight: FontWeight.w900, ), ), diff --git a/flutter_client/lib/screens/home_screen.dart b/flutter_client/lib/screens/home_screen.dart index b7dc7a7..108fa09 100644 --- a/flutter_client/lib/screens/home_screen.dart +++ b/flutter_client/lib/screens/home_screen.dart @@ -10,9 +10,16 @@ class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { + BlocProvider.of(context).add(const GetSiteManagerName()); return Scaffold( appBar: AppBar( - title: const Text('Home'), + title: Text( + 'Home', + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontSize: 24, + fontWeight: FontWeight.w900, + ), + ), actions: [ IconButton( onPressed: () { @@ -33,192 +40,202 @@ class HomeScreen extends StatelessWidget { }, ), ), - body: Center( - child: Padding( - padding: const EdgeInsets.all(25.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Hi, Supun", - style: TextStyle(fontSize: 24), - ), - const SizedBox(height: 15), - InkWell( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const CreateRequisitionOrder(), - ), - ); - }, - //Create Order Card - child: Card( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.zero), - ), - elevation: 8, - color: Theme.of(context).colorScheme.primary, - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon( - Icons.create_new_folder, - size: 24, - color: Colors.white, - ), - const SizedBox(height: 10), - Text( - 'Create order', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.white), + body: BlocBuilder( + builder: (context, state) { + return Center( + child: Padding( + padding: const EdgeInsets.all(25.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (state is SiteManagerNameLoading) + const CircularProgressIndicator() + else if (state is SiteManagerName) + Text( + state.siteManagerName, + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.w900, ), - const SizedBox(height: 10), - Text( - 'You can create orders from this.', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.white), + ), + const SizedBox(height: 15), + InkWell( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + const CreateRequisitionOrder(), + ), + ); + }, + //Create Order Card + child: Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.zero), + ), + elevation: 8, + color: Theme.of(context).colorScheme.primary, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + Icons.create_new_folder, + size: 24, + color: Colors.white, + ), + const SizedBox(height: 10), + Text( + 'Create order', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + const SizedBox(height: 10), + Text( + 'You can create orders from this.', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ], ), - ], + ), ), ), ), - ), - ), - InkWell( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return const MyOrders(); - }, - ), - ); - }, - //My Orders Card - child: Card( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.zero), - ), - elevation: 8, - color: Theme.of(context).colorScheme.primary, - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon( - Icons.view_agenda, - size: 24, - color: Color.fromARGB(255, 255, 255, 255), - ), - const SizedBox(height: 10), - Text( - 'My orders', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - const SizedBox(height: 10), - Text( - 'You can access all the orders you have taken.', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.white, - ), + InkWell( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) { + return const MyOrders(); + }, + ), + ); + }, + //My Orders Card + child: Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.zero), + ), + elevation: 8, + color: Theme.of(context).colorScheme.primary, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + Icons.view_agenda, + size: 24, + color: Color.fromARGB(255, 255, 255, 255), + ), + const SizedBox(height: 10), + Text( + 'My orders', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + const SizedBox(height: 10), + Text( + 'You can access all the orders you have taken.', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], ), - ], + ), ), ), ), - ), - ), - InkWell( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return const Deliveryadvice(); - }, - ), - ); - }, - //Dummy Card - child: Card( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.zero), - ), - elevation: 8, - color: Theme.of(context).colorScheme.primary, - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon( - Icons.delivery_dining, - size: 24, - color: Color.fromARGB(255, 255, 255, 255), - ), - const SizedBox(height: 10), - Text( - 'Delivery advice', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.white), - ), - const SizedBox(height: 10), - Text( - 'You can indicate whether the delivery advice is completed or not.', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.white), + InkWell( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) { + return const Deliveryadvice(); + }, + ), + ); + }, + //Dummy Card + child: Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.zero), + ), + elevation: 8, + color: Theme.of(context).colorScheme.primary, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + Icons.delivery_dining, + size: 24, + color: Color.fromARGB(255, 255, 255, 255), + ), + const SizedBox(height: 10), + Text( + 'Delivery advice', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + const SizedBox(height: 10), + Text( + 'You can indicate whether the delivery advice is completed or not.', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ], ), - ], + ), ), ), ), - ), + ], ), - ], - ), - ), + ), + ); + }, )); } } diff --git a/flutter_client/lib/screens/main_screen.dart b/flutter_client/lib/screens/main_screen.dart index 6b9ab8b..f8aa2d4 100644 --- a/flutter_client/lib/screens/main_screen.dart +++ b/flutter_client/lib/screens/main_screen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_client/screens/create_requisition_order_page.dart'; import 'package:flutter_client/screens/home_screen.dart'; +import 'package:flutter_client/screens/my_orders_screen.dart'; class MainScreen extends StatefulWidget { const MainScreen({super.key}); @@ -13,7 +13,7 @@ class _MainScreenState extends State { int _currentIndex = 0; final _pages = [ const HomeScreen(), - const CreateRequisitionOrder(), + const MyOrders(), const HomeScreen(), ]; diff --git a/flutter_client/lib/screens/my_order_details.dart b/flutter_client/lib/screens/my_order_details.dart index 05643d8..945ad0a 100644 --- a/flutter_client/lib/screens/my_order_details.dart +++ b/flutter_client/lib/screens/my_order_details.dart @@ -16,7 +16,12 @@ class _MyOrderDetailsState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Order Details'), + title: Text( + 'Order Details', + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.w900, + ), + ), ), body: Center( child: Padding( diff --git a/flutter_client/lib/screens/my_orders.dart b/flutter_client/lib/screens/my_orders.dart index b3b37d7..9b606dd 100644 --- a/flutter_client/lib/screens/my_orders.dart +++ b/flutter_client/lib/screens/my_orders.dart @@ -39,7 +39,12 @@ class MyOrders extends StatelessWidget { return Scaffold( appBar: AppBar( - title: const Text('My orders'), + title: Text( + 'My orders', + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.w900, + ), + ), ), body: Center( child: Padding( diff --git a/flutter_client/lib/screens/my_orders_screen.dart b/flutter_client/lib/screens/my_orders_screen.dart index 9d2d6b9..3d928a1 100644 --- a/flutter_client/lib/screens/my_orders_screen.dart +++ b/flutter_client/lib/screens/my_orders_screen.dart @@ -21,7 +21,12 @@ class _MyOrdersState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('My orders'), + title: Text( + 'My orders', + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.w900, + ), + ), ), body: BlocBuilder( builder: (context, state) { diff --git a/flutter_client/lib/screens/order_details_screen.dart b/flutter_client/lib/screens/order_details_screen.dart index 248edc6..2d53080 100644 --- a/flutter_client/lib/screens/order_details_screen.dart +++ b/flutter_client/lib/screens/order_details_screen.dart @@ -13,7 +13,12 @@ class _MyOrderDetailsState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Order details'), + title: Text( + 'Order details', + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.w900, + ), + ), ), body: Center( child: Padding( diff --git a/flutter_client/lib/screens/select_product_screen.dart b/flutter_client/lib/screens/select_product_screen.dart index 2841639..2c18583 100644 --- a/flutter_client/lib/screens/select_product_screen.dart +++ b/flutter_client/lib/screens/select_product_screen.dart @@ -33,8 +33,11 @@ class _SelectProductScreenState extends State { }, child: Scaffold( appBar: AppBar( - title: const Text( + title: Text( 'Select Product', + style: Theme.of(context).textTheme.titleLarge!.copyWith( + fontWeight: FontWeight.w900, + ), ), ), body: SingleChildScrollView( diff --git a/flutter_client/lib/screens/selected_products_screen.dart b/flutter_client/lib/screens/selected_products_screen.dart index fff80f0..416b9ef 100644 --- a/flutter_client/lib/screens/selected_products_screen.dart +++ b/flutter_client/lib/screens/selected_products_screen.dart @@ -61,7 +61,7 @@ class _SupplierProductsScreenState extends State { appBar: AppBar( title: Text( 'Products', - style: Theme.of(context).textTheme.titleMedium!.copyWith( + style: Theme.of(context).textTheme.titleLarge!.copyWith( fontWeight: FontWeight.w900, ), ), diff --git a/flutter_client/lib/widgets/my_orders_card.dart b/flutter_client/lib/widgets/my_orders_card.dart index 65c22f0..3d95d1a 100644 --- a/flutter_client/lib/widgets/my_orders_card.dart +++ b/flutter_client/lib/widgets/my_orders_card.dart @@ -47,7 +47,7 @@ class MyOrdersCard extends StatelessWidget { }, child: Card( shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.zero), + borderRadius: BorderRadius.all(Radius.circular(8)), ), elevation: 8, child: SizedBox( @@ -79,7 +79,7 @@ class MyOrdersCard extends StatelessWidget { ), const SizedBox(height: 20), Text( - order.supplierId, + order.supplierName!, style: Theme.of(context).textTheme.bodyMedium!.copyWith( fontSize: 12, fontWeight: FontWeight.bold, diff --git a/flutter_client/lib/widgets/supplier_details_card.dart b/flutter_client/lib/widgets/supplier_details_card.dart index 36ff803..2fa1265 100644 --- a/flutter_client/lib/widgets/supplier_details_card.dart +++ b/flutter_client/lib/widgets/supplier_details_card.dart @@ -48,9 +48,9 @@ class SupplierDetailsCard extends StatelessWidget { size: 8.0, color: Colors.grey.shade500), const SizedBox(width: 4.0), Text( - product.title.length < 20 + product.title.length < 16 ? product.title - : "${product.title.substring(0, 20)} ...", + : "${product.title.substring(0, 16)} ...", style: Theme.of(context).textTheme.bodySmall!.copyWith( fontWeight: FontWeight.normal, From 16e363ae8202490d4ae2ac931ebe4381993337a4 Mon Sep 17 00:00:00 2001 From: shavindaL Date: Sun, 29 Oct 2023 18:02:06 +0530 Subject: [PATCH 08/12] some changes --- flutter_client/lib/procument_mobile_app.dart | 1 - .../order/base_order_repository.dart | 3 -- .../repositiories/order/order_repository.dart | 36 ------------------- 3 files changed, 40 deletions(-) diff --git a/flutter_client/lib/procument_mobile_app.dart b/flutter_client/lib/procument_mobile_app.dart index 77ed1a2..2429b3d 100644 --- a/flutter_client/lib/procument_mobile_app.dart +++ b/flutter_client/lib/procument_mobile_app.dart @@ -86,7 +86,6 @@ class _ProcumentMobileAppState extends State { textTheme: GoogleFonts.interTextTheme(), useMaterial3: true, ), - // home: _isTokenAvailable ? const HomeScreen() : const LoginScreen(), home: _isTokenAvailable ? const MainScreen() : const LoginScreen(), ), ); diff --git a/flutter_client/lib/repositiories/order/base_order_repository.dart b/flutter_client/lib/repositiories/order/base_order_repository.dart index 78a7282..7d02dc4 100644 --- a/flutter_client/lib/repositiories/order/base_order_repository.dart +++ b/flutter_client/lib/repositiories/order/base_order_repository.dart @@ -2,8 +2,5 @@ import 'package:flutter_client/models/order.dart'; abstract class BaseOrderRepository { Future> getOrders(); - Future getOrder(String id); Future createOrder(Order order); - Future updateOrder(Order order); - Future deleteOrder(String id); } diff --git a/flutter_client/lib/repositiories/order/order_repository.dart b/flutter_client/lib/repositiories/order/order_repository.dart index f1fc6ee..145afd4 100644 --- a/flutter_client/lib/repositiories/order/order_repository.dart +++ b/flutter_client/lib/repositiories/order/order_repository.dart @@ -56,30 +56,6 @@ class OrderRepository extends BaseOrderRepository { } } - @override - Future deleteOrder(String id) async { - return Order( - supplierId: '1', - orderId: '1', - dateToBeDelivered: DateTime.now(), - siteId: '1', - siteManagerId: '1', - products: [], - ); - } - - @override - Future getOrder(String id) async { - return Order( - supplierId: '1', - orderId: '1', - dateToBeDelivered: DateTime.now(), - siteId: '1', - siteManagerId: '1', - products: [], - ); - } - @override Future> getOrders() async { final Uri orderURL = Uri.https(hostName, orderPath); @@ -114,16 +90,4 @@ class OrderRepository extends BaseOrderRepository { throw Exception(e); } } - - @override - Future updateOrder(Order order) async { - return Order( - supplierId: '1', - orderId: '1', - dateToBeDelivered: DateTime.now(), - siteId: '1', - siteManagerId: '1', - products: [], - ); - } } From 471f52a32324f7db3f34e2cb5e009ca698abf512 Mon Sep 17 00:00:00 2001 From: Sandaru <87793405+IT21001352@users.noreply.github.com> Date: Sun, 29 Oct 2023 18:15:27 +0530 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=AA=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screens/delivery_confirmation_screen.dart | 1 - react_client/src/app/orders/page.tsx | 39 +------------------ .../components/atoms/OrderStatus/index.tsx | 15 +++++++ .../components/molecules/OrderView/index.tsx | 5 ++- 4 files changed, 21 insertions(+), 39 deletions(-) create mode 100644 react_client/src/components/atoms/OrderStatus/index.tsx diff --git a/flutter_client/lib/screens/delivery_confirmation_screen.dart b/flutter_client/lib/screens/delivery_confirmation_screen.dart index 5737393..cdccc3d 100644 --- a/flutter_client/lib/screens/delivery_confirmation_screen.dart +++ b/flutter_client/lib/screens/delivery_confirmation_screen.dart @@ -27,7 +27,6 @@ class _DeliveryConfirmState extends State { Widget build(BuildContext context) { return BlocListener( listener: (context, state) { - // TODO: implement listener if (state is GoodsReceiptMarkedAsReceived) { Navigator.of(context).pop(); } diff --git a/react_client/src/app/orders/page.tsx b/react_client/src/app/orders/page.tsx index 30e2b5d..e1e66dc 100644 --- a/react_client/src/app/orders/page.tsx +++ b/react_client/src/app/orders/page.tsx @@ -1,4 +1,5 @@ "use client"; +import OrderView from "@/components/molecules/OrderView"; // import AddOrder from "@/components/organisms/OrderAdd"; // import OrderEdit from "@/components/organisms/OrderEdit"; import { OrderManagementContext } from "@/context/OrderManagement/OrderManagementContext"; @@ -25,43 +26,7 @@ const Orders = () => { columns={columns} loading={loading} expandable={{ - expandedRowRender: (record) => ( -
- {record.items.map((item) => { - return ( -
- Item: {item.item.name} -{" "} - {item.item.description} - {item.priceAtOrderTime} x{" "} - {item.quantity} = {item.priceAtOrderTime * item.quantity} -
-
- ); - })}{" "} - Total: {record.total} -
- Supplier: {record.supplier.name} -{" "} - {record.supplier.email} -
- Site Manager: {record.siteManager.name} -{" "} - {record.siteManager.email} -
- Site: {record.site.name} - {record.site.address} -
- Comments: {record.comments ?? "-"} -
- Date To Be Delivered: {record.dateToBeDelivered} -
- Status: {record.status} -
- Total: {record.total} -
- Created At:{" "} - {format(new Date(record.createdAt), "dd/MM/yyyy HH:mm:ss")} -
- Updated At:{" "} - {format(new Date(record.updatedAt), "dd/MM/yyyy HH:mm:ss")} -
- ), + expandedRowRender: (record) => , }} /> diff --git a/react_client/src/components/atoms/OrderStatus/index.tsx b/react_client/src/components/atoms/OrderStatus/index.tsx new file mode 100644 index 0000000..6d5d6f1 --- /dev/null +++ b/react_client/src/components/atoms/OrderStatus/index.tsx @@ -0,0 +1,15 @@ +import { Tag } from "antd"; +import React from "react"; + +const OrderStatus = ({ status }: { status: IOrder["status"] }) => { + if (status === "pending") return Pending; + if (status === "approved") return Approved; + if (status === "declined") return Declined; + if (status === "placed") return Placed; + if (status === "partially-shipped") + return Partially Shipped; + if (status === "shipped") return Shipped; + return Completed; +}; + +export default OrderStatus; diff --git a/react_client/src/components/molecules/OrderView/index.tsx b/react_client/src/components/molecules/OrderView/index.tsx index 4d09893..d2abc75 100644 --- a/react_client/src/components/molecules/OrderView/index.tsx +++ b/react_client/src/components/molecules/OrderView/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import OrderItemTable from "../OrderItemsTable"; import { format } from "date-fns"; +import OrderStatus from "@/components/atoms/OrderStatus"; interface OrderViewProps { order: IOrder; @@ -17,7 +18,9 @@ const OrderView = ({ order: order }: OrderViewProps) => {
Status: - {order.status} + + +
Supplier: From da857dc1fca85c1431044cd383ed8067e936ef78 Mon Sep 17 00:00:00 2001 From: Sandaru <87793405+IT21001352@users.noreply.github.com> Date: Sun, 29 Oct 2023 18:17:42 +0530 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=AA=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flutter_client/lib/screens/home_screen.dart | 216 +------------------- 1 file changed, 1 insertion(+), 215 deletions(-) diff --git a/flutter_client/lib/screens/home_screen.dart b/flutter_client/lib/screens/home_screen.dart index 108fa09..f4a34ee 100644 --- a/flutter_client/lib/screens/home_screen.dart +++ b/flutter_client/lib/screens/home_screen.dart @@ -216,7 +216,7 @@ class HomeScreen extends StatelessWidget { ), const SizedBox(height: 10), Text( - 'You can indicate whether the delivery advice is completed or not.', + 'You can indicate whether a delivery advice is completed or not.', style: Theme.of(context) .textTheme .bodyMedium! @@ -239,217 +239,3 @@ class HomeScreen extends StatelessWidget { )); } } - -// appBar: AppBar( -// title: const Text('Home'), -// actions: [ -// IconButton( -// onPressed: () { -// BlocProvider.of(context).add(SignOut()); -// }, -// icon: const Icon(Icons.logout), -// ), -// IconButton( -// icon: const Icon(Icons.account_circle), -// onPressed: () {}, -// ), -// const SizedBox(width: 10), -// ], -// leading: IconButton( -// icon: const Icon(Icons.menu), -// onPressed: () { -// Scaffold.of(context).openDrawer(); -// }, -// ), -// ), - // body: Center( - // child: Padding( - // padding: const EdgeInsets.all(25.0), - // child: Column( - // mainAxisAlignment: MainAxisAlignment.start, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // const Text( - // "Hi, Supun", - // style: TextStyle(fontSize: 24), - // ), - // const SizedBox(height: 15), - // InkWell( - // onTap: () { - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => const CreateRequisitionOrder(), - // ), - // ); - // }, - // //Create Order Card - // child: Card( - // shape: const RoundedRectangleBorder( - // borderRadius: BorderRadius.all(Radius.zero), - // ), - // elevation: 8, - // color: Theme.of(context).colorScheme.primary, - // child: SizedBox( - // width: double.infinity, - // child: Padding( - // padding: const EdgeInsets.all(16.0), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // const Icon( - // Icons.create_new_folder, - // size: 24, - // color: Colors.white, - // ), - // const SizedBox(height: 10), - // Text( - // 'Create order', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith( - // fontSize: 16, - // fontWeight: FontWeight.bold, - // color: Colors.white), - // ), - // const SizedBox(height: 10), - // Text( - // 'You can create orders from this.', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith( - // fontSize: 12, - // fontWeight: FontWeight.bold, - // color: Colors.white), - // ), - // ], - // ), - // ), - // ), - // ), - // ), - // InkWell( - // onTap: () { - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) { - // return const MyOrders(); - // }, - // ), - // ); - // }, - // //My Orders Card - // child: Card( - // shape: const RoundedRectangleBorder( - // borderRadius: BorderRadius.all(Radius.zero), - // ), - // elevation: 8, - // color: Theme.of(context).colorScheme.primary, - // child: SizedBox( - // width: double.infinity, - // child: Padding( - // padding: const EdgeInsets.all(16.0), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // const Icon( - // Icons.view_agenda, - // size: 24, - // color: Color.fromARGB(255, 255, 255, 255), - // ), - // const SizedBox(height: 10), - // Text( - // 'My orders', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith( - // fontSize: 16, - // fontWeight: FontWeight.bold, - // color: Colors.white, - // ), - // ), - // const SizedBox(height: 10), - // Text( - // 'You can access all the orders you have taken.', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith( - // fontSize: 12, - // fontWeight: FontWeight.bold, - // color: Colors.white, - // ), - // ), - // ], - // ), - // ), - // ), - // ), - // ), - // InkWell( - - // onTap: () { - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) { - // return const Deliveryadvice(); - // }, - // ), - // ); - // }, - // //Dummy Card - // child: Card( - // shape: const RoundedRectangleBorder( - // borderRadius: BorderRadius.all(Radius.zero), - // ), - // elevation: 8, - // color: Theme.of(context).colorScheme.primary, - // child: SizedBox( - // width: double.infinity, - // child: Padding( - // padding: const EdgeInsets.all(16.0), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // const Icon( - // Icons.delivery_dining, - // size: 24, - // color: Color.fromARGB(255, 255, 255, 255), - // ), - // const SizedBox(height: 10), - // Text( - // 'Delivery advice', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith( - // fontSize: 16, - // fontWeight: FontWeight.bold, - // color: Colors.white), - // ), - // const SizedBox(height: 10), - // Text( - // 'You can indicate whether the delivery advice is completed or not.', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith( - // fontSize: 12, - // fontWeight: FontWeight.bold, - // color: Colors.white), - // ), - // ], - // ), - // ), - // ), - // ), - // ), - // ], - // ), - // ), - // )); - - - From cca0495b377eeef38d5f4ee4d58a0b037011470b Mon Sep 17 00:00:00 2001 From: shavindaL Date: Sun, 29 Oct 2023 18:52:14 +0530 Subject: [PATCH 11/12] some changes --- .../android/app/src/main/AndroidManifest.xml | 2 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 6046 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 3437 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 9687 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 19392 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 31676 bytes flutter_client/lib/procument_mobile_app.dart | 3 ++- 7 files changed, 3 insertions(+), 2 deletions(-) diff --git a/flutter_client/android/app/src/main/AndroidManifest.xml b/flutter_client/android/app/src/main/AndroidManifest.xml index bfb0ccc..9a93b93 100644 --- a/flutter_client/android/app/src/main/AndroidManifest.xml +++ b/flutter_client/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ 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 Y52eO(&?VZrmH+?%07*qoM6N<$g5c|?zW@LL literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/flutter_client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/flutter_client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..59706a14ed04ef498e086bc97976d1a61045cc60 100644 GIT binary patch literal 3437 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 diff --git a/flutter_client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/flutter_client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..933d7754187d8189030abe7eb5b40d0995d012db 100644 GIT binary patch literal 19392 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 LNkvXXu0mjf*R%bQ literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/flutter_client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/flutter_client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372eebdb28e45604e46eeda8dd24651419bc0..6c9acbdb825197de506d519e34c48408b9240eb0 100644 GIT binary patch literal 31676 zcmV)mK%T#eP)PyA07*naRCr$OeFvBo)%pH=X6E+0cl$1#1(x0vP^1V;uYx7mHI@WhOrq(@FUcl< zjnNo2u_O|EYym+*dR@8*t2F6lVX52uZ8LNJ&o^@qclNRi3#9)bVq4n7ci*}6uTP?egH?o^#d#z+6}j7x1Q|Y1wZ!U zW_I}0J?j3!0YCx30qBu0@w51TmRmIaxoHHxo)KV?+bS6UczaCz`PIm1-k+7D6Do?@ zgGntR+gxA>05}1zA7)|o035CZdZK$jLO6&`3-a;Io5z6}T0M^_0ie$zVW&fUkNx@U zdBdi=HjTg;Mt}rULPnMk119#swRdKrWol1W#oM5|tOb~q21#*(Aqa*N==uqS)uYVe zII4TyN1*a!*tzN?R=s-?dp1>qhXZiR0cZ&!NQxhMIRu=u9Rh?_V4UrmroT6hK%yN~B#*-QJe_CF`!mo+HPFcgP| z1TBPp`@#`}_<~=e=>|7a%!89U zL`QuF_4&SM({)WFQ0E9R=|lb$I9hR4?S*ilmt_Ya;WtFS&K-b2K!;)n?9QkrPqu=B z8ZgwLI_yWmff^L&moiN~3C8y`PtqaH#qv;m;xImYJ`XuLWM7EG7Ey<+|JO8iO(XEN zjR2EgEB}B4NnmITu=Ww3JqbPO?S?W`$EVjeRs|Sh&o!==Y1arcO+CiJcQJ4LKHYSsbUS7ze4$=NopUv>K4Mfw8znde#*uM&MAi)bJr$APkfk6R3CG=JR zkkCiJn4utXaGgU_8MrQkG1)X{Bl2sr1D*uH1u)GJ>Vw>a!_0wvy%b0A*{6H4`rW+< zR2)Sp?ihB=ARvgN2?!07N$Ub7evVzVtTC7-Pn%_28JkwJ6%u!X$?<@c6!FT4z?Ibi zjtyX$ztif^$zJ9Xm|-9QWFQ;rkqvNq0XqXT|Em%>LiHkpxXBhc`)J3m`mw*q zuKrEJUuy?=t(;a}1)Mt|NzMxZKy4Mt@F8&yUE|;yi=aR;b_)`5SprB!a>kuRB35%J zW@CTZYApJ50cJc;+#|6IHARY}6IP#Ub9R{2KEp~)IoE5yRp&GIYEiWzY?3TNl4bfS z#s+BU3kv`kijna}03aJdr=S{H!;lR7fc|O#zyY{DI+F1fb6|zOr)C*u{$UH||NT&m zEkM71R}EvU9TuzZ(3qU-E-CI|ov((@@we_g#$GL~HWphF{@MVz5cS8h%?fX-P^Til zler-5ghW><9QcYIIGLk={KP^md1<{x;6)_*yJ`>ArQ=(7MH-iLSsdtE;b8dAt3!;v z9Vh^Y4P0|U*BpjXYYgv&$bX#+g;f`&Nt2+4$bgpMjpwja;OywQ1L+D9Lke`=G=wEdhoWdG^r%1{Mc==x3rU^h$fS?>SK#m>s3miM zr3ad3%DyC%!K#~{omy^DD>}{vB~}-zW~f*YcP=g71p)CRTJIob~JZQ=W67bN6Ooax=NQstwme znUEaqIJ6{aDra_g8RDELSP*-(FBfgW{J-r0V2!uX0&{kdeH)gQI^KavZ&p16uBS7g zo6gaj=xvenX#EiS;@9>1=EQPcG1MWKubO-93sI$if=wT-$Fe`?W5*2Q$K3V&LkF zLY@IUi~zu)hb4r95_~BdZ>HoTj73;6ZzboxI`iTL4`L77v166K z;`K$yTfYlml~(~fgo^py1pu<{?*XSL0X;_b!BrDSqB(l8YP3QHWcd9+u-asPO2U;N z@p4Kshoq=5DG_3IvZ_lB*)`08*HsyzAcHRjXr|<|0M_bDXU@a>KVOQ%yaEdagLWqq zG?&j&S755X=NI`AwN;)e*-1!m+Y({4L`_*UaNa^vlw`E*n#eN;CLzTg2ZneSKoWGM za-z1-L3@P)FdITpQNT+pa`}OE3$Xi(4cM{jFuqzuDyBG7jOgVwwihe~3~1#-t9Ta% z+|d)`9vzMh?;uuzPACsHLpW%Iu9|d*TDCC#E|YzrTe5x6Rrn)FA^>R;!XcA4lxVL( zHMa59@6W-EKmHE|`zTT^CWW%oXw|yhCaIwTEZX7d+$aDB-4}=P4|hcCHXWpZlu5bT zoS_30TMO9TJ~-l>u-R$sZP0a6XXqq)pm>YW z|HU=u;!?d}0le5Zh)&F)yV_v%gIA$-`ZcT^9TBK%248wI;!+(@Bpb+4Ngf+85<)w) zaKw!nahuixh#{a2@eoD%L|T}`;bw5jKy^5uZD0C{zWViP*!byJmO;8)0dTf?7RG(_ zdt#yw2^k3(et%nBdw)l%nX^4Y=)kJbjx)693Q`c#0e>Zo#e)vRUtt`yvywZHoD6mZ z1G16dk=DF|Cm4lC1yQ9yjPUtwG74xDQQ<07U z(jXz7(_TT@*3}h2C};tIfg!rD1_m9R+Yk&$#@w`M!FeJMVPEMgeE6GpvFz0)ma+X# z=3-b^X$dKvJxFr;pvf+HnmaLUY7z!dN+*=y}3V}du z-(ov&004}MQXxt9$abwm*5~o6lh5JNt~oK2L@Lmw?hcJr2Sq(3W1X%e5=&|ey_b1- zQk!AIkFS&ZUO$qzXxRmFVm!F&GAeZFocLOHLnT$ifEt7myP>0&lR{9}IXM_OB#9w4 z1#rWUefb;tM}Pb`R=)XRjCy%K)QX18?Khe$7g~Kuk1^+?`>-C;#9!RQ`;D6nJKCY72F7knkNnX@8U~eeGv;kegnu8RXa$%{7wRZgo=*(gDtTnZ|ucMi{B6q3t=)3gMvL00DW8D4J}9)nf9BPZtG>I8((5 z2ZBKg-AibmxQ@r+HS8{0h)@1pf(0)M0ij6}{Oa>U+qvVj5w6J2mXMuY7Xgg~*4zOy zGaayZN<`28{n>y!?n7pW@lc_lr~;^|02Bp~jp@?Cp+RCgBpVS8t)3?9?qiORu7wP2 zIURQJFhfbvF}`cbEBG?!HEd9eB1O%tl#_4M0&~X6v+ASu3zOl8PVhnxdcid>>|Qqp z-{QrPo8!8L>ml#u(hrY}PN=BE2irpY3qC8~97f=28^ktH2A47O0n+yPP(w{Q=p zWABM2nE&T}nD?);$VK#=mm&b__w#43P~fPJ!x!6i%=k6MHDWz2X2iGWghX61wgbBK z8OmDqycO=aeo$4Q#&7ER6fie(D@?J**>?c*Oe$qVTYxOtpwlq(VqTs977pdTjUy}f zMd;_&G5t;fprOl~*ji0)&eW+4ga2$t>-1DqpgRi7u3@S^6pBL8WJ;`|F*kRBvwMU{ zsA&hX8G$!SqKQw~%k5ZmWKXaF5)=3bohUK{m z#F@^I9g{kCD|20q`GW-jSqi#4e7N?G78rO}OSD58boj8h(vQ_|?8B-Lb|aWyiDSpe zeG~PXP5xOIO!!?E%SarF3Jk!>V`<<_1(lv5=K`^IVfcTnDo+F6opx6)nXc=w4qs{| zZze5)AG5LY({)(!ry~*Kp}5y~764YGn0~fabFP1&r#$RMjlDH`PiT+cBYVJ&!K_TZ z78OPDkf>&mgN!xu^oY7YbqSS`Cw2+|@d@RSwH@rMP0RIJPtL*SPlY>_1dohH)796w zhX8(E--XZ%_oY>hvBo_Z2Hzf!F2mZROaH!7%bvZEh!oD@WTmLm4}HD`JJx=V9m@|Q zcP=qADf`V->n8oK4<`P6ENhoA92K|{1t$`qLxsal03Ze}6>B<=fFn^(ID;0Jp{g9d zlp3TB(S?ARgb=RyV=du$tbrW)yP*455>%lh@%x<6P!i@tV@yw`=1 zQ`;fYHj!2E+fjD1qXht};ghcW5XPYyT%#Q$At4AEhuH4TIr_)X{12ahup)9Pol72z zNU*1oM#8*JeS&Wt5Am!50Aisq@6f813nPEk7X7~0AIb3}nCch+&8V{~!RD#tQdKSr z3RYqL^v|(y+HREP3C638i9Z`4jecYtYu7GI526Q3N_<8J9c9j$D$u#OmaPM05*u}m zb^ySe7-R{`c2r`ezV5xH_~fY#IPw*#L1GMI;}VTJ$d}U1>H|PsV6eK^tUHBRDa`NB zt#cuz+eD_sPesT-5L|OW=Q21CgVD-u5a?n**8+gB>9daW>5x%~L;Ke96|cXIdCzi32ETTj;|2J8mwQq2+RJt z245}^l`v$CeDGRn)PrML`))&YUG9pC@_2Ba!KhDc0KOsiR9*5F1%Rdk?)WhCN{3PA z|6E`D?gGqxb`ehQC(e}sK<&81r6jS9{45OxK&XSLY0mh5*1SBz5f!LU^M_;gmnN!H}t=(4oah7RJ>ms%(!? zK!ai@PKp)*K;5oUbEhEVSpugJr@WU3i(W#(p|_DeOz5eiWV@geG&CL{-ZwVM#|nUR zA%h9>S+oTFbDOW0QaV1s756ykfmDQ41tCiP|Akgm@*4(m+1T`Op9KPyX^Bl%2@4 z0D#7qT-XgA*K-!UOXY%w0^m%~D|UmZFm@l4h)KWbj$T8DGKEb1@5EZ7b&$sRnu_}jE{}(_JtEG9b zxqKM&rNBSS%-JJQi>*j21~hr6I8kA|c>!4*JLRbzFhuR0G#%cTr8EEy#i6VeKKI^KXE z?_$}E{doRnT5W}!P6WlywrUHZt}7B-`zZ!YaUoEa2*%@~+I^69ufc%T7>A?>prQmG z`$=q=Bk~k#I}ASKqgf&Th(q}U4L_CJ7lLf7HauW@*o{!70%i}h#PnG@!;9FtVpl18#NTFhSA3-^3+5s8>1gkzT((82e8tq2wE?uN6#{Yn~A8-@gj#Pvg z5UkRSJYy!;v-=32wMrlW;!{g`3i}9^n2F^xw&0alihvwz4r^^M%;^s-b|?Y3`V(r1 zu29*tH7d$8z`_}j9IYgv88|#v~rf?1~*!>E2Zdi*M*+Rt>nRn;v4Qzn8Tw13z zh6-eTBddR&p+%2Y82iY5Y|!nuAt|mis&$~MREJDOxQw7?T^=D*MIx6SsX(5DavrBF zMR|BWR=>R-IZq$JzI_q?@2Q;Svl*{ekk-8mWFK^*W3zN{Efb~1-6UP>!WCyGfHnZ) zLBgYj3z@8J(^Gw`A!9XGt~rPo#|vZ8TrKDEAuNDjqPTd1p#mu`lIve_|_-ykQy!F^|?8u2W z`uNArfs!}BkA^ z-fJAQCqDp{4FPm!bg9yf)>MrE0J6a}lXGRW0ci;vxEmi}$Kj<|@a%ppcu_1a^fXNX zXox&n&WVlCy79d~O~A;9Z$Ns|09J+Os4lS^WH)mMs1E=nG~}|Q9Uy=>c`qxfSgkMn z_dOhO$b(`Y5B}?FsolUI@T9im;gFJ{N;0&N z*>*=}3MlhUvD@HteaZFE9Bf{*1WTUTjn9`A8`n>nVn_4w!&yfEN0HceENo0NGQZSN z2$F1zFrUwN;UWT^23@lu9O6)Hj5SNx1{XfncOPAfSx;@nvX?0!CU${ueaV#b9mx7{ z5yR1G<-%=`48YL)Mn>q!T=@Vr|YB1B()~9)p8wy?-E59Aj7oAA+jl1Vi^U0bnvfYabQ>XdG@I;E~Hw7Wj&P z{?RPtO#2YK*NWiL*#KbPndsa-f8fTTJDMR08K_1#R0lgVW^WJ1+9Dimjga4csw&U-_!xUOuf+U+>_^U9Cr*K=d9OawjlX$>54`0@cv%8U13;j{ zOc^!H%b)MOMbuMnk`8G@@%c`0XkW5jxy$uAPcOu#kGET<};jJt} z8JU?1va(Y#=8h{6hsmrI*Q2Z;#SnhQM*eXkX&Fv#%VDlQMj3TohutN^&VulVkFxwt zALv_`{s*(36xE~Y^JtQ+#j{R-w(GJ}aP4(n(Ya4=c+m<0WFUZ+j8Z!pnxO`6RF|45 zhICMVvsm>_0BB%3gQimjZN>1)(2h`6xPj-behph!eT1C1%zTBkcImj|?^jBrZWzNA zOu&(vj;JmM98Riy2UG@3Be;3WN}hlZaNy7?%zyesB;Uc*xjpIKrQ84VLq6=j8{tC> z6bBh<%5>PAQUn0>N#{Fvn(1aX0Kl2gR|#l&_-g%9{o|)*VC#aS?G9v~I~rw7IE$#$ai=&oqdWi)do4hKUjIO3sE<0eo&9WO#*AnZ5mAJIYCYz6>M z{mV@@w^1KPHvUd7PA2W)+VQusYtM9i8EN=OWVoB2YlHDqMlcDt;c(?(R7C)wNkBya zkQ@QDPM^z@@iy|0ti#M_sv{Y1Ch`(nb(L;@;%=Vx{p;bSl*pirnsN@CgEayGBD)!- zp4x$gc&hDG%C@ats?Yp?Z(`e`rIt7gseA)P!K$?fP+i*A zFo1~@WDaiZ4j_h_2AvqB4r67u**J^$y{9ugkDHh%=V4WWPS^LROp($3;pXU(HIOmf zjPj~62>HEG$gh6Zh;;0fN6lcPCz=MtrR4JjOvjOuS@`IwEm-_4d2%@Jc{2fH?-?L@ za2qcUT#rDd*No;e4O%D+#eR?__~z;yAL4uL%hP15+pzA^*q_|P`%an!H|v1%fQ&#T z8PAOY05dOx$|lM-hWL1Dh#ti5+#Ejdxqo5Z`?D?2(*%HX1in~-MKsaWDSkCQ9?iSm z!Mv@01PNV@#BNe=IHwBK^--jW6sH;`+lfmytgur`u>2#Em#s+#NO5=Do-$6$$*3tQs68v&ESRoLMOmk@t!O>8K75 zS7jup7qVuUr=P@ZO#jmc%*ZBwzX}3g&mVO|M&>x?Y%v--h}UnUf|E!=C39h)UJ+P> zo!eI6k*o7hOY)!cf1Rb?6CdVnuDl+0w1l53=lM0rHj1E&DY<~fi~2mPDkMdQ$7SB< z_`wZ)<3}%H%jW5pW`$PH)j5j7<#GB24B{DIu(oQ_cd8BjuDXSF8}$fM()*DG41a*a z@+62NvKedKQNbbApi`5;Q8)Tj-*Rrlo7lB$4Q4-m0y%Gy&ss!+%?>nHk5J$1JK%eN z9>K2cIRRk|!HKd2_-o928I8ar&JHpxDdEICtUHlvvX8z$|B*6u^;peHidO|OB%IXa}QV@j8__sF-5QhW!@>m|;n|=^4JXQ|0aso%_ zT}&M;ducZ*y~{7SBVjTmo&cRuGD`>&Ef%$FpPaXt=~@_)Btwy@XaNum?BpkRzJi@Q zKg0(Qh!W}|vL96l&-()}%?rOS0Gv(}9{I>*HtKK)CMb3*+U{aFF8$>FQFSSbYVKYBjwL)L=(sC^QdoGHMmVvUStN;KY07*naR8t%o z84iqmJOu;qPD5OL3aa2mGXyXKM`1%g7B3Fsx4#V`H<#X>27x$ECIH^87{nykuTWDx z9=a}@Il(*-smga=4}QA%aY~d|jIxxp5IKE$+!lNt1!e!kPg?Jdod2z-M0^tfFx7{C zlSWCC|L<4S4jBQP9EVDO7~vr4zLA!$r)7YhZJCO?Xo*cI;UPe-`~W$Uo#wFnJBODS^yxZ)Yj*T1YjaAJH^fs@5|@9wjN*REWwOF z^%c3{?76gaaYSc8aLR=GHc3ETS%2vR@Pj zX9$(DKzOHCw*P(P=f00u9*NQ-#B<#BHxCXTu%mfV05fJppD$KOo>%226XQ2rxSI&~dth;W82M zvpr@*CjD&psO#^i2dMhp&;!@~Y7DwwIgCN+gYwE|&}j#Vct=i8_cH-NG-8Ut5+N+X zR|1Bu{EJmf@p1NCe6?bmrF1$0fVOOtQ$xp<6DF~7kN+RhvJC~PyqY5v2tu(_X+iPs z=P?Gvsx*2YE6{=jsH5Djy@i_c*YH3_G@@%hkB-bt8&s7cFOOFKx>tWnB~9xzP?8ge zb2U5|y4DL}HNh-0W-R&_k`r9l9GUl{U6=q6ms*B+tYjtOCHkt@R%78`_TtD90amf= zoQ-yVKC*IAuQ`v&Z_x9K9D(R$5BWhmT=&=jbnG^asThXR@(xCg8WR9@O|Hq>q(l-@ zfk+MT#gTCDXS+5n*O&d{L*%?iK^t)pZGk>F3V>eYu49va@jLV!b~O|*P)~?ZAOOWq zG=~d$chf$hQjlbzJKSX~#q&R1$D7!kvjsVSQjuenG_9-ggs_jOTCId$DGY;tWyj## z+anIwva;Y9RF(CH&6WzuMr~_NB3`tR?u9(Jb@EJmMpsP$coHimH@5P^k{o^Io6E4| z*^QP)g{OPi8YBjn{z;8Bn6YmfJ75f1QZ7%( zz7chU(*&6mYNvy|Fomozf2F>C-hc4gW6LccZ19e20pN*%CM&WR&Nb)S_PJE1`MVqkkqvKdQrwIENSecdPqh^kCAXt$Mhcf}mDL%C5 z5Qly@C!%}rc3_l4?7te-rLAFe*kN--5?Q{Myp)JNV*r4|lNe-fei$bU*6Bx^0VIC1MUt&y2Jn$_SAoG2RrEu_QdAbLSCQZl73 z1CN86>5GeFng2QJM0Q23cd4{fXcvEzESUFAs+{g8m#nlRrc@6MCs&ZbrR8SBx7ZP5j0EyyvjdP|z|008{NU`m5l-J`F^?)|x#oxKNZ-lr-M=J5_sgFD;~W!0Ua20KZTEt4~;JtV0en3QDZ z9TT(J+wh&nWpy}`=N$^Nv6qRk~D_{Eni=O!}3JZmo?erK+V?WJBy5IRsenTGB z>NblK#Tc~J*nm_^qlwB#A6`-lA zwh@s&Yf<5b%td|YL;yfME5oHLgO-qrnnP^cqW|ja-k*kzvnfhVM-u?fbEF9f*1}N? zw?A=})OF;eyj9N|;E+5C&}F`e#T?{z~OZu~_b^cs-GB#c2x)fFZc!eE1n9=R8`1DJvk>C{4x zr<##fTFIS0z)mV2h35~J3(0$#aW;WB)HM`NB$LR)=y)(It z*RUyPC9+qBfNZg_2&X|402(+ervt#1+!D9^aS9u9-z1jk?!_y^38*QT3~H_kfZE2T z`8%mAijgDCHIBHHGC27rek^|(=D)lQ^PizCCSm+W?T>C#ytv~J?a{Xf#U5@%LDdih zYJ}&>EE#U9Xcu}20GN5q)HskDgm@ER=+*S}Rem5)6?r=WfQZINY*cDF8!Z@SJ>f#1 z?QGXa0YJUPTyBPR?_zGl2l!&ga?H*y#QGUlT13>QJKLQvgTH^>I{*zq?aFEC9nvuF zXCtM-cZ@}X`x;)Yw}rpLZm0=njsP98t1^j@St-sSp{3L?H+JLr$(8!N7Z%{tzpkTx zi59n}IZ0VrGRD80f}Y*7n2I}5ST!EO8V<#9y_yBM8V3N;sU}rOL~m_Q(?v?zZM6DR zK+lkQ%ML(hh!N_lRW$gUm>2QPF+n{S?Eo7%Fc;f4F2}sT?ZWyQnETIl*fRI15L5LA`8s6+>3MNkJ~TLD>IcGPOZ3ufb`tg2>*wtvO@ z*tGBiES)B((e!!3@YX?PPy+p~l$v*bgnQHPfXwY?iNKrDE`?0g@9p@srvFR1|p)04O%nM@fgMJ4=kJv(d6j92xRE zaw(syN8iNpebbPAoi&Mrh;gL1nl8~%4|J5SnD_|qeC_w)b&(sAN;Hz*O(h!X`OY^Y z96P6CRWxlG<8dQlTypWAPQVl6|4qz8ee!35R*(+uE{+6m6~cTM+ca;H{?Q+2;NTZT zI;4Zn{Z?g(eG>z3b(@(#|NI>fdf(LtKHSF2!?&WkG{FFXq=>qm^`}XaQ0v?dl{^-n zQkG(WO%H`%#7%B$qDKeq9<>3`s#8m8#E+)(!FPQh$?E?=b2ed---U1}vAHUZ!qXVEHP^s|mB(`EGP&>H1T<2k?NmAh|GAcdse%8kImTtpK*qOT*5A+kRO;O%EVpMxmapSM< zVq+h^4QWZ;P|Y2vDk8OnK-UBSV{JEjh?yQTkCT>}VwSggslM*Le`D?o2DLSEGy&io z0U%DVO_84T+jMm8cQ4Br^dREAZ4HM^AV5JG@{8Bk4%BqnX{z1mo9m5JSxfi-bOo>B zvu#`On_1-%pS3W&g;yyN*Z+Pp8}rBwEIqX^uR$uROQ>7TnMyRC=WAY;mzk;?l}@Lz zr`Uyt0IG^t^Zbqfz|%KT;V&xyzBS!rzR7K0)V4Pnh3UOK7;^pHZ1BAgp+)PSP#I8J zPTgb3b!gTUI-M3_HpS3&Gf&vz){x?v&%^i-U#?n@SuY*Mju~`+v8tOBo01ZT5swd* zvhEv$wA4Y|&pV^K)NQFyC#p+ameSiu4^4(}7>wBsS2Niz4%bGmm%o6D%31hvM?vit zyK6Mw(nt?*F>dos1Auk`azE1ND#-f5Eo|a1euxg81|SRtWu>O!sMzZ>Oicg~jev3q zY%UdX?zP;n&cPQ8S7PyVdn}cjqqYZuZQO%BrJ?s`@nq+4RPz3)EcO|dA?mMDdNJnX zVtytq7Bn{ws3DWzl$5faC*WliRepp$&y^rMn-&VOyEXyf9A`@;yhQU%ueo!gbi=Rj zM8|H|a+M{btkfO>fN3k#9T20*iTJEtD)YIw!XI9ue?Dh9X8!dH9LuFD%e8&fnVAlZ z{&j0)-9JD|z<6GaQ79`&GE^W+wkNf!KF`xRzT{OP}--En-3 zk6$^28IMr59nFm(5*pUSW&F30O1SpkYo!T~O-B1JL%FVGqM|I$XbNYR zN~xYVZFT{-~D@cz3 zpuQTV=lhva~=VWg>FQc6CL!zVaVJs&HkZNoc{pR}ZTek<~XzeyD+Hcwc_xJP?Q zqkb}+x9>0vL0pCM(zM79Ktfbko^VXi#>H8Jr+|mBnQdOQM4$h{Tx?w^D7-EE{DnpLXLR-*B873gz)ZVTs%Xi^;TC7<97$AYdgC+*Rht&ovlOTVI5n#f z2PMkWH71*}*Igc5)&DlubKFmm+OmhC&Ke~eRpRW|*Tw#_mFV+$@CfNJ0)Y5rKb-s^ zJA7!RKKJjRV)08WBXyUoe61z`G;p9#_ZpB|GU9UP6p0j49-w}3kW&tY=h3d{4jBLEQfZ5W3Aa0(m!@K2E0d!PXgqeNqv66LA- zRAW&h8aO1E+-auc;nWV0Ohx2RBLC=Te94P5Fz4yH7S^qZ)zsIX>XLi8x*q78-T{Qy zAnKz0wo7^VFjMuH2G&03_c?vaA@;EM*f< zCZ9Ft026(Uks)>gLvv9t zHFrR+n*m9?Q--96;SU|;N56a>J2tk~Fr1l8ABdVuf zb7LQA(r+iTZhePw9bI`zc?#4pCxbcy0CCNQjO%57Emw^^28r2>nn9ASn6cnAy|nlh zJlxQSc4Avy(LTu`G1CVmO#IfR~lGjwFMd9b8VY zQF>WTXd^wW$@QT;VJbx6j;m&g&Np-w|H9Tk?Y2aOh3m8l0Ov69G+4C(&@8jNbn_GU zVbCp;xf9J%;&&M>fk-W3My_n^svHg4m;lfbmw1%f^`-iros0143!h=#>qL)^^-wSj zy0tlm{H&kU`HB&+Nn^ObvNMQ;DpTs>Ik!zZhu6NGPBjV!aOh!bs7<-eA=b?Cfv(|A ztjyhvr=P9@W(bd*P#Z7H!nqe~2M{TXrc|`<(LuWDPdD*_H;!WtQcL`)2vo92Q@Hv7 z5J{Ae#ASR*g>Yd5+p~L_KK<`G*!Z6vmS!2z6>89=I9&bfuIScxBy%b^B2?MO0Dxp; z&{-JlR1v7lNn#uOSxs8H*-#ts_`*nY&gUwoW9_of@Zl53ke4Ik0R#lW-MZ{(5f=*p z)?!&eW>zbC@?#@--$^6kM1NlHZ;xP=Y}W5FS{I2RnwaR?K^ywtxTFfnfgLtaU^w0b1eZ~xfTN=p&!QKc} zD~4JEiB=bq=X;-Ki zTN4204xl2=afJD`^?L4{Mfmh@%dl^QNI|9ZX?#UG>*cV+oqEQL1%TR#@>y95y8W~{ z`i&dNJn}8535`Rz$^n@GAc+K*x+_IU)Tsp=)w&FSSVwE`Zaz@`7v#z}(4vKCmO(~0 zO_JHim#Dr#PiZ%P%2$@(hVq~j@eaTtg`tB0aIwbaQW2gA=Snx5lQ_K`K353>*upo> zUVzz8e-cwEg2wl<%o4j;6KyR4Zn`m_Uy*=bS$!mq@AG4Un^95WgxyXR*1{2itQ!Dw zq$FaMs-QXuv`;z0M=7r$9@D@W+7bhH5n#Ub_rCSD`bx z2>^zANjm@mz$illpUaN`_OneN&({|``!05_qiTHOAoe2dwoOKG1D7!2m5DM6r+;O~ z$ZnmaVm!b<58i_lrCzulfYW9IfRbS9I%Mi43=V(ThMFMIDy4+?S6)LBUc-mEd67hU zx|Y78o{LvsZ3FjJ-wv!8t)`_{(xXEW`q%j~#VDv%f^QU1hq z=9iTvqS7^$tOu( zFhjUfqZ8!KOvSCg9V%trJsLiF5HD9VQB`U;YI)XQqx3SH-V1zO0|22AoL&cfE|XNg z>65v9?z2y0&)PMXyHg3^CIFnra0>vK9)uOsz0kYfDIaNb53l0gxJ_|Grg9N<7`;O4 z%M+%{W#}Oe*&Bc&t>nd_IoLFNC04$C5J%S6(VI6h9``(VrF8v0!+0D<;sn1EWd&5C zk*ZQq`4#h?-`#^$AOb+p0D#vaA)o`BW-sRRo_i8|*R5&-z=aD(ZA$HwDK1=b!*wiu z^v%ra?aNiEnc)pGh!92rtNH<8G^`5)Hg8CB+P>fw;U!Y;oE7TA7dPYZnzGZk=L{zv z`AY|kyNzm;PQYw?N+uR)16f?@`@r>@G;6b>*GIb2?q#X0w) zT3g39&03<({@Y6AZ4}Mk=pIo6{0HwgN7k)Z!6)Cy%GC*|Dou>2K=l>rZG>08Y;GZp zVAU{!+n|?GvYS(rg_shdkQJfCOsDljMo(5S|m=hmo zPMoeY!)533Ni5M(g=+mUR=oYOKI;!}qwok-GY~7k=-CoRw<&gHq%}vEtb17I;0F*N z-yGDq(k#)aLoz?~TX+az7nBn7I|USte|0L8Xjb1NHfUTT&@!%)Gkk&dYv$miKhDPX z<@+t;(i90kPazRrC@~=tZum_ihCO&CTDF+Lg7WpKENNo_KwWvl=CxE$NDZlQ`4l8L zG*sy&Y|VQg>9hXy3Qq2)pp5{4C$f{6`3R}qJQ#H2{cPyHkD_%(2LobeiAD~^_HEt) zY74(PfnqGFIk^HYEP>i6czr-x+#arBIX+*$7_VpoPh0M+O_<*Mn@!f|>f#|Ga?BpKh`k!2|$OaYWxM z34`yshfV(Vqv+VV2SSihR;n8w5F=6kTXn?5Q7pfTZuAE4)~J`H8qNFka0s%!3bKDA zFRfUNEekgw=Z)Q#++Z4@COY&5iiw~*YewnxTc@NU6_Z&39!6ndPh;_>T0v&%zIsZf zaO%()hRtOMQHW?IKfY@&|7zJkv46uFte+uVp`-%Q%!{ZnFyQtn?1ta{kagmKu4&jn+Kl0*C0FFRx3@5jUatlMPje4q9M{Q>b%5X2kvkoUUrPPy`7lQG;VV zfBWay`PmvATE8DhKP$qH9il*%6;w@uuydX!^8ykyT5V1C<_hkF6O-6+{1hh&1{eTv zI0XP`D>ywOY!uDaY1OhD3p_P|WT6~hcH&j+`C>W#eK++IrlWT7js7R=p0Uz|U)_ex zE(3WOtx#6#h^bL}Ipzt+syO0zQ`^^71-iyg^)I7}(89^=aA|PG9fl7FxE;GufW7$a z{ViDf-cHo)C_`SJVA;~>U6z?((UsslCAN_-BLI+KMpxze>Nr*<{S+m|ql_iWW~e~4 z>WFFtu~F=3i9_;SQ03=@gbmz=|6UyQmyx6pnx`x@R z=Fs0Qu1qc&rA-XoK4Sk1J)hd5**$<=sRRdoRltTS*ieBWO4+fzBK`1}`H<{~;E?vA z^kg1hxz{TEV%LuO%sR&?y7OFuT%k*4Qt3HFqP#iLcRkTh>OSF4q_rOno6?$xbg$9E zM^@^iL`2G*>o%i%3^kcaP2A7CSfuYOSc*A+--rdz9IIo+l9BabYm9tofYiRrNDg@f zsw-O?RNzY+0ClT4M$chd%ZVDI%7$)FtGxjRqiri-lfm3cHE^>dT*EQWaRg2rhX+Sc zh5~H3pTaIvH88l}R$^vEBF~h3%nES=qJ6@Xc77=$bf4-#bgi8qkwG-v9x~aP~ z?#B~(*MXy$BK71IHEB>uu#FzSb*UvZup>p!NdN#K07*naRA!<)`LAiCNJuya8`iV^ zdsgUk0b4ty#Q&Lt6)*3!06@4!8M3A(W6a~dklA50Q{~C1D(h^-6->`lU9pEo*z_9Z z7O^{kSdmHMi9$|a(GL6Xi_+ zaQJ+slBDhCd$+C7=RNl+*1l(@@QNTDN7ln0-13JEv`rsl)F>?}xdNI-mC@+Y&s3wd z0k765r_^3GO>r~VdaHobf1J|LWx(dtpeTNDJpeF2WEO;kO8B)>R&q2S6~_+h;oxED z$b&2SFti>Ak!@7RtLqSIU~RjhQC{!j-Q-f*0ct18cNm?DA3W7Zy1LIus2I(URP{ih z+N>Nc%PKgzc}~mSHT@Wr#Y8(md_sW9dLedwxm=(1#0SXzWU(b6CfunZOr2`O;8zpT z0i#(l9>(#a0Z?^v1=ip007 z3SdVeWE7wP#n`sA7<-l!A`mEnjzUQGVk~~P`V22-R49o2U8ptZS{OGr@cB)RW4)hq zDFHyRJw5SNl@SxFq(_$k?gAE;rCIHkkQo^7TMXc@e(8s9NM#iubB2P%zOU5h)zq7K>#2Ci9BIoR>@!%c0Z2tn(K^;2nt2i zcnGMsN_9ggzVXf@VL#PjL8hE()v$@oCLbzfMk%D_P=kf6y7BugG zBi!jy+5yC%3pXdjl*ba#s$UBFF_Bn%8rmuwV# zE-l{0_bht_JJ!B~rPInI7m$TZpA}7($)3|kO6&13ccx8-q$fa^h!3MeA~c;Es>U3% zy4;vlwZh~!aZ5suu|zN!Di4u3Xwi4Mfp}LjY$)X#N?=17bAxK47U4uqvA%2daU9=u z461q@updXqo+pq!>`ZD4jftRt2m|;`g3B=C?j-nG0+^l%o16lTr9k2?XvQ3r!0tE( zg&jc=iXw3s(|)-`yg`jQnT>!);}*2Uo9$4$b+aSBduQpIn;+%fM}Hr2F1ryb^H&5R z%L*7pyXrVNWyTPLR3cX(X*&5laQr{WKloq#bzENL3Yut9E6Dt>2@iLb`rmdpZ`Xe! z?8rb(*n^OtL$*nlRkJb2thS0{vN6p}EM1d~FQMiUC7b{d(oD#bchlo7L$W)M+i;kL zaY%RI2$FCV3@5PbLaWu2G}+5@R9+lm@SUz&y1&5hWFE zp@v&SQd&zA+H*+lsa7|5IKXs%NOvc0gPU!}$s_x)Wm++Ea;)j87u_Y=n3LI90H9Tf z2FY~2CAM!PO?dPtJnP>3kQ|?YY8|L52^j#8jF>=OhZ*rDz6&MEcoI+Yc;&w+34e%r zpKQYnqhMBS(>@?`U1*As`lUqWUIWf*PhQF^+`vQkIU7^=iz*qK`kv%O8{hGlabn z73`$U7P$3~!==G@j^-W=K&ihC0#(WxYLqrigrnPibj35=mlUlP3W12)(mHH632F3t z%y7e2A&g3Bs74&Bk%ls6LotpQp1`)R4zbeG!&)$S7%txt{B43Y`>ie=U(`OedUER5 z^T`%t6<+WvFPPJd&R2PmbzeNXcT9wYmMB98LTJepv<5?aBA6Q=YMRH@aN{fPz*ZDu zGd9jyhn4fTTU4Qo-f8kO0DvzEQ+|27Jm!&Gd1^uzUd0noQN*AqjMxzo0L1JBR8Emf zsi*`3AU?Gcscb3tV;+{zSc{p@AI6dOLLG<-Wy>zfnDm>gG2pfl%qtH=MX(zJRSv@# zHjDJqaW0ASRvq6|cZ8ZlY*T}g$>md#+DMg0I9z}?&WMdOa$5pNcnyxS5RU7uQGnh? z)V2ugc30q?_e!yMPbrvQiei-45wW#`fS%pz&ZKvu-LifF{N(*~RFt%Yt~ZCIG)HPi zbE!-JmPk)Z;6OYANCGivWh4Sf28-AbLb+BDg)ObQ0+7l<;lZxdXe6S z>;SPKFhOh35_H-Dq*ErL2x?Jf3Y$}hVk?v+g`3C{X!1P50ke<947BSbDSMF zJlYCZkGqCBFa;%naqw5#4V6SPYLwRHdbNIXj8R8agvg(b>5cg4jU<1?RCUOk%XttI z3qqEH;0U6oDuA-%r3h3MFoweb_OWX1pyt=|kdb->Kkis~2IL7t))c_#SN#TOW+uVO z0XrN}Bs==u<;2JbdM^(~+|wO{?;OTb z5=R;x8`JYCHZI=|t`A-}EA^C{_sV8p24ER52R zGQvzp0b~?%Hwu`BA{;3#(YG!tK>qe($S4NaPe6ARqAGY2%l=YgDcu+=0_I8_T@VCC zynas(B_Lr>GgKF)LXlGeM>0AMPC@q(DM+^`14u^zX#i3g>GwgTqPm)TxJ3X!F8>JG z&U_mBEb>v&>Q8QD#Q=cU$Sa=5Io`#l&o^NHPfuX|dSR%GOoX$=92!C7Yv1Bh1VBuB zU0)k+za;~M?;41dhQnW;VwNy806+sCo4jrcB_(_igVdA6;FCiruHL~{ygCCP zJ^5ewOGL9b8UqT7k$`KMx=F#LzL}DQhj?M|K2(=`V6*E+il7;NuB%9|(0IkRZ~F3y zP)B;cpb!|z<`DomJb>G!LBa`1Lms!|AmXrJ*Ki2icOAo$S59EZiYn-|D+B^?Cx)=k zRRiRl$&W8QTSCpb9N0J9XD`Rbicb&e?na|K8s}eLpl~il!Umd1lcBWS11f z>&XCz7dH2Rb1xY4!lGjN7**d%Nh0Cz3tkj7Wg;j>^%*{5mhip7Ej))kFYLf`4<5uj z+m$UK&Jst~=!Y)o1Ksc=pa9VD`R^BC$>-;yAaDcg;5Q-MTr3P=X#<=_0Za>lEFA#@ z=!l$PyZ-Qmz4>Q9$B8|a$w?t$p{zGj02%aota+T~3Eayg_C1J4@?=&h^-&Vjb^1DC z<=G*4BM9wO+5qi}B5F&xxEry^DOmA3W+f`&@s``cU^(JuCEnUzho9W6n63NU<(&fV zj3o@T&Pp+)G8SB*R~OF*{iG?%&&cH~kpTJ*4Qp z`zpY_zste23qGf1PPhk#Hi>h?fJqTyMkfIot&%>3JWWK%MMj|NXH1?Pv7hOHHvo93 z0X@25qn#qPaH9=Tbh48*ZK&FF$_}+QfhSHv^PWV|TZ_0|hacV1*FaB=%<0Kd8^GYr zDc0WQM{_g>b|ed$o{d0$CKlbAi;I`%BNv5;U;-i-#~8+ep%@Y5pu1gCq6m?8z#L7Z zJgWrgr_4xILZALq+8-3rrc>A*;K+2>@re00_HB9|TOQhs_un|~Sg>Ev}{B|7Iedc;UQs{MaQ-vkD}UI>B25#X5yr@A2s?mu$yz@pQUVW?u4HY41Ru{C4E*QQL_HH2IAJ||`MQasQ zBzQBh0?^zU_BeEeCnFM?0L?W)^ZJWXI;(`2Ov-}?888uqg$(Mn1|S0oOBbo}G8JkEih7PU34)pL5b=V>BxO?Q|(l z|A)B?Q*j4t!To4EHAg6b;Zhli0})syBg)(@j$x{o4`y!Uru_>Xef4FmUl~f8r^@x3 z#LDA+xarPS+Lia-fRd6WJc6m{Z1D&<(}$u_cy{`qM~!uWX$`Qg8g5zT@aL2xh$HBX zAIFQoYrvZib>Pq;l~JjH(@+e-^yl@jFkk*{5DRZDgkPVG_UL(thRc{?ltI%cK-0#7 zY2>?iW_Xe?%HZ4wFWi#QECqo$vV0*#aft8TxCzfZv;oIBN&l#wOwF{(A?|wokh?HGGc8Y`DD|ih?h34}OEgKf<(VW}h7S#!JQA|@5+|6Bh5=Satz+e8g0^1)|o(Oe(OJ%tEp9*pP zgVVKXSi`$iW3 zZM7hf)r!n`GdBE`PM*OGR@KplgiS%SffeAhzsiIwQH-uo31F5&Gm5m_33)hgX(1+# z%jG(<5ko!_$c2VHaAY8o0HPrY*%ZzfZ$xRPg!3u#-E+`5g?^|CAPr%$VF(+*Muy8m z*s5ahJiE!>^4-UAc;~y0NjN72yQ3KbrECB-OILmQa_x#Q+=eN$mV;v|@9GM`vWUWv z#?fD$aMBRthH%9ZwMuUA5NFti_uqaA8^6C7J0GV)c?BVq%Q7LV#1?!n7ZU@kSqz^< zdu%xpv4FtEs_KfE6Fq@0xQtqu{5a>l5<#s3UK~SxM;*5RtOd{iI)v_1COn=5GBZt- zmk*wLklc^cs;>qvJo(yRvT@<1rLZwYYwIY39V_F8Z!%n-68N(U;RytUKi=jp(PoOl zC8E!iB}?fTJ&bTl6x60a*ycW@zo`=dqH&2k!$zh%f{1;L?c2E7-uV3|Q2r`4GarLM z159VS0x(>7-8}7{087p`I)7xDHE$~puL+B^nS0D?)f-KXK^$jYeUwzUffcfN?{ zzWWmPJ>xXQ(nzy7!;h;MY9?;vvChkpkv|^6LIZB<&I${WSOnqbM%LYa5()db&3F~E zax37q%26As$NE|6ObTkKO3{=DT}5mMF@EP$#hMF|HWxhIZkR3?F1a}qSADGn=TDXj z(1EF(^Qq9-WY{PcX&iK731FupwxW8>7HyzpC!BQejXDX>baU(-7$gTlA|~SixxQw^ z@fP2=Wi$Tt;IlaPnsPQku)qrqE9X6~VNcd@(3gW1=4|?~3uV24j z!~U2|HtX!9gtJ27&YXT}9_C$Ngb9H>W}{GxpqSez;u?xz!h>)`!W^Xlqy$PlwIt5} z;0n-xB%E^#++r{jo}Nf>X~uB|Y_WI0wiSQ=_UkzCyo$!FIT>z=<&ch|!7e&eE&sp| z9>NXM6#!VUt{7{+HXj!(Sk0LJF?4m!gq>irpRj20=q%|=0$M?ppov|GPKxXxb%Q^_ z_P@N%e)3=b8;7>Pky3yn7tp8zVsc?APX>7f2;>&v@;eH#{F4DphKU%u@OE<-UiwKC z2cC%{YDNKX1WfPlza>-8h}F1MaEksgcp}?BZYn@w$v8cRNxZ9V5;&jAb$uMNiVBf8 zIR^o%-iHq+{K<%|Phk5*6e1f|;Ci*uC*@Tbxcx5waAcx?;im`Mb^^9ZF#x~J12UGwO0O^U4ZctjDX7>J`m+TjQ@C&^5-!C{`(;1CSOUVGR?(eg( z?27@E!eE%~)#Bcs?;{dOiqD>k87*x)Xa%IvOWUkRbA1XY_Ll!J8 zi0-aTFg*+Y%m5bNT7*S6m1;#O=248(x-p&u69vp6M{2kOVuz)VXmOlOOe2~|-5{(_ zQ3_IrbXTUr`a>C=bEj7)tEyX0DY~L!r1v2HCaP=jASRe75;)G=j&H`XgIn?5)??WG zBWJ~$dY8chfJ1rDVP7+v6~H+uGEr*XIt|x+Clk{rFJqnf3ToR|i3ScHL6#LuQm3cy zymG;aIhtt(bSkW;?uXXfyzS`s5!v!PtY6<>@JSpiy$E}UKE3@Z0Ac)rgIxFhu^2g? z@dzizqq}3AX1K<~@Z|IHvkNfcf?NcW5nC!gp+Xb}HxgW8d;xP*Bh8+dBOP2m3d@ftQ{8uO>a3^8tOFuGKrt(DAa}A4eDU0BKG7R|m(%YvX$2UdmikBhOUd9b$8gy4N zbXN{^mlv9#fl;|P$={QFpCdEp&bvAVH1)gO@skwm^loW#tm$3I%6yyq@jOnp?Z8Wq zypJayAmLXhq0{#|@}ubI2}9il&dJL;9;$M6q%eN(jcHnN@|QTv_yicT0L=}eLZJde z>L=E>PMGj0CCyQOy4<#H&vp#VbFHAkq;6(>hT8recv+ub_f*w8Bau z6ueQ8Kt*f^-pwYj@WR_2Ksez6XMT80FY?dN!0NllVZq9YS{5eqE=*?Kn8bBV0Yf$- zCeTe0+hj7T%r2!7S|TfxGGgT}pYF~aPQXfyAzkPtzo>JwmbJ{1dzD}g*VbC%_;YMiWJj{*G^H&z|DP@$H zmdj+sHjit_7jqIJ8k8=GlTNq=dd8Q8I0ELVu{xDNDaBAWuYq8W>Linbm8x!;$~OJk zy60t%ta_(gzgSqB&rc5ViJj_-CJT#!mhM~>23~}5rV}+2sO4M)Lz5< z8SmL{wj1@8Z)5!{l|YYeK<_{>Oa-jy)=oDj{oAP=eTQ}5BNH%tlEo81l^0}?MzSf{uDrN6om7MC9j8K zJz3UCc~Df;<8d`H8@1f#mCVnoZ9gi}idww-hkCs9{U)?GhhaoRsI5&AkPTtc&(w~{haPlH>S>=gf(AZ!xr9l6*Ap(5lRe20g~^`Br}63m`|p=P<^h)Uym%~J?_Sv zIMKcjFFkw&J05L-D;h?1^3ojP26(+}g)(X0R}4$zym zV8-Hcn6hAww(zE_c-g`w@EB!?TRDh!Gw23EAcZIUADhf@)CSb-%<|Uu0XV?qMzft@BFX0F9QiP7d|ZywwVJPxx!;JWnK;z-cpLmMa4`< zDT|;4CQ7)5OmS|6W5jkRo79Pvg&xEqvoa+!<3PnHLy?32+?aA61T%$A^eibCD!m7N zs4<~0gU;UsY(cr$3NKorp@p^E?Krxt$*$Ua3TCVsNYulV*8mslakRc^fca99Z>0o7 zdG`^$W;82+$_0`%iS#MBAOjz}^CHY#d>PB1vKsE-9B6hHxbA^v5f&y2!&E3}z^S7& zYQeoJaWxroZXbc1ZfIyj#BM|V(OTA0^PU~>zX6NAhV@IG23+4eKm3*p^<9$?icHis z*Cejl6T$f;&R7Y81z9MXnu)9|pUA|t5CEy0^y`B`B)R@p8Bnzy8y2KOBuqf#9pc=K22JCp`6n6c&1Cek9h8~71 z7(q-6qkMC^k6+E#Imi6z3pboe98pc|=jIAyr*eUoes%`detj9vo3(;jxD4$b6CIIY zy3XmD8Or;rozYHm+c=CpvlY5=hy{Z$+Zwi_{Kx_P{Y;g{oV;!waMx-Li*E~{AiD&e z)-;5=rfSS6;|8OM?KBQH9-R9n4^SUxhx{KYfln8dp^V{!Uz2*iq9>tyQW9ZQFj8>4 zmYIoaThl6#k#h_#`xvT^oy4B?t=Q0S>m;X-U%lTs^YjchL8DOtoE{B&cN?Xpe&o*1 z!_svNaM|CkLb2;o7RD?zw|hh&j3U9*)LAyo7|6ZmToidqFj&H!NP#iibipE~HZpgU z2428Zj|}YLI$p)`=x*%#Z6#ja*a0I(25K(G&&b7!+k&|8vMl&ffG$kXA{ftgOkg@D z0+_%FK+t{|?gC;-JFq7+6GUxJ5QlI+ft=ocez|hPS)=}-4k=#mp1`VC7zw`1D?8y( z9|ap7&=D5R@;E|h>*{1Rhw9OGvccx@IxxKk!QgS|p5s`*vV9Q266dO;&`4G8jXEV5 z&g6dZon~lvNYCbEn19`PTyot7+RRH=@ZyV>!Gr0D^L&KJKW<5qDe{R+1xVj<(v2>s zAt?<_Nk?vooErK+)M1h;y?pLCJg5P~QPyVewyO{9MD4*U@HnwZ%s^J*Os#D0IFwAx z*f zm%!~SgW<{r)2T?F+$G7~Pn2oOXGt2w{vgl?pRN8CzW3OLp)1}^zEV#S4DHcw3odUB z7(cspwU@RhVy{5&XAqopIbhfmy_PQFx!nL*?KMuF28kxZg7`z%^oHbbKrZerNKO;MR z;~CBv&)T)4Q32G^X^A#T3zwaTc^|u3n=s=RFihbc(F}y!X;HbT@RCr%DRs(i%7lB* zS@zfK>|>U|-cn$lCy4w$?V1ug$c@wGPQaUW7(UT}!VQK=Ffke7m@b<4(RG3+Q>7~O z$SEb^NngJ7P@SnSKOIJ-{!PL!Ada0}PnwhDdsD#5mj(DVD%wBAIZnZaCV0_^FxpUl zv;_yZoS+pI4!NT0#MoK&CHdGPx@$$RyZ? zy9>IDELkGQ3c$8~qRv1?YQ>!#Raeeaskf)+Og5hW6hID4Mr@5_Z!Y;%W#|fmu1pJF z7nL7Ya|>1QQd?A12!5hBH@D)YABRzUCnD7lZJ2qGvO3E=}A$LNT{9g(MuyXrHJWDIf8TSP);(5q$5D)Oi?N{!8vXv z5DV8K9;skFUTK@W5}vF|1l-5K+fL#$QwEB1s|`VV%#v#5`1z3&_WlHA1Q%ymdZ2<{ zsbn(3{(tk(GAx)&&3>*xP0K{#M)U7)`Pq6J5CyAiAb!ZBxbSoLCh^Q;XD}>3M=CkT`S(r3oDBWH<#){x153 z322k@swk0ECmUsD65F&}xG&qm(FV70X|}RXbm90rjds;LwJ<{s;JgmLjFT`zC-I}N z3>2_Z5GOt3bs(%i)bWkF>qe6TkZ(P;Ak&wfkH7i%b!@@nYr!!a^__lUYpSWh6#0=@?3MuW}J23wTF6ml-`dwx&RINioD$WSHerqjU*sgzJs z%0O>Vj)e5`6iC4^=bR2_e${g%gcJOuqUeMRS1-MnBIfOh*d`;{%%4qUuN^BEJt~{dzUFGb!*H znNf^_yAEfE8p+os1t7N?2`)qFd>vQS3lY;yHp*7Va&keF${=%E zEVztL_%dq1v?|utP=`|$^$4{$GL5xUJpi{+0LCVBPjDhir1EAY7m8@5eVP|ilql)xq7hnWD2#X8~jRv|C@O`BmK%HONU?k79Z zbS#X77LkWNhj8pzklojKURKb1}2Wbp4r|{ zA`+S*cV)qUON8}`y^RE)3N?tBmQo^OEFL)lf5uyOZpK!`@dn;_su`Ofve0rwdTg2k zCW<0D;&B6o7X+~8n^Uml`b*%)6|Bu%f>3L|D5@bFBelzanB(rp$mObG9?8Bu-IQ@F z$_|scIt-nRp@MT%Fw?BEHRA*_P!8%Sb9`?*UieiMZ*DN*c3Y^cleznU1p@p*7iTmn zfP@vFcqkXwe03g*jO$oCZa{0(1hM_OJhTlG^+|69P{Lxko1w9{81uelqx(gCDzNXg zlXK(xY%Klw#VE|Xn%VxVkm#NcT~yf1H06O)EKYmtzQUJmnAhV}OzHv&xl}r3U{ei% zY?_xyB+%I$L%6vMw%x=SD#2K#ZJNiyT_+IqRpKktYX^CmbPC4w6G#BAp$z7K>NV$D z0aOH5?YIU$^`8@P^#e<^VqC>raV46Yip1_s3cy%ANqs`XN!g#&xkaLt%-r{x9~TGC;xR4%I2?RrE{-^*E0{yT@2GChBaAZ+_%7fu-m5Z@V#A`q9vSHC^x16LlTscxk&l(6-|a4>mIy7yZWmucyVAALRf;f=3L?57wm7MEH9a4 zCc3ofA~;4TLvH>Ko{7iMg{^qu=k56U-2)e>JI7Kw-;c{~nTN&eR-UKbFlsGDR0M*QcD!U*E9u~?8ObA zTA*EV_mymX@iIHA%|)m+ODKTs%;GG1A*CVOJsX_0vdpYawk!TH*7=F+Q^G09CZULK zl^akQekwZ5amD8*;ktiVgtBQwg}xf?ZBvBMN~JrKLYv+r6>Wu_nHJ0v4WvQMJ4_BU z7Ka({(5%Es4je-;ztT2%IqGUEvE!G=u<^SCoo4BVc)I6iOvq0o$>$mZDUVLF>Z{a` z8}D4Mt^EA8C>gheCyW^gwfmtlCW^DAFiHWoZ7L*T(Csj@STz#e8||j@$MCJojwHuS z8k1^&nu0PKFj)htm0Q!q($8k%lmA|ZnFZIfE_?!wEwe;Gja-ltb`3NANkLO92WBGO+ZntF%>j-N;MFFGiG&N2t}4b^=h68g(G2pct6f zRnJX!fYrXY*?#-!r?BDwQfGDg(Abm$D4}rfnCe6@LG*EPy0lH|uSK3I>B%9OLr7bl)A=8-0PJm%5;pkF;{QOKTzwbJB#og;r zTDk}k6rrm{a?+$A5bd;v$ij5{Y!>t%LxR7?_P_X|wfToTu>V=r0Gp;_u->yYcG^89 zFF#@aCvgq4@C|gdt`x#6ArKiE11UgC=p^5eQZTs;O2r8N=tdNbHEW4@6?YlO>`Z?p zbX4H*foeSe?^Ss53B{MGzU55d8|Jc(T|U$q7+ngGn;XRPFW$&j-+MbsOBN!6Jao0l zB)60TP>zgCloxvZ7Rw3jM;zPO&Zl0np88*JqxulxWfje&UAs4}N@`}DCxkS@|Mm4{ zEWhlVa0k{vqc*65@HHk$s`{xqbG8>EWg&x>?rI|fO+;$DsgDdgTD#F))yld%nh}rH zz%Z)ptehHXRy7VEti`WBPXVrhKBUCXq(A3)oN#BTYd&_JV+KZ_0<8Gr&1}^@pFnBp z0@1L!i&A*{Q2^@L==NL43GC)^Y{KqmcHs99zK4^$DF=uILk7xDuK+35<{SQT5u3mE z0ZhK+dbqh;@Ny=iacBlHwJBJY+}kPdKS`}ZDGLO1yp$aZlUb+}33xu#^B7K{vZ@KY zpQ=aWv38hN8(e5cAfpZ4yct{nYcS!bXDL^vI#beJm}7?S2T;IJ-WcP5}toq+E%!RxQx3{>uIQ;F=1?<+Of^23v;-q($2A^}e< zo{ZSivxm|Z#ThaG0Lwl0)$|$opP>M8Y{dReJFwx$@1uM(by`=S;VZzJuYQfsz3yiC zPNx8(ov00s*pTfgV&P6iLoKip4a|;Lz?)fNXLzd+wW_i6=^Fg*E6(?Ft^=*XKzaAh zU4Kk^M_>jB4zxcm+9xf{`KHw+^DYDpE&@6Uzlgghf40)O4N9DNF~{7W~mRd?T>RDc3>wMfdo z{*7Q$%MHB4W7w?idU}WX)c<}LRR;-EDxSlwz+e#^d7TPRPM3r4^d6;S z`Z0_@f;u|76oBFYm*0CWTXpZPC@m&8XbHMnj6vL>7Rw48MZ(^}-rn|-_562V!`s`a z@wIbj9jNstjh%L0>1QW5=oYMD5qty9tyhRRfb2Y@+@N&5EXA};Cdwl-@@seooZ;nx*iVnk%jolA_Iq)%8BvE6ybEzIs$(mT?&Bl zKHPZc<=TqRtzqL!FSBFDc?h>>h{$T+R0!hr(V!#5Y&0Mddd6-!{7d}P%EQTdB7vj+ zxz6s4$*Adg4XCBvT<-ph*ZJ_dpUlLxg0-v@x1+x00?|i|*pXAI5TpP^;p{u`5s>6Fyydx8fb?uo4{rL_#oFpGtmY--mm`Xc(bbwW zKr)?9HPceOz-EoFXGWNBzIRm3j0bKaR zzs%59-+wtT&A1YsxEyWGRKwd}I<#zhrx+k|^4{c`cpRP{WN>IyBh{2@w?*>=UGT+5sMI`5u~&KY@);FzkIv z1IkHjlxL~G0+h44zGKfi%?zAt1xPQ5(edf;6=Ti)3$wpHIknu67ZJx6l<#{B|2V(=w5vbo+8oSUIvdmHEoa4ZSHR~jgXSuPY5GKY77^ac zQ$l)aY>TS3G`MtXw%3ieQ*ZLBoj=BpKK&Q0SfOM4c9mX{t^f+_pZ1l;E;ze0aIO^~ z-7~`QH$Tk8ntSJ<*jUTjunx^llarBFXGvtrC8_dp3?l-@E12ec)kf$!RMc+6`dKp3 zZJ^Ih|8kMGqnk8NITMtOnu{aDM_fIpSmnW2>{lOs z1ke9uTk;X~UaFzrP$Il%ceTf!)@KGrlLAPWA+-~|;OoBfw>{|Wmx(gTzir*}`| zF`*mPGjOgIKuu24JClsauKRxlIDhVqtZ>$S@C6ku3UzWJS`pV+iB5~& zU?b1V*a?PRC@-(Tu0OV+@kp2GY-lqLnwAB|^N>HeL|bt4Y<9t%i@1iFyv+;>)@f0s zE@)9G+M8saqxxe@M?A_zkxWTe6WrLt-#)wrzxnDmy!$*A;V1>5*g|g?>!=oizwVbC zEehZy#sa3T@nF`hYuJL@zl;epm%(M|Nn$Jxo%$C!6hH``h}cR#9m5@mKTr>_8rIoT zh5BR15pHc@jEA_*ywLbKa7^L;tnnzGUWDAD0@3a$643@A#-bhsmSA6wN2w=)hSIDf z+=Caezx;Xp{-1VZ&xQtv7!8(x^w%wIqj2=2NdbCOBhI^KnReYbB{ias!a=AJoztp{ zNk~VCE`qrH%NcM2jCaCDfDj9BRcgNe=iG6>u_iy_->fS$qy&F~j4{48T={n?rk6n0fXJE9P0KJW1 zniH}E?)df;Tr__r#p$5FnQx~{1ErV{JU?V64~eHb$^niN36hE#0eu0LjB&c*Y!?4sK_3tSH? zngh%Bi00U`MUwM7$}^#1eFz z(vodbNdd@69f-Ch+32p{xse?v<;NM3PIhP^1>id3F}HwTnFUR}z_S4%`~jOEJ%C3) zqiTXQ+q9~`Z z4?gx3Z<@-n%sOU3h$|lnp zS#9tcM_C-N+9&rvjW>_(#D?2cp3h*!TfsULaSD3rKz{MNJPXgG zDfTjUKCu@+{mfX@_uRfE0dp2F)bgjU;%@IH(2xg?99Zy!!6h7+bSjYNhMGHwKT^4o$RGJ;u$*Yv`!ngnKVIn0!MOv{NmJ#<2fc7K{(`aid)UoW6ZI zZn6jFT`>vsZn+TCCS1fkn9ib@i8v;64H-fKs1~d{1elgo0D>}Nk56-l_Vn9LDvH}f zk>e&7#QQve_w5)CpsMCwy#D8R@#y_TxtKD{Q`|#i3h-e{0Q-*9@q=m2uVO+>{l!3vAm<5qGG3*mSk7%0v9UgS;w6n1j-8g_fn;Y=nufy1| zVXVOAEDPt^c-%)t0i4|YDUzxGdOI6l-z+VZn2&JhEUp`qVYqVO&&@<2$AF<};7k|o ziBxZ{9t%U`qP~D4%9>_@BZg@BBx`Fp$TV}0l^c8ucTcZyEP`t0F%Zwt*;uc!XMD&r z@KIBMzBGY%JXnHgVhW<+34oRlZymTycjNR^R%)m!Q0hC*(Z;J7>X&xXm zh;Y;o=JFyd!-Yk6WMJv-naIxyB7zKrJBZ;*7xaof-PmCw9*e@|?}E?O0o&-p;kP>R z+QVVgZtp~Sd4FWKV|f2;Nab04#z#p3dcaHam%awFx?;t81E07n8>J;V2qPQq?LON7 zL7mriropD}>@ZGn}Ls-0?_+9d*6~P za$w{1W$r~Qa?sEe5ba4t&o8nG2oTu`Sn)8B-|Qf@N}p-!F-Ff+&lxLn897-zCwKn; Xnq$1aHL@co00000NkvXXu0mjfAgBZD literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/flutter_client/lib/procument_mobile_app.dart b/flutter_client/lib/procument_mobile_app.dart index 2429b3d..21f053b 100644 --- a/flutter_client/lib/procument_mobile_app.dart +++ b/flutter_client/lib/procument_mobile_app.dart @@ -39,7 +39,8 @@ class _ProcumentMobileAppState extends State { }); }).catchError((error) { developer.log( - error, + 'Error: ${error.toString()}', + error: error, name: 'procument_mobile_app.dart', stackTrace: error, ); From 740009a0f798b4ccd9efc05703f23a290338c7ee Mon Sep 17 00:00:00 2001 From: Sandaru <87793405+IT21001352@users.noreply.github.com> Date: Sun, 29 Oct 2023 19:09:45 +0530 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=AA=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react_client/src/app/orders/page.tsx | 3 ++- react_client/src/app/page.tsx | 5 +---- react_client/src/app/supplier/deliveries/page.tsx | 4 ++++ .../src/components/atoms/DeliveryStatus/index.tsx | 11 +++++++++++ .../src/components/atoms/OrderStatus/index.tsx | 4 ++-- .../src/components/molecules/HierarchyTable/index.tsx | 4 ++-- react_client/src/components/organisms/Sider/index.tsx | 7 ++++--- 7 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 react_client/src/components/atoms/DeliveryStatus/index.tsx diff --git a/react_client/src/app/orders/page.tsx b/react_client/src/app/orders/page.tsx index e1e66dc..f68fdae 100644 --- a/react_client/src/app/orders/page.tsx +++ b/react_client/src/app/orders/page.tsx @@ -1,4 +1,5 @@ "use client"; +import OrderStatus from "@/components/atoms/OrderStatus"; import OrderView from "@/components/molecules/OrderView"; // import AddOrder from "@/components/organisms/OrderAdd"; // import OrderEdit from "@/components/organisms/OrderEdit"; @@ -70,7 +71,7 @@ const columns = [ title: "Status", dataIndex: "status", key: "status", - render: (status: IOrder["status"]) => <>{status}, + render: (status: IOrder["status"]) => , }, // { // title: "Date To Be Delivered", diff --git a/react_client/src/app/page.tsx b/react_client/src/app/page.tsx index 9bfa167..5251f3e 100644 --- a/react_client/src/app/page.tsx +++ b/react_client/src/app/page.tsx @@ -9,10 +9,7 @@ export default function Home() { const { user } = useContext(AuthContext) as IAuthContext; return (

- {JSON.stringify(user)} - - - +

Welcome {user?.name}

); } diff --git a/react_client/src/app/supplier/deliveries/page.tsx b/react_client/src/app/supplier/deliveries/page.tsx index 56041fc..3f12fb7 100644 --- a/react_client/src/app/supplier/deliveries/page.tsx +++ b/react_client/src/app/supplier/deliveries/page.tsx @@ -1,4 +1,5 @@ "use client"; +import DeliveryStatus from "@/components/atoms/DeliveryStatus"; import OrderView from "@/components/organisms/OrderModal"; import { OrderDeliveryContext } from "@/context/OrderDelivery/OrderDeliveryContext"; import { OrderPlacementContext } from "@/context/OrderPlacement/OrderPlacementContext"; @@ -50,6 +51,9 @@ const Deliveries = () => { title: "Status", dataIndex: "status", key: "status", + render: (status: IGoodReceipt["status"]) => ( + + ), }, ]; return ( diff --git a/react_client/src/components/atoms/DeliveryStatus/index.tsx b/react_client/src/components/atoms/DeliveryStatus/index.tsx new file mode 100644 index 0000000..7940c18 --- /dev/null +++ b/react_client/src/components/atoms/DeliveryStatus/index.tsx @@ -0,0 +1,11 @@ +import { Tag } from "antd"; +import React from "react"; + +const DeliveryStatus = ({ status }: { status: IGoodReceipt["status"] }) => { + if (status === "pending-shipping") + return Shipping Pending; + + return Received; +}; + +export default DeliveryStatus; diff --git a/react_client/src/components/atoms/OrderStatus/index.tsx b/react_client/src/components/atoms/OrderStatus/index.tsx index 6d5d6f1..5eabc42 100644 --- a/react_client/src/components/atoms/OrderStatus/index.tsx +++ b/react_client/src/components/atoms/OrderStatus/index.tsx @@ -2,8 +2,8 @@ import { Tag } from "antd"; import React from "react"; const OrderStatus = ({ status }: { status: IOrder["status"] }) => { - if (status === "pending") return Pending; - if (status === "approved") return Approved; + if (status === "pending") return Pending; + if (status === "approved") return Approved; if (status === "declined") return Declined; if (status === "placed") return Placed; if (status === "partially-shipped") diff --git a/react_client/src/components/molecules/HierarchyTable/index.tsx b/react_client/src/components/molecules/HierarchyTable/index.tsx index f73c6bc..97c172d 100644 --- a/react_client/src/components/molecules/HierarchyTable/index.tsx +++ b/react_client/src/components/molecules/HierarchyTable/index.tsx @@ -14,12 +14,12 @@ interface DataType { const columns: ColumnsType = [ { title: "Hierarchy Id", dataIndex: "hierarchyId", key: "hierarchyId" }, { - title: "Lower Bound Price", + title: "Lower Bound Price (Rs.)", dataIndex: "lowerBoundPrice", key: "lowerBoundPrice", }, { - title: "Upper Bound Price", + title: "Upper Bound Price (Rs.)", dataIndex: "upperBoundPrice", key: "upperBoundPrice", }, diff --git a/react_client/src/components/organisms/Sider/index.tsx b/react_client/src/components/organisms/Sider/index.tsx index 07cf733..e7dd0cf 100644 --- a/react_client/src/components/organisms/Sider/index.tsx +++ b/react_client/src/components/organisms/Sider/index.tsx @@ -10,6 +10,7 @@ import { FileSyncOutlined, InfoCircleOutlined, InboxOutlined, + GiftOutlined, } from "@ant-design/icons"; import type { MenuProps } from "antd"; import { Layout, Menu, theme } from "antd"; @@ -127,19 +128,19 @@ const SidebarRoutes: MenuProps["items"] = [ }, { key: APP_ROUTES.DELIVERIES_SUPPLIER, - icon: , + icon: , // for supplier label: Deliveries, }, { key: APP_ROUTES.INVOICES_SUPPLIER, - icon: , + icon: , // for supplier label: Invoices, }, { key: APP_ROUTES.ORDER_HISTORY_SUPPLIER, - icon: , + icon: , // for supplier label: Order History, },