Skip to content

Commit

Permalink
feat: Add ability to add and remove user resources
Browse files Browse the repository at this point in the history
  • Loading branch information
lsetiawan committed Dec 19, 2024
1 parent 389cc38 commit a370cc8
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 12 deletions.
13 changes: 11 additions & 2 deletions src/support_sphere/lib/data/models/resource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Resource extends Equatable {
this.description = '',
this.qtyNeeded = 0,
this.qtyAvailable = 0,
this.userQuantity = 0,
});

final String id;
Expand All @@ -18,6 +19,7 @@ class Resource extends Equatable {
final String? notes;
final int qtyNeeded;
final int qtyAvailable;
final int userQuantity;
final ResourceTypes resourceType;

@override
Expand All @@ -26,6 +28,11 @@ class Resource extends Equatable {
static Resource fromJson(Map<String, dynamic> json) {
var resourceTypesJson = json['resource_types'];
var resourcesCvJson = json['resources_cv'];
var userQuantity = 0;
if (json['user_resources'].length > 0) {
userQuantity = json['user_resources'].map((userResource) => userResource['quantity']).reduce((a, b) => a + b);
}
var neededQuantity = json['qty_needed'] - userQuantity;
return Resource(
id: resourcesCvJson['id'],
name: resourcesCvJson['name'],
Expand All @@ -36,8 +43,8 @@ class Resource extends Equatable {
description: resourceTypesJson['description']
),
notes: json['notes'],
qtyNeeded: json['qty_needed'],
qtyAvailable: json['qty_available'],
qtyNeeded: neededQuantity < 0 ? 0 : neededQuantity,
qtyAvailable: json['qty_available'] + userQuantity,
);
}

Expand All @@ -48,6 +55,7 @@ class Resource extends Equatable {
String? notes,
int? qtyNeeded,
int? qtyAvailable,
int? userQuantity,
ResourceTypes? resourceType,
}) {
return Resource(
Expand All @@ -56,6 +64,7 @@ class Resource extends Equatable {
description: description ?? this.description,
resourceType: resourceType ?? this.resourceType,
notes: notes ?? this.notes,
userQuantity: userQuantity ?? this.userQuantity,
qtyNeeded: qtyNeeded ?? this.qtyNeeded,
qtyAvailable: qtyAvailable ?? this.qtyAvailable,
);
Expand Down
14 changes: 13 additions & 1 deletion src/support_sphere/lib/data/repositories/resource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ResourceRepository {
}

Future<List<Resource>> getResources() async {
PostgrestList? results = await _resourceService.getResources();
PostgrestList? results = await _resourceService.getAllResources();
return results?.map((data) => Resource.fromJson(data)).toList() ?? [];
}

Expand Down Expand Up @@ -46,4 +46,16 @@ class ResourceRepository {
await _resourceService.deleteResource(id);
await _resourceService.deleteResourceCV(id);
}

Future<void> addToUserInventory(Map<String, dynamic> data) async {
await _resourceService.addUserResource(data);
}

Future<void> deleteUserResource(String id) async {
await _resourceService.deleteUserResource(id);
}

Future<void> markUpToDate(String id, DateTime updated_at) async {
await _resourceService.markUpToDate(id, updated_at);
}
}
37 changes: 36 additions & 1 deletion src/support_sphere/lib/data/services/resource_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,41 @@ class ResourceService {
''');
}

Future<PostgrestList?> getAllResources() async {
return await _supabaseClient.from('resources').select('''
notes,
qty_needed,
qty_available,
resources_cv (
id,
name,
description
),
resource_types (
id,
name,
description
),
user_resources (
quantity
)
''');
}

Future<void> addUserResource(Map<String, dynamic> data) async {
await _supabaseClient.from('user_resources').upsert(data);
}

Future<void> deleteUserResource(String id) async {
await _supabaseClient.from('user_resources').delete().eq('id', id);
}

Future<void> markUpToDate(String id, DateTime updated_at) async {
await _supabaseClient
.from('user_resources')
.update({'updated_at': updated_at.toIso8601String()}).eq('id', id);
}

Future<void> createResourceCV(Map<String, dynamic> data) async {
await _supabaseClient.from('resources_cv').upsert(data);
}
Expand All @@ -75,4 +110,4 @@ class ResourceService {
Future<void> deleteResourceCV(String id) async {
await _supabaseClient.from('resources_cv').delete().eq('id', id);
}
}
}
23 changes: 23 additions & 0 deletions src/support_sphere/lib/logic/cubit/resource_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,27 @@ class ResourceCubit extends Cubit<ResourceState> {
List<UserResource> userResources = await _resourceRepository.getUserResourcesByUserId(userId);
emit(state.copyWith(userResources: userResources));
}

void addToUserInventory(Map<String, dynamic> data) async {
final userId = authUser.uuid;
final payload = {...data, 'user_id': userId};
await _resourceRepository.addToUserInventory(payload);
// Empty the resources list to force a refresh
emit(state.copyWith(resources: []));
fetchUserResources(authUser.uuid);
fetchResources();
}

void deleteUserResource(String id) async {
await _resourceRepository.deleteUserResource(id);
// Empty the resources list to force a refresh
emit(state.copyWith(resources: []));
fetchUserResources(authUser.uuid);
fetchResources();
}

void markUpToDateNow(String id) async {
await _resourceRepository.markUpToDate(id, DateTime.now());
fetchUserResources(authUser.uuid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ class _ManageResourceBodyControllerState
});
}

print("Rebuilding ManageResourceBodyController");

return BlocProvider(
create: (context) => ManageResourceCubit(),
child: (_showingAddResource)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
Expand All @@ -7,6 +8,56 @@ import 'package:support_sphere/data/enums/resource_nav.dart';
import 'package:support_sphere/data/models/resource.dart';
import 'package:support_sphere/logic/cubit/resource_cubit.dart';
import 'package:support_sphere/presentation/components/auth/borders.dart';
import 'package:uuid/v4.dart';

class AddToInventoryFormData extends Equatable {
const AddToInventoryFormData({
this.resourceId,
this.quantity,
// TODO: Implement Subtype
// this.subtype,
this.notes,
});
final String? resourceId;
final int? quantity;
// final String? subtype;
final String? notes;

@override
List<Object?> get props => [
resourceId,
quantity,
// subtype,
notes,
];

copyWith({
String? resourceId,
int? quantity,
// String? subtype,
String? notes,
}) {
return AddToInventoryFormData(
resourceId: resourceId ?? this.resourceId,
quantity: quantity ?? this.quantity,
// subtype: subtype ?? this.subtype,
notes: notes ?? this.notes
);
}

Map<String, dynamic> toJson() {
String now = DateTime.now().toIso8601String();
return {
'id': const UuidV4().generate(),
'resource_id': resourceId,
'quantity': quantity,
// 'subtype': subtype,
'notes': notes,
'created_at': now,
'updated_at': now,
};
}
}

class AddToInventoryForm extends StatefulWidget {
const AddToInventoryForm({super.key, required this.resource});
Expand All @@ -19,6 +70,7 @@ class AddToInventoryForm extends StatefulWidget {

class _AddToInventoryFormState extends State<AddToInventoryForm> {
final _formKey = GlobalKey<FormState>();
AddToInventoryFormData _formData = AddToInventoryFormData();

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -49,6 +101,8 @@ class _AddToInventoryFormState extends State<AddToInventoryForm> {
initialValue: '1',
keyboardType: TextInputType.number,
autovalidateMode: AutovalidateMode.onUserInteraction,
onSaved: (value) => _formData = _formData.copyWith(
quantity: int.tryParse(value ?? '0')),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
FormBuilderValidators.numeric(),
Expand Down Expand Up @@ -80,7 +134,7 @@ class _AddToInventoryFormState extends State<AddToInventoryForm> {
// Resource Notes (Only user and cluster captains can see)
TextFormField(
key: const Key('AddToInventoryForm_notes_textFormField'),
// onSaved: (value) => _formData = _formData.copyWith(notes: value),
onSaved: (value) => _formData = _formData.copyWith(notes: value),
autovalidateMode: AutovalidateMode.onUserInteraction,
keyboardType: TextInputType.multiline,
minLines: 1,
Expand All @@ -101,6 +155,10 @@ class _AddToInventoryFormState extends State<AddToInventoryForm> {
ElevatedButton(onPressed: () {
_formKey.currentState!.save();
if (_formKey.currentState!.validate()) {
_formData = _formData.copyWith(resourceId: resource.id);
context
.read<ResourceCubit>()
.addToUserInventory(_formData.toJson());
context
.read<ResourceCubit>()
.currentNavChanged(ResourceNav.savedResourceInventory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ class ResourceBody extends StatelessWidget {
return BlocProvider(
create: (context) => ResourceCubit(authUser),
child: BlocBuilder<ResourceCubit, ResourceState>(
buildWhen: (previous, current) =>
previous.currentNav != current.currentNav ||
previous.resourceTypes != current.resourceTypes,
// buildWhen: (previous, current) =>
// previous.currentNav != current.currentNav ||
// previous.resourceTypes != current.resourceTypes ||
// previous.resources != current.resources,
builder: (context, state) {
switch (state.currentNav) {
case ResourceNav.showAllResources:
Expand Down Expand Up @@ -148,6 +149,8 @@ class AllResourcesTab extends StatelessWidget {
child: Text("No resources found"),
);
}
// TODO: Figure out how this can be updated as user add and delete resources
// need to somehow fetch the resources and update the state when we tab around
return ListView.builder(
itemCount: state.resources.length,
itemBuilder: (context, index) {
Expand Down Expand Up @@ -356,14 +359,18 @@ class UserResourcesTab extends StatelessWidget {
WidgetStateProperty.all(Colors.greenAccent)),
icon: const FaIcon(FontAwesomeIcons.circleCheck),
iconAlignment: IconAlignment.end,
onPressed: () {},
onPressed: () {
context.read<ResourceCubit>().markUpToDateNow(userResource.id);
},
label: Text("Mark as up to date")),
const SizedBox(height: 8),
ElevatedButton.icon(
style: ButtonStyle(
backgroundColor:
WidgetStateProperty.all(Colors.redAccent)),
onPressed: () {},
onPressed: () {
context.read<ResourceCubit>().deleteUserResource(userResource.id);
},
label: const Text(
"Delete Item",
style: TextStyle(color: Colors.white),
Expand Down

0 comments on commit a370cc8

Please sign in to comment.