Files
GymLink_Flutter/lib/pages/basket.dart
2024-06-09 14:40:30 +03:00

353 lines
12 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:gymlink_module_web/components/app_bar.dart';
import 'package:gymlink_module_web/components/basket_item_card.dart';
import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/pages/main.dart';
import 'package:gymlink_module_web/pages/order_confirmation.dart';
import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/tools/items.dart';
import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/routes.dart';
import 'package:gymlink_module_web/tools/text.dart';
import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
import 'package:provider/provider.dart';
List<Map<String, dynamic>> cart = [
{
"name": "Протеин",
"image": "product.png",
"price": "120",
"details": "Test details",
"id": "34fa3126-bfaf-5dec-8f4a-b246c097ef73"
},
{
"name": "Протеин",
"image": "product.png",
"price": "150",
"details": "Test details",
"id": "34a26e82-7656-5e98-a44a-c2d01d0b1ad1123"
},
{
"name": "Протеин",
"image": "product.png",
"price": "250",
"details": "Test details",
"id": "4fb204b7-3f9e-52a2-bed1-415c00a31a37123"
},
{
"name": "Протеин",
"image": "product.png",
"price": "300",
"details": "Test details",
"id": "09b2f5bb-683e-5c39-ae89-b8e152fa8bcf123"
},
{
"name": "Протеин",
"image": "product.png",
"price": "100",
"details": "Test details",
"id": "cd1b6817-db94-5394-be1d-af88af79749f123"
}
];
class BasketPage extends StatefulWidget {
const BasketPage({super.key});
@override
State<BasketPage> createState() => _BasketPageState();
}
class _BasketPageState extends State<BasketPage> {
List<GymItem> cartItems = [];
double totalPrice = 0;
List<GymItem> gymCart = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
Future.microtask(() => getCart().then((value) async {
final itemIds =
value.map((element) => element['id'] as String).toList();
final items = await getItemsByIds(context, itemIds);
setState(() {
gymCart = items;
cartItems = value.map((element) {
final item = gymCart.firstWhere((e) => e.id == element['id']);
item.localCount = element['count'] as int;
return item;
}).toList();
totalPrice = cartItems.fold(
0, (sum, item) => sum + item.price * item.localCount);
_isLoading = false;
});
}));
}
void _updateCart() {
Provider.of<CartProvider>(context, listen: false).updateCartLength();
}
void removeItem(String id) async {
final item = cartItems.firstWhere((element) => element.id == id);
bool toDelete = false;
setState(() {
if (item.localCount > 1) {
item.localCount--;
cartItems[cartItems.indexOf(item)].localCount = item.localCount;
} else {
toDelete = true;
}
totalPrice =
cartItems.fold(0, (sum, item) => sum + item.price * item.localCount);
});
if (toDelete) {
await _deleteItemAlert(id, item.title);
} else {
await removeItemFromCart(id);
}
}
void addItem(String id) async {
final item =
cartItems.firstWhere((element) => element.id == id, orElse: () {
final cartItem = gymCart.firstWhere((element) => element.id == id);
cartItem.localCount = 0;
return cartItem;
});
if (item.localCount + 1 > item.count) {
return;
}
setState(() {
item.localCount++;
cartItems[cartItems.indexOf(item)].localCount = item.localCount;
totalPrice =
cartItems.fold(0, (sum, item) => sum + item.price * item.localCount);
});
await addItemToCart(id);
}
Future<void> _deleteItemAlert(String id, String name) async {
return showDialog<void>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Удаление из корзины'),
content: SingleChildScrollView(
child: ListBody(
children: [
Text('Вы действительно хотите убрать "$name" из корзины?'),
],
),
),
actions: [
TextButton(
child: const Text('Отмена'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Удалить'),
onPressed: () {
removeItemFromCart(id);
setState(() {
cartItems.removeWhere((element) => element.id == id);
});
if (mounted) {
_updateCart();
}
Navigator.of(context).pop();
},
),
],
);
},
);
}
Future<void> _clearCartAlert() async {
return showDialog<void>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Очистка корзины'),
content: const SingleChildScrollView(
child: ListBody(
children: [
Text('Вы действительно хотите очистить корзину?'),
],
),
),
actions: [
TextButton(
child: const Text('Отмена'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Очистить'),
onPressed: () {
clearCart();
setState(() {
cartItems = [];
});
if (mounted) {
_updateCart();
}
Navigator.of(context).pop();
},
),
],
);
},
);
}
Widget _buildRowOrCol(
{required BuildContext context, required List<Widget> children}) {
if (MediaQuery.of(context).size.width > 600) {
return Row(children: children);
}
return Column(children: children);
}
Widget _buildSpacer() {
if (MediaQuery.of(context).size.width > 600) {
return const Spacer();
}
return const SizedBox(height: 10);
}
void _onLoad() async {
await Future.delayed(const Duration(microseconds: 1000));
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const GymLinkAppBar(),
body: Column(
children: [
const GymLinkHeader(title: "Корзина"),
_isLoading
? const Expanded(
child: Center(child: CircularProgressIndicator()))
: cartItems.isEmpty
? Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Корзина пуста',
style: Theme.of(context).textTheme.bodyLarge),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () => Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
builder: (_) => const MainPage()),
(route) => route.isFirst),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(50)),
),
foregroundColor: Colors.white,
),
child: const Text('Вернуться назад'),
),
],
),
),
)
: Expanded(
child: _buildRowOrCol(
context: context,
children: [
Expanded(
child: LazyLoadScrollView(
onEndOfPage: _onLoad,
child: ListView.builder(
itemCount: cartItems.length,
itemBuilder: (context, index) {
final item = cartItems[index];
return BasketItemCard(
name: shortString(item.title),
price: item.price.toStringAsFixed(2),
id: item.id,
image: Image(
image: NetworkImage(item.images[0].url),
width: 50,
),
onTapPlus: () =>
addItem(item.id.toString()),
onTapMinus: () {
removeItem(item.id.toString());
},
quantity: item.localCount.toString(),
);
},
),
),
),
_buildSpacer(),
Padding(
padding: const EdgeInsetsDirectional.symmetric(
horizontal: 10, vertical: 10),
child: Column(
children: [
Text(
'Итого: ${totalPrice.toStringAsFixed(2)} руб.',
),
ElevatedButton(
onPressed: () => Navigator.of(context).push(
CustomPageRoute(
builder: (context) =>
const OrderConfirmationPage(),
),
),
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(50)),
),
foregroundColor: Colors.white,
),
child: const Text('Оформить заказ'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _clearCartAlert,
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(50))),
foregroundColor: Colors.white,
),
child: const Text('Очистить корзину'),
),
],
),
),
const SizedBox(width: 50),
],
),
),
],
),
);
}
}