feat: fake orders

This commit is contained in:
2024-06-18 15:14:37 +03:00
parent fb5538ab79
commit bdcd4507c2
5 changed files with 288 additions and 52 deletions

View File

@@ -150,7 +150,7 @@ class GymCategory {
} }
class GymHistoryItem { class GymHistoryItem {
final String id; String id;
final String date; final String date;
final String sum; final String sum;
final String photo; final String photo;
@@ -216,7 +216,7 @@ class GymHistoryItemDetail {
receiver: json["receiver"], receiver: json["receiver"],
email: json["email"], email: json["email"],
address: json["address"], address: json["address"],
payUrl: json["pay_url"], payUrl: json["pay_url"] as String?,
providers: List<GymHistoryItemDetailProvider>.from(json["providers"] providers: List<GymHistoryItemDetailProvider>.from(json["providers"]
.map((x) => GymHistoryItemDetailProvider.fromJson(x))), .map((x) => GymHistoryItemDetailProvider.fromJson(x))),
); );

View File

@@ -6,6 +6,7 @@ import 'package:gymlink_module_web/components/order_confirm_item_card.dart';
import 'package:gymlink_module_web/interfaces/items.dart'; import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/pages/order_history.dart'; import 'package:gymlink_module_web/pages/order_history.dart';
import 'package:gymlink_module_web/providers/cart.dart'; import 'package:gymlink_module_web/providers/cart.dart';
import 'package:gymlink_module_web/tools/history.dart';
import 'package:gymlink_module_web/tools/items.dart'; import 'package:gymlink_module_web/tools/items.dart';
import 'package:gymlink_module_web/tools/prefs.dart'; import 'package:gymlink_module_web/tools/prefs.dart';
import 'package:gymlink_module_web/tools/routes.dart'; import 'package:gymlink_module_web/tools/routes.dart';
@@ -64,6 +65,9 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
List<GymItem> gymCart = []; List<GymItem> gymCart = [];
bool isAgree = false; bool isAgree = false;
bool _isLoading = true; bool _isLoading = true;
final _emailController = TextEditingController();
final _addressController = TextEditingController();
final _nameController = TextEditingController();
@override @override
void initState() { void initState() {
@@ -93,6 +97,65 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
} }
} }
bool _checkInputs() {
final email = _emailController.text;
final address = _addressController.text;
final name = _nameController.text;
if (!RegExp(r"^((?!\.)[\w\-_.]*[^.])(@\w+)(\.\w+(\.\w+)?[^.\W])$")
.hasMatch(email)) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Ошибка'),
content: const Text('Некорректный email'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('ОК'),
)
],
),
);
return false;
}
if (address.isEmpty) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Ошибка'),
content: const Text('Адрес не может быть пустым'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('ОК'),
)
],
),
);
return false;
}
if (name.isEmpty) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Ошибка'),
content: const Text('ФИО не может быть пустым'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('ОК'),
)
],
),
);
return false;
}
return true;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@@ -148,6 +211,7 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
data: '## Итого: ${totalPrice.toStringAsFixed(2)} руб.'), data: '## Итого: ${totalPrice.toStringAsFixed(2)} руб.'),
Expanded( Expanded(
child: TextField( child: TextField(
controller: _addressController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Адрес доставки', hintText: 'Адрес доставки',
border: OutlineInputBorder( border: OutlineInputBorder(
@@ -158,6 +222,7 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
), ),
Expanded( Expanded(
child: TextField( child: TextField(
controller: _emailController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Электронная почта', hintText: 'Электронная почта',
border: OutlineInputBorder( border: OutlineInputBorder(
@@ -169,6 +234,7 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
), ),
Expanded( Expanded(
child: TextField( child: TextField(
controller: _nameController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Получатель', hintText: 'Получатель',
border: OutlineInputBorder( border: OutlineInputBorder(
@@ -179,8 +245,15 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
), ),
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
if (!_checkInputs()) return;
_goToPage(); _goToPage();
await clearCart(); await clearCart();
await addToHistory(GymHistoryItem(
id: '123',
date: '01.01.1970',
sum: '123',
photo: 'product.png',
));
Provider.of<CartProvider>(context, listen: false) Provider.of<CartProvider>(context, listen: false)
.updateCartLength(); .updateCartLength();
Navigator.of(context).pushAndRemoveUntil( Navigator.of(context).pushAndRemoveUntil(

View File

@@ -1,10 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gymlink_module_web/components/app_bar.dart'; import 'package:gymlink_module_web/components/app_bar.dart';
import 'package:gymlink_module_web/components/heading.dart'; import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/components/history_item_card.dart'; import 'package:gymlink_module_web/components/history_item_card.dart';
import 'package:gymlink_module_web/interfaces/items.dart'; import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/tools/history.dart';
import 'package:gymlink_module_web/tools/relative.dart'; import 'package:gymlink_module_web/tools/relative.dart';
import 'package:lazy_load_scrollview/lazy_load_scrollview.dart'; import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
@@ -48,29 +50,22 @@ class HistoryPage extends StatefulWidget {
class _HistoryPageState extends State<HistoryPage> { class _HistoryPageState extends State<HistoryPage> {
List<GymHistoryItem> my_orders = []; List<GymHistoryItem> my_orders = [];
late Timer _updateTimer; late Timer _updateTimer;
bool _isLoading = true;
bool _isRefreshing = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
my_orders = [
GymHistoryItem(
id: '123', date: '01.01.1970', sum: '120', photo: 'product.png')
];
ordersRefresh(); ordersRefresh();
} }
void ordersRefresh() { void ordersRefresh() {
_updateTimer = Timer.periodic(const Duration(minutes: 1), _onRefresh); _updateTimer = Timer.periodic(const Duration(minutes: 1), _onRefresh);
Future.microtask(() => _onRefresh(_updateTimer));
} }
void _onLoad() async { void _onLoad() async {
await Future.delayed(const Duration(milliseconds: 1000)); await Future.delayed(const Duration(milliseconds: 1000));
setState(() {
my_orders.add(
GymHistoryItem(
id: '123', date: '01.01.1970', sum: '120', photo: 'product.png'),
);
});
} }
@override @override
@@ -81,7 +76,12 @@ class _HistoryPageState extends State<HistoryPage> {
Future<void> _onRefresh(Timer timer) async { Future<void> _onRefresh(Timer timer) async {
await Future.delayed(const Duration(milliseconds: 1000)); await Future.delayed(const Duration(milliseconds: 1000));
debugPrint('refreshed'); var orders = await getHistory();
setState(() {
my_orders = orders;
_isLoading = false;
_isRefreshing = false;
});
} }
@override @override
@@ -95,7 +95,43 @@ class _HistoryPageState extends State<HistoryPage> {
title: 'История заказов', title: 'История заказов',
toMain: true, toMain: true,
), ),
Expanded( const SizedBox(height: 5),
kIsWeb && !_isLoading
? Center(
child: ElevatedButton(
onPressed: () {
setState(() => _isRefreshing = true);
_onRefresh(_updateTimer);
},
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(50)),
),
foregroundColor: Colors.white,
fixedSize: const Size(180, 40),
),
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('Обновить'),
Spacer(),
Icon(Icons.refresh),
Spacer()
],
),
),
)
: const SizedBox.shrink(),
const SizedBox(height: 5),
_isRefreshing
? const Center(child: CircularProgressIndicator())
: const SizedBox.shrink(),
const SizedBox(height: 5),
_isLoading
? const Expanded(
child: Center(child: CircularProgressIndicator()))
: Expanded(
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
@@ -105,7 +141,9 @@ class _HistoryPageState extends State<HistoryPage> {
child: RefreshIndicator( child: RefreshIndicator(
edgeOffset: 55, edgeOffset: 55,
onRefresh: () => _onRefresh(_updateTimer), onRefresh: () => _onRefresh(_updateTimer),
child: Stack( child: my_orders.isEmpty
? const Center(child: Text('Нет заказов'))
: Stack(
children: [ children: [
ListView.builder( ListView.builder(
itemCount: my_orders.length, itemCount: my_orders.length,
@@ -116,7 +154,8 @@ class _HistoryPageState extends State<HistoryPage> {
cost: item.sum, cost: item.sum,
date: item.date, date: item.date,
image: Image( image: Image(
image: AssetImage('assets/${item.photo}'), image: AssetImage(
'assets/${item.photo}'),
width: 50, width: 50,
), ),
); );
@@ -127,7 +166,9 @@ class _HistoryPageState extends State<HistoryPage> {
), ),
), ),
), ),
getSpacer(context: context) my_orders.isEmpty
? const SizedBox.shrink()
: getSpacer(context: context)
], ],
), ),
), ),

View File

@@ -7,6 +7,7 @@ import 'package:gymlink_module_web/components/app_bar.dart';
import 'package:gymlink_module_web/components/heading.dart'; import 'package:gymlink_module_web/components/heading.dart';
import 'package:gymlink_module_web/components/order_detail_item_card.dart'; import 'package:gymlink_module_web/components/order_detail_item_card.dart';
import 'package:gymlink_module_web/interfaces/items.dart'; import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:gymlink_module_web/tools/history.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
final GymHistoryItemDetail item = GymHistoryItemDetail.fromJson({ final GymHistoryItemDetail item = GymHistoryItemDetail.fromJson({
@@ -38,7 +39,6 @@ final GymHistoryItemDetail item = GymHistoryItemDetail.fromJson({
] ]
}); });
//FIXME: Починить скролл
class OrderInfoPage extends StatefulWidget { class OrderInfoPage extends StatefulWidget {
final String id; final String id;
const OrderInfoPage({super.key, required this.id}); const OrderInfoPage({super.key, required this.id});
@@ -51,6 +51,7 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
GymHistoryItemDetail? detail; GymHistoryItemDetail? detail;
final _scrollController = ScrollController(); final _scrollController = ScrollController();
late Timer _updateTimer; late Timer _updateTimer;
bool _isRefreshing = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -65,9 +66,11 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
} }
Future<void> _onRefresh(Timer timer) async { Future<void> _onRefresh(Timer timer) async {
return Future.delayed(const Duration(milliseconds: 1000), () { return Future.delayed(const Duration(milliseconds: 1000), () async {
var orderInfo = await getHistoryDetail(widget.id);
setState(() { setState(() {
detail = item; detail = orderInfo;
_isRefreshing = false;
}); });
}); });
} }
@@ -100,7 +103,12 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
kIsWeb kIsWeb
? Center( ? Center(
child: ElevatedButton( child: ElevatedButton(
onPressed: () => _onRefresh(_updateTimer), onPressed: () {
setState(() {
_isRefreshing = true;
});
_onRefresh(_updateTimer);
},
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
@@ -122,13 +130,19 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
), ),
) )
: const SizedBox.shrink(), : const SizedBox.shrink(),
const SizedBox(height: 10), const SizedBox(height: 5),
_isRefreshing
? const Center(
child: CircularProgressIndicator(),
)
: const SizedBox.shrink(),
const SizedBox(height: 5),
ListView.builder( ListView.builder(
itemCount: 3, itemCount: detail!.providers.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final provider = detail!.providers[0]; final provider = detail!.providers[index];
return Padding( return Padding(
padding: const EdgeInsetsDirectional.symmetric( padding: const EdgeInsetsDirectional.symmetric(
vertical: 10, vertical: 10,

108
lib/tools/history.dart Normal file
View File

@@ -0,0 +1,108 @@
import 'dart:convert';
import 'dart:math';
import 'package:gymlink_module_web/interfaces/items.dart';
import 'package:shared_preferences/shared_preferences.dart';
Future<List<GymHistoryItem>> getHistory() async {
final prefs = await SharedPreferences.getInstance();
String historyString = prefs.getString('history') ?? "[]";
List<GymHistoryItem> history = [];
for (var historyItem in jsonDecode(historyString) as List<dynamic>) {
history.add(GymHistoryItem.fromJson(historyItem));
}
history.sort((a, b) => b.id.compareTo(a.id));
history = history.reversed.toList();
return history;
}
Future<void> addToHistory(GymHistoryItem item) async {
final prefs = await SharedPreferences.getInstance();
String historyString = prefs.getString('history') ?? "[]";
List<GymHistoryItem> history = [];
for (var historyItem in jsonDecode(historyString) as List<dynamic>) {
history.add(GymHistoryItem.fromJson(historyItem));
}
item.id = Random().nextInt(100000).toString();
String detailHistoryString = prefs.getString('detail_history') ?? "[]";
List<GymHistoryItemDetail> detailHistory = [];
for (var historyItem in jsonDecode(detailHistoryString) as List<dynamic>) {
detailHistory.add(GymHistoryItemDetail.fromJson(historyItem));
}
var json = {
"id": item.id,
"date": DateTime.now()
.toLocal()
.toLocal()
.toString()
.split(' ')[0]
.replaceAll('-', '.')
.split('.')
.reversed
.join('.'),
"sum": Random().nextInt(100000).toString(),
"pay_url": [null, "https://example.org"][Random().nextInt(2)],
"receiver": "Иванов Иван Иванович ${Random().nextInt(100000).toString()}",
"email": "a${Random().nextInt(100000).toString()}@a.ru",
"address":
"г. ${['Москва', 'Петербург', 'Новгород'][Random().nextInt(3)]}, ул. ${[
'Пушкина',
'Ленина',
'Лермонтова'
][Random().nextInt(3)]}, д. ${Random().nextInt(100).toString()}",
"providers": [
{
"id": Random().nextInt(100000).toString(),
"name": "Поставщик ${Random().nextInt(100000).toString()}",
"status": ["Доставлен", "Доставляется", "Ожидает"][Random().nextInt(3)],
"items": [
{
"photo": "url${Random().nextInt(100000).toString()}",
"id": Random().nextInt(100000).toString(),
"count": Random().nextInt(100),
"price": Random().nextInt(100000).toString()
},
{
"photo": "url${Random().nextInt(100000).toString()}",
"id": Random().nextInt(100000).toString(),
"count": Random().nextInt(100),
"price": Random().nextInt(100000).toString()
}
]
},
{
"id": Random().nextInt(100000).toString(),
"name": "Поставщик ${Random().nextInt(100000).toString()}",
"status": ["Доставлен", "Доставляется", "Ожидает"][Random().nextInt(3)],
"items": [
{
"photo": "url${Random().nextInt(100000).toString()}",
"id": Random().nextInt(100000).toString(),
"count": Random().nextInt(100),
"price": Random().nextInt(100000).toString()
}
]
}
]
};
final detailHistoryItem = GymHistoryItemDetail.fromJson(json);
detailHistory.add(detailHistoryItem);
history.add(GymHistoryItem(
date: detailHistoryItem.date,
id: detailHistoryItem.id,
photo: 'product.png',
sum: detailHistoryItem.sum));
prefs.setString('history', jsonEncode(history));
prefs.setString('detail_history', jsonEncode(detailHistory));
}
Future<GymHistoryItemDetail?> getHistoryDetail(String id) async {
final prefs = await SharedPreferences.getInstance();
String historyString = prefs.getString('detail_history') ?? "[]";
for (var historyItem in jsonDecode(historyString) as List<dynamic>) {
if (GymHistoryItemDetail.fromJson(historyItem).id == id) {
return GymHistoryItemDetail.fromJson(historyItem);
}
}
return null;
}