feat(validation): add garage-side community confirmation action
This commit is contained in:
parent
b26bcf6226
commit
d3f6fc3853
1 changed files with 57 additions and 1 deletions
|
|
@ -93,7 +93,7 @@ class GarageScreenState extends State<GarageScreen> {
|
||||||
final data = await supabase
|
final data = await supabase
|
||||||
.from('hotwheels')
|
.from('hotwheels')
|
||||||
.select(
|
.select(
|
||||||
'id, created_at, hw_id, notes, user_image_url, global_cars(name, series, year, color)')
|
'id, created_at, hw_id, notes, user_image_url, global_cars(name, series, year, color, is_verified, confirmation_count)')
|
||||||
.eq('collection_id', widget.collectionId)
|
.eq('collection_id', widget.collectionId)
|
||||||
.order('created_at', ascending: false)
|
.order('created_at', ascending: false)
|
||||||
.range(from, to);
|
.range(from, to);
|
||||||
|
|
@ -476,6 +476,8 @@ class GarageScreenState extends State<GarageScreen> {
|
||||||
final name = global?['name'] as String?;
|
final name = global?['name'] as String?;
|
||||||
final series = global?['series'] as String?;
|
final series = global?['series'] as String?;
|
||||||
final year = global?['year'] as int?;
|
final year = global?['year'] as int?;
|
||||||
|
final verified = global?['is_verified'] == true;
|
||||||
|
final confirmations = (global?['confirmation_count'] as num?)?.toInt() ?? 0;
|
||||||
final notes = car['notes'] as String?;
|
final notes = car['notes'] as String?;
|
||||||
final imageUrl = car['signed_image_url'] as String?;
|
final imageUrl = car['signed_image_url'] as String?;
|
||||||
|
|
||||||
|
|
@ -597,11 +599,35 @@ class GarageScreenState extends State<GarageScreen> {
|
||||||
_DetailRow(icon: Icons.collections, label: 'Series', value: series),
|
_DetailRow(icon: Icons.collections, label: 'Series', value: series),
|
||||||
if (year != null)
|
if (year != null)
|
||||||
_DetailRow(icon: Icons.calendar_today, label: 'Year', value: '$year'),
|
_DetailRow(icon: Icons.calendar_today, label: 'Year', value: '$year'),
|
||||||
|
_DetailRow(
|
||||||
|
icon: verified ? Icons.verified : Icons.hourglass_bottom,
|
||||||
|
label: 'Validation',
|
||||||
|
value: verified
|
||||||
|
? 'Verified by community'
|
||||||
|
: 'Pending verification',
|
||||||
|
),
|
||||||
|
_DetailRow(
|
||||||
|
icon: Icons.how_to_vote,
|
||||||
|
label: 'Confirmations',
|
||||||
|
value: '$confirmations',
|
||||||
|
),
|
||||||
if (notes != null && notes.isNotEmpty)
|
if (notes != null && notes.isNotEmpty)
|
||||||
_DetailRow(icon: Icons.notes, label: 'Notes', value: notes),
|
_DetailRow(icon: Icons.notes, label: 'Notes', value: notes),
|
||||||
|
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
|
if (!verified) ...[
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: OutlinedButton.icon(
|
||||||
|
onPressed: () => _confirmCatalogEntry(hwId, context),
|
||||||
|
icon: const Icon(Icons.thumb_up_alt_outlined, size: 18),
|
||||||
|
label: const Text('Confirm Catalog Entry'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
],
|
||||||
|
|
||||||
// Edit & Delete buttons
|
// Edit & Delete buttons
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -730,6 +756,36 @@ class GarageScreenState extends State<GarageScreen> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _confirmCatalogEntry(String hwId, BuildContext sheetContext) async {
|
||||||
|
final user = supabase.auth.currentUser;
|
||||||
|
if (user == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final existingVote = await supabase
|
||||||
|
.from('car_votes')
|
||||||
|
.select('id')
|
||||||
|
.eq('hw_id', hwId)
|
||||||
|
.eq('user_id', user.id)
|
||||||
|
.maybeSingle();
|
||||||
|
|
||||||
|
if (existingVote != null) {
|
||||||
|
showGlobalSnackBar('You already confirmed this catalog entry.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await supabase.from('car_votes').insert({
|
||||||
|
'hw_id': hwId,
|
||||||
|
'user_id': user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
showGlobalSnackBar('Thanks! Your validation vote was recorded.');
|
||||||
|
if (sheetContext.mounted) Navigator.pop(sheetContext);
|
||||||
|
_loadCars(reset: true);
|
||||||
|
} catch (e) {
|
||||||
|
showGlobalSnackBar('Failed to submit validation vote: $e', isError: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<String?> _pickTargetCollection() async {
|
Future<String?> _pickTargetCollection() async {
|
||||||
final collections = await CollectionService.getMyCollections();
|
final collections = await CollectionService.getMyCollections();
|
||||||
if (!mounted) return null;
|
if (!mounted) return null;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue