fix: ultra-fake orders

This commit is contained in:
2024-06-18 20:40:45 +03:00
parent bdcd4507c2
commit 893b925a04
7 changed files with 170 additions and 191 deletions

View File

@@ -16,7 +16,7 @@ class HistoryItemCard extends StatelessWidget {
final String id; final String id;
final String cost; final String cost;
final String date; final String date;
final Image image; final Widget image;
const HistoryItemCard({ const HistoryItemCard({
super.key, super.key,

View File

@@ -31,6 +31,8 @@ class GymItem {
final double price; final double price;
final String categoryId; final String categoryId;
final List<GymImage> images; final List<GymImage> images;
final String supplierId;
final String supplierName;
int localCount = 0; int localCount = 0;
GymItem({ GymItem({
@@ -42,13 +44,16 @@ class GymItem {
required this.price, required this.price,
required this.categoryId, required this.categoryId,
required this.images, required this.images,
required this.supplierId,
required this.supplierName,
}); });
factory GymItem.fromRawJson(String str) => GymItem.fromJson(json.decode(str)); factory GymItem.fromRawJson(String str) => GymItem.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson()); String toRawJson() => json.encode(toJson());
factory GymItem.fromJson(Map<String, dynamic> json) => GymItem( factory GymItem.fromJson(Map<String, dynamic> json) {
return GymItem(
id: json["id"], id: json["id"],
externalId: json["ExternalId"], externalId: json["ExternalId"],
title: json["title"], title: json["title"],
@@ -56,9 +61,14 @@ class GymItem {
count: json["count"], count: json["count"],
price: json["price"] / 100, price: json["price"] / 100,
categoryId: json["categoryId"], categoryId: json["categoryId"],
images: List<GymImage>.from( images:
json["images"].map((x) => GymImage.fromJson(x))), List<GymImage>.from(json["images"].map((x) => GymImage.fromJson(x))),
supplierId: json["supplier"] == null ? '' : json["supplier"]["id"] ?? '',
supplierName: json["supplier"] == null
? ''
: json["supplier"]["title"] ?? "Поставщик",
); );
}
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"id": id, "id": id,
@@ -69,6 +79,8 @@ class GymItem {
"price": price, "price": price,
"categoryId": categoryId, "categoryId": categoryId,
"images": List<dynamic>.from(images.map((x) => x.toJson())), "images": List<dynamic>.from(images.map((x) => x.toJson())),
"supplier":
supplierId == '' ? null : {"id": supplierId, "title": supplierName},
}; };
} }
@@ -183,7 +195,7 @@ class GymHistoryItem {
} }
class GymHistoryItemDetail { class GymHistoryItemDetail {
final String id; String id;
final String date; final String date;
final String sum; final String sum;
String? payUrl; String? payUrl;
@@ -236,7 +248,7 @@ class GymHistoryItemDetail {
class GymHistoryItemDetailProvider { class GymHistoryItemDetailProvider {
final String id; final String id;
final String name; final String name;
final String status; String status;
final List<GymHistoryItemDetailItem> items; final List<GymHistoryItemDetailItem> items;
GymHistoryItemDetailProvider({ GymHistoryItemDetailProvider({
@@ -251,14 +263,15 @@ class GymHistoryItemDetailProvider {
String toRawJson() => json.encode(toJson()); String toRawJson() => json.encode(toJson());
factory GymHistoryItemDetailProvider.fromJson(Map<String, dynamic> json) => factory GymHistoryItemDetailProvider.fromJson(Map<String, dynamic> json) {
GymHistoryItemDetailProvider( return GymHistoryItemDetailProvider(
id: json["id"], id: json["id"],
name: json["name"], name: json["name"],
status: json["status"], status: json["status"],
items: List<GymHistoryItemDetailItem>.from( items: List<GymHistoryItemDetailItem>.from(
json["items"].map((x) => GymHistoryItemDetailItem.fromJson(x))), json["items"].map((x) => GymHistoryItemDetailItem.fromJson(x))),
); );
}
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"id": id, "id": id,
@@ -272,6 +285,7 @@ class GymHistoryItemDetailItem {
final String photo; final String photo;
final String id; final String id;
final int count; final int count;
final String name;
final String price; final String price;
GymHistoryItemDetailItem({ GymHistoryItemDetailItem({
@@ -279,6 +293,7 @@ class GymHistoryItemDetailItem {
required this.id, required this.id,
required this.count, required this.count,
required this.price, required this.price,
required this.name,
}); });
factory GymHistoryItemDetailItem.fromRawJson(String str) => factory GymHistoryItemDetailItem.fromRawJson(String str) =>
@@ -292,6 +307,7 @@ class GymHistoryItemDetailItem {
id: json["id"], id: json["id"],
count: json["count"], count: json["count"],
price: json["price"], price: json["price"],
name: json["name"],
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@@ -299,5 +315,6 @@ class GymHistoryItemDetailItem {
"id": id, "id": id,
"count": count, "count": count,
"price": price, "price": price,
"name": name,
}; };
} }

View File

@@ -6,6 +6,7 @@ import 'package:gymlink_module_web/main_mobile.dart';
import 'package:gymlink_module_web/providers/main.dart'; import 'package:gymlink_module_web/providers/main.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() { void main() {
runApp(const MyExampleApp()); runApp(const MyExampleApp());
@@ -250,8 +251,16 @@ class ExampleSecondPage extends StatelessWidget {
title: const Text('GymLink Example App'), title: const Text('GymLink Example App'),
), ),
drawer: getDrawer(context), drawer: getDrawer(context),
body: const Center( body: Center(
child: Text('Example page'), child: TextButton(
onPressed: () async {
final prefs = await SharedPreferences.getInstance();
prefs.remove('token');
prefs.remove('history');
prefs.remove('cart');
prefs.remove('detail_history');
},
child: const Text('Clear')),
), ),
); );
} }

View File

@@ -1,3 +1,5 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:gymlink_module_web/components/app_bar.dart'; import 'package:gymlink_module_web/components/app_bar.dart';
@@ -69,6 +71,57 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
final _addressController = TextEditingController(); final _addressController = TextEditingController();
final _nameController = TextEditingController(); final _nameController = TextEditingController();
Future<void> _addOrderToHistory() async {
String name = _nameController.text;
String email = _emailController.text;
String address = _addressController.text;
Set<String> supplierIdsSet = {};
for (final item in cartItems) {
supplierIdsSet.add(item.supplierId);
}
List<GymHistoryItemDetailProvider> providers = [];
for (final supplierId in supplierIdsSet) {
List<GymItem> items =
cartItems.where((e) => e.supplierId == supplierId).toList();
List<GymHistoryItemDetailItem> detailItems = [];
for (final item in items) {
detailItems.add(GymHistoryItemDetailItem(
id: item.id,
photo: item.images[0].url,
count: item.localCount,
price: item.price.toString(),
name: item.title,
));
}
GymHistoryItemDetailProvider provider = GymHistoryItemDetailProvider(
id: supplierId,
name: items.first.supplierName,
items: detailItems,
// status: 'Не оплачен'
status: Random().nextBool()
? 'Не оплачен'
: Random().nextBool()
? 'Не оплачен'
: Random().nextBool()
? 'Сборка'
: 'Доставляется',
);
providers.add(provider);
}
final order = GymHistoryItemDetail(
id: Random().nextInt(1000000).toString(),
receiver: name,
email: email,
address: address,
sum: totalPrice.toString(),
date: '',
providers: providers,
);
await addToHistory(order);
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -248,12 +301,7 @@ class _OrderConfirmationPageState extends State<OrderConfirmationPage> {
if (!_checkInputs()) return; if (!_checkInputs()) return;
_goToPage(); _goToPage();
await clearCart(); await clearCart();
await addToHistory(GymHistoryItem( await _addOrderToHistory();
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

@@ -153,10 +153,22 @@ class _HistoryPageState extends State<HistoryPage> {
id: item.id, id: item.id,
cost: item.sum, cost: item.sum,
date: item.date, date: item.date,
image: Image( image: FutureBuilder(
image: AssetImage( future: precacheImage(
'assets/${item.photo}'), NetworkImage(item.photo),
context),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
return Image(
image: NetworkImage(
item.photo),
width: 50, width: 50,
);
} else {
return const CircularProgressIndicator();
}
},
), ),
); );
}, },

View File

@@ -8,6 +8,7 @@ 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:gymlink_module_web/tools/history.dart';
import 'package:gymlink_module_web/tools/text.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({
@@ -77,8 +78,7 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
Future<void> _goToPage() async { Future<void> _goToPage() async {
if (detail?.payUrl != null) { if (detail?.payUrl != null) {
final Uri url = Uri.parse(detail?.payUrl ?? 'example.org'); final Uri url = Uri.parse(detail?.payUrl ?? 'https://example.org');
detail!.payUrl = null;
if (!await launchUrl(url, webOnlyWindowName: '_blank')) { if (!await launchUrl(url, webOnlyWindowName: '_blank')) {
throw 'Could not launch $url'; throw 'Could not launch $url';
} }
@@ -160,14 +160,12 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
OrderDetailCardItemCard( OrderDetailCardItemCard(
image: FutureBuilder( image: FutureBuilder(
future: precacheImage( future: precacheImage(
const AssetImage('assets/product.png'), NetworkImage(item.photo), context),
context),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == if (snapshot.connectionState ==
ConnectionState.done) { ConnectionState.done) {
return const Image( return Image(
image: image: NetworkImage(item.photo),
AssetImage('assets/product.png'),
width: 50, width: 50,
); );
} else { } else {
@@ -175,7 +173,7 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
} }
}, },
), ),
name: 'Протеин', name: shortString(item.name),
count: item.count, count: item.count,
price: double.parse(item.price), price: double.parse(item.price),
), ),
@@ -207,13 +205,15 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
MarkdownBody(
data: '## Итого: ${detail!.sum} руб.'),
MarkdownBody( MarkdownBody(
data: data:
"### Адрес получателя: __${detail!.address}__"), "### Адрес получателя: __${detail!.address}__"),
MarkdownBody( MarkdownBody(
data: '### Почта: __${detail!.email}__'), data: '### Почта: __${detail!.email}__'),
MarkdownBody( MarkdownBody(
data: '### ФИО: _${detail!.receiver}_'), data: '### ФИО: __${detail!.receiver}__'),
], ],
), ),
detail?.payUrl == null detail?.payUrl == null
@@ -222,7 +222,7 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
await _goToPage(); await _goToPage();
debugPrint('clicked'); await payOrder(detail!.id);
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor:
@@ -261,102 +261,4 @@ class _OrderInfoPageState extends State<OrderInfoPage> {
: _buildContent(), : _buildContent(),
); );
} }
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: const GymLinkAppBar(),
// body: detail == null
// ? const Center(child: CircularProgressIndicator())
// : Column(
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// GymLinkHeader(title: "Заказ #${detail?.id} от ${detail?.date}"),
// Expanded(
// child: RefreshIndicator(
// onRefresh: () => _onRefresh(),
// edgeOffset: 55,
// child: Scrollbar(
// controller: _scrollController,
// child: ListView(
// shrinkWrap: true,
// controller: _scrollController,
// children: [
// detail != null
// ? ListView.builder(
// itemCount: (detail!.providers.length + 1),
// shrinkWrap: true,
// physics: const NeverScrollableScrollPhysics(),
// itemBuilder: (context, index) {
// final provider = detail!.providers[0];
// return Card(
// elevation: 3,
// child: Column(
// children: [
// MarkdownBody(
// data: '# ${provider.name}'),
// MarkdownBody(
// data:
// '## Статус: ${provider.status}'),
// const MarkdownBody(
// data: '### Состав:'),
// for (final item in provider.items)
// OrderDetailCardItemCard(
// image: FutureBuilder(
// future: precacheImage(
// const AssetImage(
// 'assets/product.png'),
// context),
// builder: (context, snapshot) {
// if (snapshot
// .connectionState ==
// ConnectionState.done) {
// return const Image(
// image: AssetImage(
// 'assets/product.png'),
// width: 50,
// );
// } else {
// return const CircularProgressIndicator();
// }
// },
// ),
// name: 'Протеин',
// count: item.count,
// price: double.parse(item.price),
// ),
// ],
// ),
// );
// },
// )
// : const SizedBox.shrink(),
// Card(
// elevation: 4,
// child: Padding(
// padding: const EdgeInsetsDirectional.symmetric(
// horizontal: 10, vertical: 20),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// MarkdownBody(
// data:
// "### Адрес получателя: _${detail!.address}_"),
// Markdown(
// data: '### Почта: _${detail!.email}_'),
// // Markdown(
// // data: '### ФИО: _${detail!.receiver}_'),
// ],
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// ],
// ),
// );
// }
} }

View File

@@ -16,7 +16,7 @@ Future<List<GymHistoryItem>> getHistory() async {
return history; return history;
} }
Future<void> addToHistory(GymHistoryItem item) async { Future<void> addToHistory(GymHistoryItemDetail item) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
String historyString = prefs.getString('history') ?? "[]"; String historyString = prefs.getString('history') ?? "[]";
List<GymHistoryItem> history = []; List<GymHistoryItem> history = [];
@@ -29,6 +29,10 @@ Future<void> addToHistory(GymHistoryItem item) async {
for (var historyItem in jsonDecode(detailHistoryString) as List<dynamic>) { for (var historyItem in jsonDecode(detailHistoryString) as List<dynamic>) {
detailHistory.add(GymHistoryItemDetail.fromJson(historyItem)); detailHistory.add(GymHistoryItemDetail.fromJson(historyItem));
} }
List<Map<String, dynamic>> providers = [];
for (final provider in item.providers) {
providers.add(provider.toJson());
}
var json = { var json = {
"id": item.id, "id": item.id,
"date": DateTime.now() "date": DateTime.now()
@@ -40,58 +44,23 @@ Future<void> addToHistory(GymHistoryItem item) async {
.split('.') .split('.')
.reversed .reversed
.join('.'), .join('.'),
"sum": Random().nextInt(100000).toString(), "sum": item.sum,
"pay_url": [null, "https://example.org"][Random().nextInt(2)], "pay_url": item.providers.where((e) => e.status == 'Не оплачен').isNotEmpty
"receiver": "Иванов Иван Иванович ${Random().nextInt(100000).toString()}", ? 'https://example.org'
"email": "a${Random().nextInt(100000).toString()}@a.ru", : null,
"address": "receiver": item.receiver,
"г. ${['Москва', 'Петербург', 'Новгород'][Random().nextInt(3)]}, ул. ${[ "email": item.email,
'Пушкина', "address": item.address,
'Ленина', "providers": providers
'Лермонтова'
][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); final detailHistoryItem = GymHistoryItemDetail.fromJson(json);
detailHistory.add(detailHistoryItem); detailHistory.add(detailHistoryItem);
history.add(GymHistoryItem( history.add(GymHistoryItem(
date: detailHistoryItem.date, date: detailHistoryItem.date,
id: detailHistoryItem.id, id: detailHistoryItem.id,
photo: 'product.png', photo: detailHistoryItem.providers[0].items[0].photo,
sum: detailHistoryItem.sum)); sum: detailHistoryItem.sum,
));
prefs.setString('history', jsonEncode(history)); prefs.setString('history', jsonEncode(history));
prefs.setString('detail_history', jsonEncode(detailHistory)); prefs.setString('detail_history', jsonEncode(detailHistory));
} }
@@ -106,3 +75,25 @@ Future<GymHistoryItemDetail?> getHistoryDetail(String id) async {
} }
return null; return null;
} }
Future<void> payOrder(String id) async {
final prefs = await SharedPreferences.getInstance();
String historyString = prefs.getString('detail_history') ?? "[]";
List<GymHistoryItemDetail> history = [];
for (var historyItem in jsonDecode(historyString) as List<dynamic>) {
history.add(GymHistoryItemDetail.fromJson(historyItem));
}
List<GymHistoryItemDetail> newHistory = [];
for (final historyItem in history) {
if (historyItem.id == id) {
for (final provider in historyItem.providers) {
if (provider.status == 'Не оплачен') {
provider.status = 'Оплачен';
}
}
historyItem.payUrl = null;
}
newHistory.add(historyItem);
}
prefs.setString('detail_history', jsonEncode(newHistory));
}