Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ plugins {
}

android {
compileSdk = 35
compileSdk = flutter.compileSdkVersion
buildToolsVersion = "35.0.1"
namespace = "edu.BitaZoft.harvest_manager"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
ndkVersion = "29.0.13113456"

Expand Down
46 changes: 46 additions & 0 deletions lib/feature/add-account/models/account_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'package:cloud_firestore/cloud_firestore.dart';

class AccountModel {
final String? id;
final String factoryName;
final String transporterName;
final String accountNumber;
final String route;
final String userId;
final DateTime createdAt;
final bool isActive;

AccountModel({
this.id,
required this.factoryName,
required this.transporterName,
required this.accountNumber,
required this.route,
required this.createdAt,
this.isActive = true,
required this.userId
});

factory AccountModel.fromFirestore(DocumentSnapshot doc){
Map<String, dynamic>data=doc.data() as Map<String, dynamic>;
return AccountModel(factoryName: data['factoryName'] ?? '',
transporterName: data['transporterName'] ?? '',
accountNumber: data['accountNumber'] ?? '',
route: data['route'] ?? '',
userId: data['supplierId'] ?? '',
createdAt: (data['createdAt'] ?? '' as Timestamp?)?.ToDate() ?? DateTime.now(),
isActive: data['isActive'] ?? true,

);
}
Map <String, dynamic> toFirestore(){
return{
'factoryName': factoryName,
'transporterName': transporterName,
'accountNumber': accountNumber,
'route': route,
'createdAt': FieldValue.serverTimestamp(),
'isActive': isActive,
};
}
}
24 changes: 24 additions & 0 deletions lib/feature/add-account/models/factory_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:cloud_firestore/cloud_firestore.dart';

class FactoryModel {
final String id;
final String name;
final String location;
final String contactNumber;

FactoryModel({
required this.id,
required this.name,
required this.location,
required this.contactNumber,
});

factory FactoryModel.fromFirestore(String id, Map<String, dynamic> data){
return FactoryModel(
id: id,
name: data['name'] ?? '',
location: data['location'] ?? '',
contactNumber: data['contactNumber'] ?? '',
);
}
}
24 changes: 24 additions & 0 deletions lib/feature/add-account/models/transporter_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

class TransporterModel {
final String id;
final String name;
final String assignedFactoryId;
final List<String> routes;

TransporterModel({
required this.id,
required this.name,
required this.assignedFactoryId,
required this.routes,
});


factory TransporterModel.fromFirestore(String id, Map<String, dynamic> data) {
return TransporterModel(
id: id,
name: data['fullName'] ?? '',
assignedFactoryId: data['facId'] ?? '',
routes: List<String>.from(data['route'] ?? []),
);
}
}
268 changes: 268 additions & 0 deletions lib/feature/add-account/screens/add_account_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:harvest_manager/shared/widgets/background_template.dart';
import 'package:harvest_manager/feature/add-account/models/factory_model.dart';
import 'package:harvest_manager/feature/add-account/models/transporter_model.dart';
import 'package:harvest_manager/feature/add-account/widgets/form_widgets.dart';
import 'package:harvest_manager/feature/add-account/service/addaccount_service.dart';
import 'package:firebase_auth/firebase_auth.dart';

class AddAccountScreen extends StatefulWidget {
const AddAccountScreen({super.key});

@override
State<AddAccountScreen> createState() => _AddAccountScreenState();
}

class _AddAccountScreenState extends State<AddAccountScreen> {
final AddAccountService _addAccountService = AddAccountService();

String? selectedFactoryId;
String? selectedTransporterId;
String? selectedRoute;



final TextEditingController accountNoController = TextEditingController();

List<FactoryModel> factories = [];
List<TransporterModel> transporters = [];
List<String> availableRoutes = [];

bool isLoadingFactories = true;
bool isLoadingTransporters = false;

@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await fetchFactories();
});
}

Future<void> fetchFactories() async {
setState(() {
isLoadingFactories = true;
});

try {
final fetchedFactories = await _addAccountService.getFactories();
setState(() {
factories = fetchedFactories;
isLoadingFactories = false;
});
} catch (e) {
print('Error fetching factories: $e');
setState(() {
isLoadingFactories = false;
});
}
}

Future<void> fetchTransportersForFactory(String factoryId) async {
setState(() {
isLoadingTransporters = true;
transporters = [];
selectedTransporterId = null;
availableRoutes = [];
});

try {
final fetchedTransporters =
await _addAccountService.getTransportersForFactory(factoryId);
setState(() {
transporters = fetchedTransporters;
isLoadingTransporters = false;
});
} catch (e) {
print('Error fetching transporters: $e');
setState(() {
isLoadingTransporters = false;
});
}
}

Future<void> handleAddAccount() async {
if (selectedFactoryId != null &&
selectedTransporterId != null &&
selectedRoute != null &&
accountNoController.text.isNotEmpty
) {
try {

final String supplierId = FirebaseAuth.instance.currentUser!.uid;

await _addAccountService.addAccount(
factoryId: selectedFactoryId!,
transporterId: selectedTransporterId!,
accountNo: accountNoController.text,
route: selectedRoute!,
userId: supplierId,

);

ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Account successfully added!')),
);

accountNoController.clear();
setState(() {
selectedFactoryId = null;
selectedTransporterId = null;
selectedRoute = null;
transporters = [];
availableRoutes = [];
});
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed to add account.')),
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please complete all fields')),
);
}
}

@override
Widget build(BuildContext context) {
return BackgroundTemplate(
child: Padding(
padding: const EdgeInsets.only(bottom: 100.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset("assets/images/teacup.png", height: 60, width: 60),
Expanded(
child: Center(
child: Text(
"Add Accounts",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(33, 33, 33, 1),
),
),
),
),
IconButton(
icon: Icon(Icons.notifications_none, color: Colors.black),
onPressed: () {},
),
],
),
const SizedBox(height: 20),

buildLabel('Name of the Factory'),
isLoadingFactories
? const Center(child: CircularProgressIndicator())
: buildDropdown<String>(
value: selectedFactoryId,
hint: 'Select Factory',
items: factories.map((factory) {
return DropdownMenuItem(
value: factory.id,
child: Text(factory.name),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedFactoryId = value;
});
if (value != null) {
fetchTransportersForFactory(value);
}
},
),
const SizedBox(height: 16),

buildLabel('Transporter Name'),
isLoadingTransporters
? const Center(child: CircularProgressIndicator())
: buildDropdown<String>(
value: selectedTransporterId,
hint: 'Select Transporter',
items: transporters.map((transporter) {
return DropdownMenuItem(
value: transporter.id,
child: Text(transporter.name),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedTransporterId = value;
final selected = transporters.firstWhere(
(t) => t.id == value,
orElse: () => TransporterModel(
id: '',
name: '',
assignedFactoryId: '',
routes: [],
),
);
availableRoutes = selected.routes;
selectedRoute = null;
});
},
),
const SizedBox(height: 16),

buildLabel('Account No.'),
buildTextField(
hint: 'Enter Account No',
controller: accountNoController,
),
const SizedBox(height: 16),

buildLabel('Routes'),
buildDropdown<String>(
value: selectedRoute,
hint: 'Select Route',
items: availableRoutes.map((route) {
return DropdownMenuItem(
value: route,
child: Text(route),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedRoute = value;
});
},
),

const SizedBox(height: 48),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: handleAddAccount,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: const Text(
"Add Account",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
)
],
),
),
),
);
}
}
Loading