first commit
This commit is contained in:
142
lib/Screens/product_brand/add_brans.dart
Normal file
142
lib/Screens/product_brand/add_brans.dart
Normal file
@@ -0,0 +1,142 @@
|
||||
// ignore_for_file: unused_result
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mobile_pos/constant.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as lang;
|
||||
|
||||
import '../../GlobalComponents/glonal_popup.dart';
|
||||
import '../../http_client/custome_http_client.dart';
|
||||
import '../../service/check_user_role_permission_provider.dart';
|
||||
import '../product_brand/model/brands_model.dart';
|
||||
import 'brand repo/brand_repo.dart';
|
||||
|
||||
class AddBrands extends StatefulWidget {
|
||||
const AddBrands({super.key, this.brand});
|
||||
|
||||
final Brand? brand;
|
||||
|
||||
@override
|
||||
// ignore: library_private_types_in_public_api
|
||||
_AddBrandsState createState() => _AddBrandsState();
|
||||
}
|
||||
|
||||
class _AddBrandsState extends State<AddBrands> {
|
||||
bool showProgress = false;
|
||||
TextEditingController brandController = TextEditingController();
|
||||
|
||||
final GlobalKey<FormState> _key = GlobalKey();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
widget.brand != null ? brandController.text = widget.brand?.brandName ?? '' : null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _theme = Theme.of(context);
|
||||
return Consumer(builder: (context, ref, __) {
|
||||
final permissionService = PermissionService(ref);
|
||||
return GlobalPopup(
|
||||
child: Scaffold(
|
||||
backgroundColor: kWhite,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
lang.S.of(context).addBrand,
|
||||
),
|
||||
iconTheme: const IconThemeData(color: Colors.black),
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.white,
|
||||
elevation: 0.0,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Visibility(
|
||||
visible: showProgress,
|
||||
child: const CircularProgressIndicator(
|
||||
color: kMainColor,
|
||||
strokeWidth: 5.0,
|
||||
),
|
||||
),
|
||||
Form(
|
||||
key: _key,
|
||||
child: TextFormField(
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
// return 'Please enter a valid brand name';
|
||||
return lang.S.of(context).pleaseEnterAValidBrandName;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
controller: brandController,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
// hintText: 'Enter a brand name',
|
||||
hintText: lang.S.of(context).enterABrandName,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
labelText: lang.S.of(context).brandName,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
maximumSize: const Size(double.infinity, 48),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
disabledBackgroundColor: _theme.colorScheme.primary.withValues(alpha: 0.15),
|
||||
),
|
||||
onPressed: () async {
|
||||
if (widget.brand == null) {
|
||||
if (!permissionService.hasPermission(Permit.brandsCreate.value)) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
backgroundColor: Colors.red,
|
||||
content: Text('You do not have permission to create brand'),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!permissionService.hasPermission(Permit.brandsUpdate.value)) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
backgroundColor: Colors.red,
|
||||
content: Text('You do not have permission to update brand'),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_key.currentState!.validate()) {
|
||||
BrandsRepo brandRepo = BrandsRepo();
|
||||
widget.brand == null
|
||||
? await brandRepo.addBrand(ref: ref, context: context, name: brandController.text)
|
||||
: await brandRepo.editBrand(ref: ref, id: widget.brand?.id ?? 0, context: context, name: brandController.text);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
lang.S.of(context).save,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: _theme.textTheme.bodyMedium?.copyWith(
|
||||
color: _theme.colorScheme.primaryContainer,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
151
lib/Screens/product_brand/brand repo/brand_repo.dart
Normal file
151
lib/Screens/product_brand/brand repo/brand_repo.dart
Normal file
@@ -0,0 +1,151 @@
|
||||
//ignore_for_file: unused_local_variable
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../Const/api_config.dart';
|
||||
import '../../../Repository/constant_functions.dart';
|
||||
import '../../../http_client/custome_http_client.dart';
|
||||
import '../../../http_client/customer_http_client_get.dart';
|
||||
import '../model/brands_model.dart';
|
||||
import '../product_brand_provider/product_brand_provider.dart';
|
||||
|
||||
class BrandsRepo {
|
||||
Future<List<Brand>> fetchAllBrands() async {
|
||||
CustomHttpClientGet clientGet = CustomHttpClientGet(client: http.Client());
|
||||
final uri = Uri.parse('${APIConfig.url}/brands');
|
||||
|
||||
try {
|
||||
final response = await clientGet.get(url: uri);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final parsedData = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
final categoryList = parsedData['data'] as List<dynamic>;
|
||||
return categoryList.map((category) => Brand.fromJson(category)).toList();
|
||||
} else {
|
||||
throw Exception('Failed to fetch brands: ${response.statusCode}');
|
||||
}
|
||||
} catch (error) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addBrand({
|
||||
required WidgetRef ref,
|
||||
required BuildContext context,
|
||||
required String name,
|
||||
}) async {
|
||||
final uri = Uri.parse('${APIConfig.url}/brands');
|
||||
|
||||
try {
|
||||
CustomHttpClient customHttpClient = CustomHttpClient(client: http.Client(), context: context, ref: ref);
|
||||
var responseData = await customHttpClient.post(
|
||||
url: uri,
|
||||
body: {
|
||||
'brandName': name,
|
||||
},
|
||||
);
|
||||
final parsedData = jsonDecode(responseData.body);
|
||||
|
||||
if (responseData.statusCode == 200) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Added successful!')));
|
||||
var data1 = ref.refresh(brandsProvider);
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Brand creation failed: ${parsedData['message']}')));
|
||||
}
|
||||
} catch (error) {
|
||||
// Handle unexpected errors gracefully
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('An error occurred: $error')));
|
||||
}
|
||||
}
|
||||
|
||||
Future<num?> addBrandForBulkUpload({
|
||||
required String name,
|
||||
}) async {
|
||||
final uri = Uri.parse('${APIConfig.url}/brands');
|
||||
|
||||
try {
|
||||
var responseData = await http.post(uri, headers: {
|
||||
"Accept": 'application/json',
|
||||
'Authorization': await getAuthToken(),
|
||||
}, body: {
|
||||
'brandName': name,
|
||||
});
|
||||
final parsedData = jsonDecode(responseData.body);
|
||||
|
||||
if (responseData.statusCode == 200) {
|
||||
return parsedData['data']['id'];
|
||||
}
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
///_________Edit_brand_________________________
|
||||
Future<void> editBrand({
|
||||
required WidgetRef ref,
|
||||
required BuildContext context,
|
||||
required num id,
|
||||
required String name,
|
||||
}) async {
|
||||
final uri = Uri.parse('${APIConfig.url}/brands/$id');
|
||||
|
||||
try {
|
||||
CustomHttpClient customHttpClient = CustomHttpClient(client: http.Client(), context: context, ref: ref);
|
||||
var responseData = await customHttpClient.post(
|
||||
url: uri,
|
||||
body: {
|
||||
'brandName': name,
|
||||
'_method': 'put',
|
||||
},
|
||||
);
|
||||
final parsedData = jsonDecode(responseData.body);
|
||||
|
||||
if (responseData.statusCode == 200) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('update successful!')));
|
||||
var data1 = ref.refresh(brandsProvider);
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Brand update failed: ${parsedData['message']}')));
|
||||
}
|
||||
} catch (error) {
|
||||
// Handle unexpected errors gracefully
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('An error occurred: $error')));
|
||||
}
|
||||
}
|
||||
|
||||
///_________delete_brand________________________
|
||||
Future<bool> deleteBrand({required BuildContext context, required num brandId, required WidgetRef ref}) async {
|
||||
final String apiUrl = '${APIConfig.url}/brands/$brandId'; // Replace with your API URL
|
||||
|
||||
try {
|
||||
CustomHttpClient customHttpClient = CustomHttpClient(ref: ref, context: context, client: http.Client());
|
||||
final response = await customHttpClient.delete(
|
||||
url: Uri.parse(apiUrl),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = json.decode(response.body);
|
||||
final String message = responseData['message'];
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(message)),
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Failed to delete brand.')),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('An error occurred.')),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
179
lib/Screens/product_brand/brands_list.dart
Normal file
179
lib/Screens/product_brand/brands_list.dart
Normal file
@@ -0,0 +1,179 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mobile_pos/Provider/profile_provider.dart';
|
||||
import 'package:mobile_pos/Screens/product_brand/product_brand_provider/product_brand_provider.dart';
|
||||
import 'package:mobile_pos/constant.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as lang;
|
||||
import 'package:nb_utils/nb_utils.dart';
|
||||
|
||||
import '../../GlobalComponents/glonal_popup.dart';
|
||||
import '../../http_client/custome_http_client.dart';
|
||||
import '../../widgets/empty_widget/_empty_widget.dart';
|
||||
import '../../service/check_user_role_permission_provider.dart';
|
||||
import '../hrm/widgets/deleteing_alart_dialog.dart';
|
||||
import '../product_category/product_category_list_screen.dart';
|
||||
import 'add_brans.dart';
|
||||
import 'brand repo/brand_repo.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class BrandsList extends StatefulWidget {
|
||||
const BrandsList({super.key, required this.isFromProductList});
|
||||
|
||||
final bool isFromProductList;
|
||||
|
||||
@override
|
||||
// ignore: library_private_types_in_public_api
|
||||
_BrandsListState createState() => _BrandsListState();
|
||||
}
|
||||
|
||||
class _BrandsListState extends State<BrandsList> {
|
||||
String search = '';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GlobalPopup(
|
||||
child: Scaffold(
|
||||
backgroundColor: kWhite,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
lang.S.of(context).brands,
|
||||
),
|
||||
iconTheme: const IconThemeData(color: Colors.black),
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.white,
|
||||
elevation: 0.0,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Consumer(builder: (context, ref, __) {
|
||||
final brandData = ref.watch(brandsProvider);
|
||||
final businessInfo = ref.watch(businessInfoProvider);
|
||||
final permissionService = PermissionService(ref);
|
||||
return businessInfo.when(data: (details) {
|
||||
// if (!permissionService.hasPermission(Permit.categoriesRead.value)) {
|
||||
// return Center(child: PermitDenyWidget());
|
||||
// }
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: AppTextField(
|
||||
textFieldType: TextFieldType.NAME,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
hintText: lang.S.of(context).search,
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: kGreyTextColor.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
search = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10.0),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
const AddBrands().launch(context);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 20.0, right: 20.0),
|
||||
height: 48.0,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
border: Border.all(color: kGreyTextColor),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.add,
|
||||
color: kGreyTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
brandData.when(data: (data) {
|
||||
return data.isNotEmpty
|
||||
? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: data.length,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, i) {
|
||||
return (data[i].brandName ?? '').toLowerCase().contains(search.toLowerCase())
|
||||
? ListCardWidget(
|
||||
onSelect: widget.isFromProductList
|
||||
? () {}
|
||||
: () async {
|
||||
Navigator.pop(context, data[i]);
|
||||
},
|
||||
title: data[i].brandName ?? '',
|
||||
// Delete
|
||||
onDelete: () async {
|
||||
if (!permissionService.hasPermission(Permit.salesCreate.value)) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
backgroundColor: Colors.red,
|
||||
content: Text('You do not have permission to delete brands.'),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
bool confirmDelete = await showDeleteConfirmationDialog(context: context, itemName: 'brand');
|
||||
if (confirmDelete) {
|
||||
EasyLoading.show();
|
||||
if (await BrandsRepo().deleteBrand(context: context, brandId: data[i].id ?? 0, ref: ref)) {
|
||||
ref.refresh(brandsProvider);
|
||||
}
|
||||
EasyLoading.dismiss();
|
||||
}
|
||||
},
|
||||
// Edit
|
||||
onEdit: () async {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => AddBrands(
|
||||
brand: data[i],
|
||||
),
|
||||
));
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
})
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Text(
|
||||
lang.S.of(context).noDataFound,
|
||||
//'No Data Found'
|
||||
),
|
||||
);
|
||||
}, error: (_, __) {
|
||||
return Container();
|
||||
}, loading: () {
|
||||
return const CircularProgressIndicator();
|
||||
}),
|
||||
],
|
||||
);
|
||||
}, error: (e, stack) {
|
||||
return Text(e.toString());
|
||||
}, loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
});
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
37
lib/Screens/product_brand/model/brands_model.dart
Normal file
37
lib/Screens/product_brand/model/brands_model.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
class Brand {
|
||||
Brand({
|
||||
this.id,
|
||||
this.businessId,
|
||||
this.brandName,
|
||||
this.status,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
});
|
||||
|
||||
Brand.fromJson(dynamic json) {
|
||||
id = json['id'];
|
||||
businessId = json['business_id'];
|
||||
brandName = json['brandName'];
|
||||
status = json['status'];
|
||||
createdAt = json['created_at'];
|
||||
updatedAt = json['updated_at'];
|
||||
}
|
||||
|
||||
num? id;
|
||||
num? businessId;
|
||||
String? brandName;
|
||||
num? status;
|
||||
String? createdAt;
|
||||
String? updatedAt;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
map['id'] = id;
|
||||
map['business_id'] = businessId;
|
||||
map['brandName'] = brandName;
|
||||
map['status'] = status;
|
||||
map['created_at'] = createdAt;
|
||||
map['updated_at'] = updatedAt;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mobile_pos/Screens/product_brand/model/brands_model.dart';
|
||||
|
||||
import '../brand repo/brand_repo.dart';
|
||||
|
||||
BrandsRepo brandsRepo = BrandsRepo();
|
||||
final brandsProvider = FutureProvider<List<Brand>>((ref) => brandsRepo.fetchAllBrands());
|
||||
Reference in New Issue
Block a user