From 791201a1887340e3f6b12618d9ce8e7ff2697a0d Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Wed, 23 Oct 2024 20:35:49 -0400 Subject: [PATCH 1/3] Display and edit item notes field --- apps/api/apps/librarian/routes/inventory.js | 8 +-- apps/api/services/inventory/mapItem.js | 2 +- apps/api/services/inventory/service.js | 12 ++-- apps/librarian/lib/core/api/inventory.dart | 8 +-- .../lib/core/api/models/item_model.dart | 6 +- .../lib/core/data/inventory_repository.dart | 8 +-- .../inventory/create_items/create_items.dart | 2 +- .../create_items/create_items_controller.dart | 4 +- .../item_details/condition_dropdown.dart | 1 + .../inventory/item_details/item_details.dart | 66 ++++++++++++------- .../item_details/item_details_controller.dart | 13 ++-- 11 files changed, 75 insertions(+), 55 deletions(-) diff --git a/apps/api/apps/librarian/routes/inventory.js b/apps/api/apps/librarian/routes/inventory.js index 5e6ba38..cb1e99c 100644 --- a/apps/api/apps/librarian/routes/inventory.js +++ b/apps/api/apps/librarian/routes/inventory.js @@ -22,10 +22,10 @@ router.get('/:id', async (req, res) => { }); router.put('/', async (req, res) => { - const { thingId, quantity, brand, condition, description, estimatedValue, hidden, image, manuals } = req.body; + const { thingId, quantity, brand, condition, notes, estimatedValue, hidden, image, manuals } = req.body; try { - res.send(await createItems(thingId, { quantity, brand, condition, description, estimatedValue, hidden, image, manuals })); + res.send(await createItems(thingId, { quantity, brand, condition, notes, estimatedValue, hidden, image, manuals })); } catch (error) { console.error(error); res.status(error.status || 500).send({ errors: [error] }); @@ -33,10 +33,10 @@ router.put('/', async (req, res) => { }); router.patch('/:id', async (req, res) => { - const { brand, description, estimatedValue, hidden, condition, image, manuals } = req.body; + const { brand, notes, estimatedValue, hidden, condition, image, manuals } = req.body; try { - await updateItem(req.params.id, { brand, description, estimatedValue, hidden, condition, image, manuals }); + await updateItem(req.params.id, { brand, notes, estimatedValue, hidden, condition, image, manuals }); res.status(204).send(); } catch (error) { console.error(error); diff --git a/apps/api/services/inventory/mapItem.js b/apps/api/services/inventory/mapItem.js index 3490c94..28d2622 100644 --- a/apps/api/services/inventory/mapItem.js +++ b/apps/api/services/inventory/mapItem.js @@ -13,7 +13,7 @@ function mapItem(record) { && !isThingHidden, hidden: hidden || isThingHidden, brand: record.get('Brand'), - description: record.get('Description'), + notes: record.get('Notes'), dueBack: record.get('Due Back')?.[0], estimatedValue: record.get('Estimated Value'), eyeProtection: Boolean(record.get('Eye Protection')), diff --git a/apps/api/services/inventory/service.js b/apps/api/services/inventory/service.js index cc94067..3b1153e 100644 --- a/apps/api/services/inventory/service.js +++ b/apps/api/services/inventory/service.js @@ -7,7 +7,7 @@ const inventoryFields = [ 'Thing', 'Name', 'Brand', - 'Description', + 'Notes', 'Due Back', 'Eye Protection', 'Active Loans', @@ -53,13 +53,13 @@ const fetchItem = async (id, { recordId } = { recordId: undefined }) => { return mapItem(records[0]); } -const createItems = async (thingId, { quantity, brand, description, estimatedValue, hidden, condition, image, manuals }) => { +const createItems = async (thingId, { quantity, brand, notes, estimatedValue, hidden, condition, image, manuals }) => { const inventoryData = Array.from(Array(Number(quantity))).map(() => ({ fields: { 'Thing': [thingId], 'Brand': brand, 'Condition': condition, - 'Description': description, + 'Notes': notes, 'Estimated Value': Number(estimatedValue), 'Hidden': hidden, 'Picture': image?.url ? [{ url: image.url }] : [], @@ -71,15 +71,15 @@ const createItems = async (thingId, { quantity, brand, description, estimatedVal return records.map(mapItem); } -const updateItem = async (id, { brand, description, estimatedValue, hidden, condition, image, manuals }) => { +const updateItem = async (id, { brand, notes, estimatedValue, hidden, condition, image, manuals }) => { let updatedFields = {}; if (brand !== null) { updatedFields['Brand'] = brand; } - if (description !== null) { - updatedFields['Description'] = description; + if (notes !== null) { + updatedFields['Notes'] = notes; } if (estimatedValue !== null) { diff --git a/apps/librarian/lib/core/api/inventory.dart b/apps/librarian/lib/core/api/inventory.dart index 25f0057..a4f500a 100644 --- a/apps/librarian/lib/core/api/inventory.dart +++ b/apps/librarian/lib/core/api/inventory.dart @@ -13,7 +13,7 @@ Future createInventoryItems( required int quantity, required String? brand, String? condition, - required String? description, + required String? notes, required double? estimatedValue, bool? hidden, ImageDTO? image, @@ -24,7 +24,7 @@ Future createInventoryItems( 'quantity': quantity, 'brand': brand, 'condition': condition, - 'description': description, + 'notes': notes, 'estimatedValue': estimatedValue, 'hidden': hidden, 'image': { @@ -38,7 +38,7 @@ Future updateInventoryItem( String id, { String? brand, String? condition, - String? description, + String? notes, double? estimatedValue, bool? hidden, ImageDTO? image, @@ -47,7 +47,7 @@ Future updateInventoryItem( return await DioClient.instance.patch('/inventory/$id', data: { 'brand': brand, 'condition': condition, - 'description': description, + 'notes': notes, 'estimatedValue': estimatedValue, 'hidden': hidden, 'image': image != null ? {'url': image.url} : null, diff --git a/apps/librarian/lib/core/api/models/item_model.dart b/apps/librarian/lib/core/api/models/item_model.dart index fe271be..47300dd 100644 --- a/apps/librarian/lib/core/api/models/item_model.dart +++ b/apps/librarian/lib/core/api/models/item_model.dart @@ -15,7 +15,7 @@ class ItemModel { required this.linkedThingIds, this.brand, this.condition, - this.description, + this.notes, this.estimatedValue, this.location, }); @@ -24,7 +24,7 @@ class ItemModel { final String thingId; final int number; final String name; - final String? description; + final String? notes; final String? brand; final String? condition; final String? location; @@ -48,7 +48,7 @@ class ItemModel { thingId: json['thingId'] as String, number: json['number'] as int, name: json['name'] as String? ?? 'Unknown Thing', - description: json['description'] as String?, + notes: json['notes'] as String?, available: json['available'] as bool, hidden: json['hidden'] as bool, totalLoans: json['totalLoans'] as int, diff --git a/apps/librarian/lib/core/data/inventory_repository.dart b/apps/librarian/lib/core/data/inventory_repository.dart index 11fbb60..60b5b6f 100644 --- a/apps/librarian/lib/core/data/inventory_repository.dart +++ b/apps/librarian/lib/core/data/inventory_repository.dart @@ -129,7 +129,7 @@ class InventoryRepository extends Notifier>> { required int quantity, required String? brand, required String? condition, - required String? description, + required String? notes, required double? estimatedValue, required bool? hidden, required UpdatedImageModel? image, @@ -146,7 +146,7 @@ class InventoryRepository extends Notifier>> { quantity: quantity, brand: brand, condition: condition, - description: description, + notes: notes, estimatedValue: estimatedValue, hidden: hidden, image: image == null ? null : api.ImageDTO(url: imageUrl), @@ -158,7 +158,7 @@ class InventoryRepository extends Notifier>> { Future updateItem( String id, { String? brand, - String? description, + String? notes, String? condition, double? estimatedValue, bool? hidden, @@ -175,7 +175,7 @@ class InventoryRepository extends Notifier>> { id, brand: brand, condition: condition, - description: description, + notes: notes, estimatedValue: estimatedValue, hidden: hidden, image: image == null ? null : api.ImageDTO(url: imageUrl), diff --git a/apps/librarian/lib/modules/things/details/inventory/create_items/create_items.dart b/apps/librarian/lib/modules/things/details/inventory/create_items/create_items.dart index 5ab1ea9..0befc1b 100644 --- a/apps/librarian/lib/modules/things/details/inventory/create_items/create_items.dart +++ b/apps/librarian/lib/modules/things/details/inventory/create_items/create_items.dart @@ -78,7 +78,7 @@ class CreateItems extends ConsumerWidget { ), const SizedBox(height: 16), TextFormField( - controller: controller.descriptionController, + controller: controller.notesController, decoration: inputDecoration.copyWith(labelText: 'Description'), enabled: !controller.isLoading, ), diff --git a/apps/librarian/lib/modules/things/details/inventory/create_items/create_items_controller.dart b/apps/librarian/lib/modules/things/details/inventory/create_items/create_items_controller.dart index 3b05212..f7ed81d 100644 --- a/apps/librarian/lib/modules/things/details/inventory/create_items/create_items_controller.dart +++ b/apps/librarian/lib/modules/things/details/inventory/create_items/create_items_controller.dart @@ -27,7 +27,7 @@ class CreateItemsController extends ChangeNotifier { late final brandController = TextEditingController() ..addListener(notifyListeners); - late final descriptionController = TextEditingController() + late final notesController = TextEditingController() ..addListener(notifyListeners); late final estimatedValueController = TextEditingController() @@ -105,7 +105,7 @@ class CreateItemsController extends ChangeNotifier { quantity: quantity, brand: brandController.text, condition: conditionNotifier.value, - description: descriptionController.text, + notes: notesController.text, estimatedValue: estimatedValue, hidden: hiddenNotifier.value, image: createUpdatedImageModel(), diff --git a/apps/librarian/lib/modules/things/details/inventory/item_details/condition_dropdown.dart b/apps/librarian/lib/modules/things/details/inventory/item_details/condition_dropdown.dart index b37ac2e..102982e 100644 --- a/apps/librarian/lib/modules/things/details/inventory/item_details/condition_dropdown.dart +++ b/apps/librarian/lib/modules/things/details/inventory/item_details/condition_dropdown.dart @@ -50,6 +50,7 @@ class ConditionDropdown extends StatelessWidget { Widget build(BuildContext context) { return DropdownButtonFormField( decoration: const InputDecoration( + border: OutlineInputBorder(), labelText: 'Condition', ), items: editable diff --git a/apps/librarian/lib/modules/things/details/inventory/item_details/item_details.dart b/apps/librarian/lib/modules/things/details/inventory/item_details/item_details.dart index 607af1c..019500d 100644 --- a/apps/librarian/lib/modules/things/details/inventory/item_details/item_details.dart +++ b/apps/librarian/lib/modules/things/details/inventory/item_details/item_details.dart @@ -68,19 +68,40 @@ class ItemDetails extends ConsumerWidget { value: controller.conditionNotifier.value, ), ), - _HiddenCheckboxListTile( - isItemDamaged: _isItemDamaged, - isThingHidden: isThingHidden, - isManagedByPartner: item.isManagedByPartner, - value: controller.hiddenNotifier.value, - onChanged: (value) { - controller.hiddenNotifier.value = value ?? false; - }, + const Divider(height: 1), + Padding( + padding: const EdgeInsets.all(16.0), + child: TextFormField( + controller: controller.notesController, + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Needs a new part installed.', + labelText: 'Notes', + ), + enabled: !controller.isLoading, + maxLines: 128, + minLines: 3, + ), ), ], ), ), const SizedBox(height: 32), + Card( + clipBehavior: Clip.antiAlias, + elevation: isMobile(context) ? 1 : 0, + margin: EdgeInsets.zero, + child: _HiddenCheckboxListTile( + isItemDamaged: _isItemDamaged, + isThingHidden: isThingHidden, + isManagedByPartner: item.isManagedByPartner, + value: controller.hiddenNotifier.value, + onChanged: (value) { + controller.hiddenNotifier.value = value ?? false; + }, + ), + ), + const SizedBox(height: 32), Card( clipBehavior: Clip.antiAlias, elevation: isMobile(context) ? 1 : 0, @@ -102,14 +123,18 @@ class ItemDetails extends ConsumerWidget { readOnly: true, controller: controller.nameController, decoration: InputDecoration( + border: const OutlineInputBorder(), labelText: 'Thing', - suffix: Tooltip( - message: 'Convert', - child: IconButton( - onPressed: () { - controller.convertThing(context); - }, - icon: const Icon(convertIcon), + suffixIcon: Padding( + padding: const EdgeInsets.only(right: 8), + child: Tooltip( + message: 'Convert', + child: IconButton( + onPressed: () { + controller.convertThing(context); + }, + icon: const Icon(convertIcon), + ), ), ), ), @@ -119,23 +144,17 @@ class ItemDetails extends ConsumerWidget { TextFormField( controller: controller.brandController, decoration: const InputDecoration( + border: OutlineInputBorder(), labelText: 'Brand', hintText: 'Generic', ), enabled: !controller.isLoading, ), const SizedBox(height: 16), - TextFormField( - controller: controller.descriptionController, - decoration: const InputDecoration( - labelText: 'Description', - ), - enabled: !controller.isLoading, - ), - const SizedBox(height: 16), TextFormField( controller: controller.estimatedValueController, decoration: const InputDecoration( + border: OutlineInputBorder(), labelText: 'Estimated Value (\$)', prefixText: '\$ ', ), @@ -148,6 +167,7 @@ class ItemDetails extends ConsumerWidget { const SizedBox(height: 16), TextFormField( decoration: const InputDecoration( + border: OutlineInputBorder(), labelText: 'Location', ), enabled: false, diff --git a/apps/librarian/lib/modules/things/details/inventory/item_details/item_details_controller.dart b/apps/librarian/lib/modules/things/details/inventory/item_details/item_details_controller.dart index a17bff9..135f4ec 100644 --- a/apps/librarian/lib/modules/things/details/inventory/item_details/item_details_controller.dart +++ b/apps/librarian/lib/modules/things/details/inventory/item_details/item_details_controller.dart @@ -27,7 +27,7 @@ class ItemDetailsController extends ChangeNotifier { late TextEditingController nameController; late ValueNotifier hiddenNotifier; late TextEditingController brandController; - late TextEditingController descriptionController; + late TextEditingController notesController; late TextEditingController estimatedValueController; late ValueNotifier conditionNotifier; late ValueNotifier> manualsNotifier; @@ -45,8 +45,7 @@ class ItemDetailsController extends ChangeNotifier { nameController = TextEditingController(text: item!.name); hiddenNotifier = ValueNotifier(false)..addListener(notifyListeners); brandController = TextEditingController()..addListener(notifyListeners); - descriptionController = TextEditingController() - ..addListener(notifyListeners); + notesController = TextEditingController()..addListener(notifyListeners); estimatedValueController = TextEditingController() ..addListener(notifyListeners); conditionNotifier = ValueNotifier(null)..addListener(notifyListeners); @@ -58,8 +57,8 @@ class ItemDetailsController extends ChangeNotifier { brandController.text = item!.brand!; } - if (item?.description != null) { - descriptionController.text = item!.description!; + if (item?.notes != null) { + notesController.text = item!.notes!; } final estimatedValue = formatNumber(item?.estimatedValue); @@ -163,7 +162,7 @@ class ItemDetailsController extends ChangeNotifier { await repository?.updateItem( item!.id, brand: brandController.text, - description: descriptionController.text, + notes: notesController.text, condition: conditionNotifier.value, estimatedValue: estimatedValue, hidden: hiddenNotifier.value, @@ -226,7 +225,7 @@ class ItemDetailsController extends ChangeNotifier { !listEquals(manualsNotifier.value, _originalManuals) || hiddenNotifier.value != (item?.hidden ?? false) || brandController.text != (item?.brand ?? '') || - descriptionController.text != (item?.description ?? '') || + notesController.text != (item?.notes ?? '') || estimatedValueController.text != (formatNumber(item?.estimatedValue) ?? '') || conditionNotifier.value != item?.condition || From 3b855e3c94fe8966dbcb144b682ba74e11f1077e Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Wed, 23 Oct 2024 20:58:24 -0400 Subject: [PATCH 2/3] Bump package versions --- apps/api/package.json | 2 +- apps/librarian/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index 5ff363a..da3bc79 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -1,6 +1,6 @@ { "name": "pvdthings-api", - "version": "1.21.2", + "version": "1.21.3", "description": "", "main": "server.js", "scripts": { diff --git a/apps/librarian/pubspec.yaml b/apps/librarian/pubspec.yaml index e17303c..0b686ab 100644 --- a/apps/librarian/pubspec.yaml +++ b/apps/librarian/pubspec.yaml @@ -10,7 +10,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. -version: 1.0.0+19 +version: 1.0.0+20 environment: sdk: '>=3.0.0' From 616fc697414ae352ce1d35f3df5f1747df9fcea7 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Wed, 23 Oct 2024 21:39:23 -0400 Subject: [PATCH 3/3] Display repair item notes on hover --- .../lib/modules/things/maintenance/view.dart | 39 ++++++++++++++----- apps/librarian/pubspec.lock | 24 ++++++------ 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/apps/librarian/lib/modules/things/maintenance/view.dart b/apps/librarian/lib/modules/things/maintenance/view.dart index 8a5024b..63c6bcc 100644 --- a/apps/librarian/lib/modules/things/maintenance/view.dart +++ b/apps/librarian/lib/modules/things/maintenance/view.dart @@ -105,13 +105,15 @@ class KanbanColumn extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: GridView.count( crossAxisCount: 4, - children: items - .map((item) => ItemCard( - number: item.item.number, - imageUrl: item.item.imageUrls.firstOrNull, - onTap: () => onTapItem?.call(item), - )) - .toList(), + children: items.map((model) { + final item = model.item; + return ItemCard( + number: item.number, + imageUrl: item.imageUrls.firstOrNull, + notes: item.notes, + onTap: () => onTapItem?.call(model), + ); + }).toList(), ), ), ), @@ -126,11 +128,13 @@ class ItemCard extends StatelessWidget { super.key, required this.number, this.imageUrl, + this.notes, this.onTap, }); final int number; final String? imageUrl; + final String? notes; final void Function()? onTap; @override @@ -156,9 +160,24 @@ class ItemCard extends StatelessWidget { ), Padding( padding: const EdgeInsets.all(8.0), - child: Text( - '#$number', - style: Theme.of(context).textTheme.titleMedium, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '#$number', + style: Theme.of(context).textTheme.titleMedium, + ), + if (notes != null) + Tooltip( + message: '#$number: $notes', + textStyle: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(color: Colors.black, fontSize: 18), + child: const Icon(Icons.info), + ), + ], ), ), ], diff --git a/apps/librarian/pubspec.lock b/apps/librarian/pubspec.lock index 0d9db04..eaf218d 100644 --- a/apps/librarian/pubspec.lock +++ b/apps/librarian/pubspec.lock @@ -452,18 +452,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -500,18 +500,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" mime: dependency: transitive description: @@ -817,10 +817,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.2" timing: dependency: transitive description: @@ -921,10 +921,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.5" watcher: dependency: transitive description: