import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:go_router/go_router.dart'; import 'package:outbag_app/backend/request.dart'; import 'package:outbag_app/backend/room.dart'; import 'package:outbag_app/backend/user.dart'; import 'package:outbag_app/components/category_chip.dart'; import 'package:outbag_app/tools/fetch_wrapper.dart'; import 'package:provider/provider.dart'; class NewItemPage extends StatefulWidget { final String room; final String server; final int? item; const NewItemPage( {super.key, required this.room, required this.server, this.item}); @override State createState() => _NewItemPageState(); } class _NewItemPageState extends State { // input controllers final _ctrInput = TextEditingController(); // data cache List categories = []; List products = []; RoomItem? item; void fetchCategories() { final user = context.read(); // TODO: load cached categories first doNetworkRequest(ScaffoldMessenger.of(context), req: () => postWithCreadentials( credentials: user, target: user.server, path: 'getCategories', body: {'room': widget.room, 'server': widget.server}), onOK: (body) async { final resp = body['data'] .map((raw) => RoomCategory.fromJSON(raw)) .toList(); setState(() { categories = resp; }); }); } void fetchProducts() { final user = context.read(); // TODO: load cached products first doNetworkRequest(ScaffoldMessenger.of(context), req: () => postWithCreadentials( credentials: user, target: user.server, path: 'getProducts', body: {'room': widget.room, 'server': widget.server}), onOK: (body) async { final resp = body['data'] .map((raw) => RoomProduct.fromJSON(raw)) .toList(); setState(() { products = resp; }); }); } void fetchItem() { final user = context.read(); // TODO: load cached item first doNetworkRequest(ScaffoldMessenger.of(context), req: () => postWithCreadentials( credentials: user, target: user.server, path: 'getItem', body: { 'room': widget.room, 'server': widget.server, 'listItemID': widget.item }), onOK: (body) async { final resp = RoomItem.fromJSON(body['data']); setState(() { item = resp; }); }); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { fetchCategories(); fetchProducts(); if (widget.item != null) { fetchItem(); } }); } String _query = ""; void createItem(BuildContext ctx, String name, int? productID) { final scaffMgr = ScaffoldMessenger.of(context); final router = GoRouter.of(context); final user = context.read(); doNetworkRequest(scaffMgr, req: () => postWithCreadentials( target: user.server, credentials: user, path: 'addItem', body: { 'room': widget.room, 'server': widget.server, 'state': 0, 'title': name, 'description': '', 'listCatID': null, 'unit': 0, 'value': '', 'listProdID': productID }), onOK: (body) async { final id = body["data"]["listItemID"]; // TODO cache item // launch edit item screen router.pushReplacementNamed('edit-item', params: { 'server': widget.server, 'id': widget.room, 'item': id.toString() }); }); } void createProduct(BuildContext ctx, String name, Function(int) cb) { final scaffMgr = ScaffoldMessenger.of(context); final user = context.read(); doNetworkRequest(scaffMgr, req: () => postWithCreadentials( target: user.server, credentials: user, path: 'addProduct', body: { 'room': widget.room, 'server': widget.server, 'title': name, 'description': '', 'listCatID': null, 'defUnit': 0, 'defValue': '', 'ean': '', 'parent': null }), onOK: (body) async { final id = body["data"]["listProdID"]; // TODO: cache product cb(id); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text((widget.item == null) ? AppLocalizations.of(context)!.createItem : AppLocalizations.of(context)!.editItem), ), body: SingleChildScrollView( child: Center( child: Padding( padding: const EdgeInsets.all(14), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 400), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SearchBar( controller: _ctrInput, leading: const Icon(Icons.search), hintText: AppLocalizations.of(context)!.newItemQueryHint, onChanged: (text) { setState(() { _query = text; }); }, ), const Divider(), // button bar ...((_query == "") ? ([ Text(AppLocalizations.of(context)! .newItemQueryEmpty) ]) : ([ Wrap( spacing: 20, runSpacing: 10, alignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.center, children: [ Text(AppLocalizations.of(context)! .newItemQuickAccessPrefix), // new item FilledButton.icon( onPressed: () { // create new named item // launch edit item screen once done createItem(context, _query, null); }, icon: const Icon(Icons.add), label: Text(_query)), // new product FilledButton.icon( onPressed: () { // create new product with name, // create new item with name // and link to the created product // launch edit item screen once done createProduct( context, _query, (p0) => createItem( context, _query, p0)); }, icon: const Icon(Icons.add), label: Text(AppLocalizations.of( context)! .newItemQuickProduct(_query))), ]) ])), const Divider(), // link products search ...((products // show all products if query is empty // when query isn't empty show products // that contain the query in the title // or description .where((element) => (_query == "") || element.name.contains(_query) || element.description.contains(_query)) .map((e) => ListTile( title: Text(e.name), subtitle: Text(e.description), trailing: CategoryChip( category: categories .where((element) => element.id == e.category) .firstOrNull ?? RoomCategory.other(context), ), onTap: () { // create new item and link it to the product // launch edit item screen once done createItem( context, // use productname as item name e.name, e.id); }, )))) ], ))))), ); } }