// Label StoreMax // // Created by Anthony Gordon. // 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; import 'package:flutter_app/app/controllers/product_detail_controller.dart'; import 'package:flutter_app/app/models/cart_line_item.dart'; import 'package:flutter_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/enums/wishlist_action_enums.dart'; import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/resources/widgets/app_loader_widget.dart'; import 'package:flutter_app/resources/widgets/buttons.dart'; import 'package:flutter_app/resources/widgets/cart_icon_widget.dart'; import 'package:flutter_app/resources/widgets/future_build_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_body_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_footer_actions_widget.dart'; import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; import 'package:woosignal/models/response/product_variation.dart' as ws_product_variation; import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:woosignal/models/response/woosignal_app.dart'; class ProductDetailPage extends NyStatefulWidget { @override final ProductDetailController controller = ProductDetailController(); ProductDetailPage({Key key}) : super(key: key); @override _ProductDetailState createState() => _ProductDetailState(); } class _ProductDetailState extends NyState { bool _isLoading = true; ws_product.Product _product; List _productVariations = []; final Map _tmpAttributeObj = {}; final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig; @override widgetDidLoad() async { _product = widget.controller.data(); if (_product.type == "variable") { await _fetchProductVariations(); return; } setState(() { _isLoading = false; }); } _fetchProductVariations() async { List tmpVariations = []; int currentPage = 1; bool isFetching = true; while (isFetching) { List tmp = await appWooSignal( (api) => api.getProductVariations(_product.id, perPage: 100, page: currentPage), ); if (tmp != null && tmp.isNotEmpty) { tmpVariations.addAll(tmp); } if (tmp != null && tmp.length >= 100) { currentPage += 1; } else { isFetching = false; } } _productVariations = tmpVariations; setState(() { _isLoading = false; }); } _modalBottomSheetOptionsForAttribute(int attributeIndex) { wsModalBottom( context, title: "${trans("Select a")} ${_product.attributes[attributeIndex].name}", bodyWidget: ListView.separated( itemCount: _product.attributes[attributeIndex].options.length, separatorBuilder: (BuildContext context, int index) => Divider(), itemBuilder: (BuildContext context, int index) { return ListTile( title: Text( _product.attributes[attributeIndex].options[index], style: Theme.of(context).textTheme.subtitle1, ), trailing: (_tmpAttributeObj.isNotEmpty && _tmpAttributeObj.containsKey(attributeIndex) && _tmpAttributeObj[attributeIndex]["value"] == _product.attributes[attributeIndex].options[index]) ? Icon(Icons.check, color: Colors.blueAccent) : null, onTap: () { _tmpAttributeObj[attributeIndex] = { "name": _product.attributes[attributeIndex].name, "value": _product.attributes[attributeIndex].options[index] }; Navigator.pop(context, () {}); Navigator.pop(context); _modalBottomSheetAttributes(); }, ); }, ), ); } _modalBottomSheetAttributes() { ws_product_variation.ProductVariation productVariation = widget.controller .findProductVariation( tmpAttributeObj: _tmpAttributeObj, productVariations: _productVariations); wsModalBottom( context, title: trans("Options"), bodyWidget: ListView.separated( itemCount: _product.attributes.length, separatorBuilder: (BuildContext context, int index) => Divider( color: Colors.black12, thickness: 1, ), itemBuilder: (BuildContext context, int index) { return ListTile( title: Text(_product.attributes[index].name, style: Theme.of(context).textTheme.subtitle1), subtitle: (_tmpAttributeObj.isNotEmpty && _tmpAttributeObj.containsKey(index)) ? Text(_tmpAttributeObj[index]["value"], style: Theme.of(context).textTheme.bodyText1) : Text( "${trans("Select a")} ${_product.attributes[index].name}"), trailing: (_tmpAttributeObj.isNotEmpty && _tmpAttributeObj.containsKey(index)) ? Icon(Icons.check, color: Colors.blueAccent) : null, onTap: () => _modalBottomSheetOptionsForAttribute(index), ); }, ), extraWidget: Container( decoration: BoxDecoration( border: Border(top: BorderSide(color: Colors.black12, width: 1))), padding: EdgeInsets.only(top: 10), child: Column( children: [ Text( (productVariation != null ? "${trans("Price")}: ${formatStringCurrency(total: productVariation.price)}" : (((_product.attributes.length == _tmpAttributeObj.values.length) && productVariation == null) ? trans("This variation is unavailable") : trans("Choose your options"))), style: Theme.of(context).textTheme.subtitle1, ), Text( (productVariation != null ? productVariation.stockStatus != "instock" ? trans("Out of stock") : "" : ""), style: Theme.of(context).textTheme.subtitle1, ), PrimaryButton( title: trans("Add to cart"), action: () async { if (_product.attributes.length != _tmpAttributeObj.values.length) { showToastNotification(context, title: trans("Oops"), description: trans("Please select valid options first"), style: ToastNotificationStyleType.WARNING); return; } if (productVariation == null) { showToastNotification(context, title: trans("Oops"), description: trans("Product variation does not exist"), style: ToastNotificationStyleType.WARNING); return; } if (productVariation.stockStatus != "instock") { showToastNotification(context, title: trans("Sorry"), description: trans("This item is not in stock"), style: ToastNotificationStyleType.WARNING); return; } List options = []; _tmpAttributeObj.forEach((k, v) { options.add("${v["name"]}: ${v["value"]}"); }); CartLineItem cartLineItem = CartLineItem.fromProductVariation( quantityAmount: widget.controller.quantity, options: options, product: _product, productVariation: productVariation, ); await widget.controller.itemAddToCart( cartLineItem: cartLineItem, onSuccess: () => setState(() => {})); setState(() {}); Navigator.of(context).pop(); }), ], ), margin: EdgeInsets.only(bottom: 10), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( actions: [ if (_wooSignalApp.wishlistEnabled) FutureBuildWidget( asyncFuture: hasAddedWishlistProduct(_product.id), onValue: (isInFavourites) { return isInFavourites ? IconButton( onPressed: () => widget.controller.toggleWishList( onSuccess: () => setState(() {}), wishlistAction: WishlistAction.remove), icon: Icon(Icons.favorite, color: Colors.red)) : IconButton( onPressed: () => widget.controller.toggleWishList( onSuccess: () => setState(() {}), wishlistAction: WishlistAction.add), icon: Icon(Icons.favorite_border, color: Colors.black54)); }), CartIconWidget(), ], title: StoreLogo( height: 55, showBgWhite: (Theme.of(context).brightness == Brightness.dark)), centerTitle: true, ), body: SafeArea( child: _isLoading ? AppLoaderWidget() : Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: ProductDetailBodyWidget( wooSignalApp: _wooSignalApp, product: _product, ), ), // ProductDetailFooterActionsWidget( onAddToCart: _addItemToCart, onViewExternalProduct: widget.controller.viewExternalProduct, onAddQuantity: () => widget.controller .addQuantityTapped(onSuccess: () => setState(() {})), onRemoveQuantity: () => widget.controller .removeQuantityTapped(onSuccess: () => setState(() {})), product: _product, quantity: widget.controller.quantity, ) ], ), ), ); } _addItemToCart() async { if (_product.type != "simple") { _modalBottomSheetAttributes(); return; } if (_product.stockStatus != "instock") { showToastNotification(context, title: trans("Sorry"), description: trans("This item is out of stock"), style: ToastNotificationStyleType.WARNING, icon: Icons.local_shipping); return; } await widget.controller.itemAddToCart( cartLineItem: CartLineItem.fromProduct( quantityAmount: widget.controller.quantity, product: _product), onSuccess: () => setState(() {})); } }