first commit

This commit is contained in:
2026-02-07 15:57:09 +07:00
commit 157096f164
1153 changed files with 415766 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
import 'dart:io';
import 'package:file_selector/file_selector.dart';
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/generated/l10n.dart' as lang;
import 'package:mobile_pos/Screens/Products/bulk%20product%20upload/repo/bulk_upload_repo.dart';
import 'package:mobile_pos/constant.dart';
import '../../../GlobalComponents/glonal_popup.dart';
class BulkUploader extends StatefulWidget {
const BulkUploader({
super.key,
});
@override
State<BulkUploader> createState() => _BulkUploaderState();
}
class _BulkUploaderState extends State<BulkUploader> {
File? file;
String getFileExtension(String fileName) {
return fileName.split('/').last;
}
@override
Widget build(BuildContext context) {
final _lang = lang.S.of(context);
return GlobalPopup(
child: Scaffold(
appBar: AppBar(
title: Text(_lang.excelUploader),
),
body: Consumer(builder: (context, ref, __) {
final businessInfo = ref.watch(businessInfoProvider);
return businessInfo.when(data: (details) {
return Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Visibility(
visible: file != null,
child: Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Card(
child: ListTile(
leading: Container(
height: 40,
width: 40,
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: const BorderRadius.all(Radius.circular(10)),
),
child: const Image(image: AssetImage('images/excel.png'))),
title: Text(
getFileExtension(file?.path ?? ''),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
trailing: GestureDetector(
onTap: () {
setState(() {
file = null;
});
},
child: Text(_lang.remove)))),
),
),
Visibility(
visible: file == null,
child: const Padding(
padding: EdgeInsets.only(bottom: 20),
child: Image(
height: 100,
width: 100,
image: AssetImage('images/file-upload.png'),
)),
),
ElevatedButton(
style: const ButtonStyle(backgroundColor: WidgetStatePropertyAll(kMainColor)),
onPressed: () async {
if (file == null) {
await pickAndUploadFile(ref: ref);
} else {
EasyLoading.show(status: _lang.uploading);
await BulkUpLoadRepo().uploadBulkFile(file: file!, ref: ref, context: context);
EasyLoading.dismiss();
}
},
child: Text(file == null ? _lang.pickAndUploadFile : _lang.upload,
style: const TextStyle(color: Colors.white)),
),
TextButton(
onPressed: () async {
await BulkUpLoadRepo().downloadFile(context);
},
child: Text(_lang.downloadExcelFormat),
),
],
),
),
);
}, error: (e, stack) {
return Text(e.toString());
}, loading: () {
return const Center(
child: CircularProgressIndicator(),
);
});
}),
),
);
}
///
Future<void> pickAndUploadFile({required WidgetRef ref}) async {
XTypeGroup typeGroup = XTypeGroup(
label: lang.S.of(context).excelFiles,
extensions: ['xlsx'],
);
final XFile? fileResult = await openFile(acceptedTypeGroups: [typeGroup]);
if (fileResult != null) {
final File files = File(fileResult.path);
setState(() {
file = files;
});
} else {
print(lang.S.of(context).noFileSelected);
}
}
}

View File

@@ -0,0 +1,75 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mobile_pos/Provider/product_provider.dart';
import 'package:mobile_pos/Screens/product_brand/product_brand_provider/product_brand_provider.dart';
import 'package:mobile_pos/Screens/product_category/provider/product_category_provider/product_unit_provider.dart';
import 'package:mobile_pos/Screens/product_unit/provider/product_unit_provider.dart';
import '../../../../Const/api_config.dart';
import '../../../../Repository/constant_functions.dart';
import '../../../../http_client/custome_http_client.dart';
import 'package:http/http.dart' as http;
class BulkUpLoadRepo {
Future<void> uploadBulkFile({
required WidgetRef ref,
required BuildContext context,
required File file,
}) async {
CustomHttpClient customHttpClient = CustomHttpClient(client: http.Client(), context: context, ref: ref);
final uri = Uri.parse('${APIConfig.url}/bulk-uploads');
var request = http.MultipartRequest('POST', uri)
..headers['Accept'] = 'application/json'
..headers['Authorization'] = await getAuthToken();
request.files.add(http.MultipartFile.fromBytes('file', file.readAsBytesSync(), filename: file.path));
final response = await customHttpClient.uploadFile(url: uri, fileFieldName: 'file', file: file, fields: request.fields);
final responseData = await response.stream.bytesToString();
final parsedData = jsonDecode(responseData);
if (response.statusCode == 200) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Added successful!')));
ref.refresh(productProvider);
ref.refresh(categoryProvider);
ref.refresh(brandsProvider);
ref.refresh(unitsProvider);
Navigator.pop(context);
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Failed: ${parsedData['message']}')));
}
}
final String fileUrl = '${APIConfig.domain}assets/POSpro_bulk_product_upload.xlsx';
Future<void> downloadFile(BuildContext context) async {
try {
final response = await http.get(Uri.parse(fileUrl));
if (response.statusCode != 200) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed to download file!')),
);
return;
}
final downloadPath = '/storage/emulated/0/Download';
final file = File('$downloadPath/POSpro_bulk_product_upload.xlsx');
await file.writeAsBytes(response.bodyBytes);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('File saved to: ${file.path}')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Download error: $e')),
);
}
}
}