Done Category, Product Catalogue, Customer, Vendor, Purchase Invoice Module
This commit is contained in:
211
scratch/rewrite_product_detail.py
Normal file
211
scratch/rewrite_product_detail.py
Normal file
@@ -0,0 +1,211 @@
|
||||
import os
|
||||
|
||||
file_path = "/Users/maddy/Projects/Kifi/kifi-app/lib/features/inventory/presentation/product_detail_screen.dart"
|
||||
|
||||
content = """import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:kifi_app/features/inventory/providers/products_provider.dart';
|
||||
import 'package:kifi_app/core/network/dio_client.dart';
|
||||
import 'package:kifi_app/features/inventory/domain/product.dart';
|
||||
import 'package:kifi_app/features/inventory/presentation/add_product_screen.dart';
|
||||
import 'package:kifi_app/features/inventory/presentation/stock_ledger_tab.dart';
|
||||
import 'package:kifi_app/features/inventory/presentation/widgets/adjust_stock_sheet.dart';
|
||||
|
||||
class ProductDetailScreen extends ConsumerWidget {
|
||||
final Product product;
|
||||
|
||||
const ProductDetailScreen({super.key, required this.product});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// Watch products to get latest updates (like stock changes)
|
||||
final productsState = ref.watch(productsProvider);
|
||||
final currentProduct = productsState.value?.firstWhere((p) => p.id == product.id, orElse: () => product) ?? product;
|
||||
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.grey[50],
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.white,
|
||||
foregroundColor: Colors.black,
|
||||
title: Text(currentProduct.name, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.black),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => AddProductScreen(product: currentProduct),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
bottom: const TabBar(
|
||||
labelColor: Colors.blue,
|
||||
unselectedLabelColor: Colors.grey,
|
||||
indicatorColor: Colors.blue,
|
||||
tabs: [
|
||||
Tab(text: "Overview"),
|
||||
Tab(text: "Stock Ledger"),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: TabBarView(
|
||||
children: [
|
||||
_buildOverviewTab(context, currentProduct, ref),
|
||||
StockLedgerTab(productId: currentProduct.id!),
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (context) => AdjustStockSheet(productId: currentProduct.id!),
|
||||
);
|
||||
},
|
||||
backgroundColor: Colors.blue,
|
||||
icon: const Icon(Icons.inventory),
|
||||
label: const Text("Adjust Stock"),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOverviewTab(BuildContext context, Product p, WidgetRef ref) {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Image Header
|
||||
if (p.imageIds.isNotEmpty)
|
||||
Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.grey[200],
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: FutureBuilder<String?>(
|
||||
future: DioClient().storage.read(key: 'jwt_token'),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
final token = snapshot.data;
|
||||
if (token == null) {
|
||||
return const Icon(Icons.image, size: 50, color: Colors.grey);
|
||||
}
|
||||
return Image.network(
|
||||
'${DioClient().dio.options.baseUrl}/inventory/products/${p.id}/images/${p.imageIds.first}/content',
|
||||
fit: BoxFit.cover,
|
||||
headers: {'Authorization': 'Bearer $token'},
|
||||
errorBuilder: (context, error, stackTrace) => const Icon(Icons.image, size: 50, color: Colors.grey),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Stock Summary Card
|
||||
Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(Icons.inventory_2, color: Colors.blue),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Current Stock", style: TextStyle(color: Colors.grey[600], fontSize: 14)),
|
||||
Text(
|
||||
"${p.currentStock ?? 0}",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 24),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Details Card
|
||||
Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Metal Details", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
|
||||
const Divider(),
|
||||
_buildDetailRow("SKU / HUID", p.sku ?? "-"),
|
||||
_buildDetailRow("Gross Weight", "${p.weight ?? 0} g"),
|
||||
_buildDetailRow("Purity Factor", "${p.purityFactor ?? 1.0}"),
|
||||
_buildDetailRow("Wastage", "${p.wastagePercentage ?? 0}%"),
|
||||
_buildDetailRow("Net Weight", "${(p.weight ?? 0) * (1 - (p.wastagePercentage ?? 0) / 100)} g"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
// Pricing Card
|
||||
Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Pricing Details", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
|
||||
const Divider(),
|
||||
_buildDetailRow("Making Charges", "₹${p.makingCharges?.toStringAsFixed(2) ?? '0.00'} (${p.makingChargesType})"),
|
||||
_buildDetailRow("HSN Code", p.hsnCode ?? "-"),
|
||||
_buildDetailRow("GST Rate", "${p.gstRate?.toStringAsFixed(1) ?? '0'}%"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailRow(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(label, style: TextStyle(color: Colors.grey[600])),
|
||||
Text(value, style: const TextStyle(fontWeight: FontWeight.w500)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
with open(file_path, "w") as f:
|
||||
f.write(content)
|
||||
Reference in New Issue
Block a user