This commit is contained in:
Patrick Alvin Alcala 2025-02-25 15:18:41 +08:00
parent b299297fa5
commit 11fc5c43bf
29 changed files with 1041 additions and 124 deletions

View file

@ -6,6 +6,7 @@ import 'package:pharmacy_mobile/pages/add_medicine_page.dart';
import 'package:pharmacy_mobile/pages/add_stock_page.dart';
import 'package:pharmacy_mobile/pages/add_type_page.dart';
import 'package:pharmacy_mobile/pages/customer_page.dart';
import 'package:pharmacy_mobile/pages/customer_pages/customer_itemview_page.dart';
import 'package:pharmacy_mobile/pages/delete_stock_page.dart';
import 'package:pharmacy_mobile/pages/list_stocks_page.dart';
import 'package:pharmacy_mobile/pages/login_page.dart';
@ -92,10 +93,14 @@ final _router = GoRouter(
path: '/customer',
builder: (context, state) => const CustomerPage(),
),
GoRoute(
name: 'itemview',
path: '/itemview',
builder: (context, state) => const CustomerItemviewPage(),
),
],
);
class MyApp extends StatelessWidget {
const MyApp({super.key});

View file

@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';
@ -5,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:image_picker/image_picker.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:pharmacy_mobile/security/encryption.dart';
import 'package:pharmacy_mobile/tables/ref_categories.dart';
import 'package:pharmacy_mobile/tables/ref_generic_names.dart';
import 'package:pharmacy_mobile/tables/ref_manufactorers.dart';
@ -21,6 +23,7 @@ import 'package:pharmacy_mobile/widgets/snackbar_widget.dart';
import 'package:pharmacy_mobile/widgets/text_widget.dart';
import 'package:pharmacy_mobile/widgets/title_widget.dart';
import 'package:go_router/go_router.dart';
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
import 'package:uuid/uuid.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
@ -40,6 +43,7 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
final _refMedicines = RefMedicines();
final _storage = Storage();
final _nameController = TextEditingController();
final _barcodeController = TextEditingController();
final FocusNode _focusNode = FocusNode();
bool _isLoading = false;
@ -134,17 +138,37 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
_selectedManufactorer = manufactorer;
}
Future<void> _scanBarcode() async {
String? barcode = await SimpleBarcodeScanner.scanBarcode(
context,
// barcodeAppBar: const BarcodeAppBar(
// // appBarTitle: 'Test',
// // centerTitle: false,
// // enableBackButton: false,
// // backButtonIcon: Icon(Icons.arrow_back_ios),
// ),
// isShowFlashIcon: true,
delayMillis: 2000,
scanType: ScanType.barcode,
cameraFace: CameraFace.back,
);
_barcodeController.text = barcode != '-1' ? barcode ?? '' : '';
}
void _saveMedicine() async {
setState(() => _isLoading = true);
try {
final String encrpytedBarcode = await encrypt(_barcodeController.text);
if (await InternetConnectionChecker.instance.hasConnection) {
final medName = _nameController.text;
final medGenericUUID = await _refGenericNames.getUUID(_selectedGeneric);
final medTypeUUID = await _refTypes.getUUID(_selectedType);
final medManufactorerUUID = await _refManufactorer.getUUID(_selectedManufactorer);
await _refMedicines.postMedicine(uuid, medName, medManufactorerUUID, medGenericUUID, medTypeUUID);
await _refMedicines.postMedicine(
uuid, medName, medManufactorerUUID, medGenericUUID, medTypeUUID, encrpytedBarcode);
} else {
if (mounted) {
showNotification(context, 'Error: No Internet Connection', false);
@ -191,6 +215,7 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
void dispose() {
_nameController.dispose();
_focusNode.dispose();
_barcodeController.dispose();
_genericNameList = [];
_selectedGeneric = '';
@ -245,6 +270,10 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
list: _manufactorerList,
listTitle: 'manufactorer_name',
onChanged: _updateManufactorer),
const Gap(16),
InputWidget(label: 'Barcode', controller: _barcodeController),
const Gap(8),
ButtonWidget(text: 'Scan Barcode', onPressed: _scanBarcode),
const Gap(32),
if (imageUrl.isNotEmpty)
Center(

View file

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:pharmacy_mobile/tables/ref_medicines.dart';
@ -10,6 +12,7 @@ import 'package:pharmacy_mobile/widgets/input_widget.dart';
import 'package:pharmacy_mobile/widgets/page_background_widget.dart';
import 'package:pharmacy_mobile/widgets/text_widget.dart';
import 'package:pharmacy_mobile/widgets/title_widget.dart';
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
class AddStockPage extends StatefulWidget {
const AddStockPage({super.key});
@ -18,7 +21,7 @@ class AddStockPage extends StatefulWidget {
State<AddStockPage> createState() => _AddStockPageState();
}
class _AddStockPageState extends State<AddStockPage> {
class _AddStockPageState extends State<AddStockPage> with WidgetsBindingObserver {
final _formKey = GlobalKey<FormState>();
final FocusNode _focusNode = FocusNode();
final _refMedicines = RefMedicines();
@ -31,6 +34,7 @@ class _AddStockPageState extends State<AddStockPage> {
late List _medicineList = [];
late String _selectedMedicine = '';
late DateTime selectedDate = DateTime.now();
late String barcode = '';
void autoRun() async {
_medicineList = await _refMedicines.getList();
@ -101,7 +105,34 @@ class _AddStockPageState extends State<AddStockPage> {
value: selectedDate,
),
const Gap(32),
ButtonWidget(text: 'Add Stock', onPressed: _saveStock)
ButtonWidget(text: 'Add Stock', onPressed: _saveStock),
const Gap(16),
ButtonWidget(
text: 'Barcode',
onPressed: () async {
String? bc = await SimpleBarcodeScanner.scanBarcode(
context,
// barcodeAppBar: const BarcodeAppBar(
// // appBarTitle: 'Test',
// // centerTitle: false,
// // enableBackButton: false,
// // backButtonIcon: Icon(Icons.arrow_back_ios),
// ),
// isShowFlashIcon: true,
delayMillis: 2000,
scanType: ScanType.barcode,
cameraFace: CameraFace.back,
);
setState(() {
barcode = bc as String;
});
},
),
const Gap(16),
TextWidget(
text: barcode,
size: 14,
)
],
),
),

View file

@ -15,19 +15,15 @@ class CustomerCartPage extends StatelessWidget {
body: PageBackgroundWidget(
child: Column(
children: [
Column(
children: [
const Gap(96),
const TitleWidget(
firstTextSize: 14,
secondTextSize: 24,
logoSize: 90,
),
const Gap(32),
const TextWidget(text: 'My Cart'),
const Gap(16),
],
)
const Gap(96),
const TitleWidget(
firstTextSize: 14,
secondTextSize: 24,
logoSize: 90,
),
const Gap(32),
const TextWidget(text: 'My Cart'),
const Gap(16),
],
)));
}

View file

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:pharmacy_mobile/tables/storage.dart';
import 'package:pharmacy_mobile/widgets/page_background_widget.dart';
class CustomerItemviewPage extends StatelessWidget {
const CustomerItemviewPage({super.key});
@override
Widget build(BuildContext context) {
final storage = Storage();
void getURL() async {
final image = await storage.getPublicURL('ref_medicines_images', 'cb6eafdb-d86f-460a-9571-44446570d4cb.webp');
// setState(() {
// imageUrl = image;
}
return Scaffold(
body: PageBackgroundWidget(
child: Column(
children: [
Image.network('imageUrl',
fit: BoxFit.cover,
width: 21,
height: 21 / 1.4,
cacheWidth: (21 * MediaQuery.of(context).devicePixelRatio).round()),
],
)),
);
}
}

View file

@ -76,6 +76,7 @@ class _CustomerSearchPageState extends State<CustomerSearchPage> {
return Scaffold(
body: PageBackgroundWidget(
// height: MediaQuery.of(context).size.height * 2,
child: Column(
children: [
Column(
@ -121,6 +122,30 @@ class _CustomerSearchPageState extends State<CustomerSearchPage> {
// padding: EdgeInsets.all(8),
// ),
// )
Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 8, 0, 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ItemCardWidget(
imageUrl: imageUrl,
text: 'sample',
price: 500,
quantity: 15,
),
ItemCardWidget(
imageUrl: imageUrl,
text: 'sample',
price: 20,
quantity: 85,
),
],
),
)
],
),
Column(
children: [
Padding(

View file

@ -0,0 +1,24 @@
import 'package:lazyxchacha/keypair.dart' as kp;
import 'package:lazyxchacha/lazyxchacha.dart';
final key = kp.KeyPair.newKeyPair();
Future<String> encrypt(String text) async {
final lazyxchacha = LazyXChaCha.instance;
final localKey = await key;
final sharedKey = await localKey.sharedKey(localKey.pk);
final ciphertext = await lazyxchacha.encrypt(text, sharedKey);
return ciphertext;
}
Future<String> decrypt(String encrypted) async {
final lazyXChaCha = LazyXChaCha.instance;
final localKey = await key;
final sharedKey = await localKey.sharedKey(localKey.pk);
final plaintext = await lazyXChaCha.decrypt(encrypted, sharedKey);
return plaintext;
}

View file

@ -29,13 +29,14 @@ class RefMedicines {
return data.first['ref_medicines_uuid'];
}
Future<void> postMedicine(String uuid, String name, String muuid, String guuid, String tuuid) async {
Future<void> postMedicine(String uuid, String name, String muuid, String guuid, String tuuid, String barcode) async {
final medicine = {
'ref_medicines_uuid': uuid,
'medicine_name': name,
'ref_manufactorers_uuid': muuid,
'ref_generic_names_uuid': guuid,
'ref_types_uuid': tuuid
'ref_types_uuid': tuuid,
'barcode': barcode
};
await _supabase.from('ref_medicines').insert(medicine);

View file

@ -26,10 +26,7 @@ class DropdownWrapperWidget extends StatelessWidget {
spacing: 16,
children: [
const CircularProgressIndicator(color: Color.fromRGBO(255, 255, 255, 1)),
TextWidget(
text: 'Fetching $text',
size: 16,
)
TextWidget(text: 'Fetching $text', size: 16, footer: true)
],
),
],

View file

@ -26,10 +26,7 @@ class DropdownWrapperMultiWidget extends StatelessWidget {
spacing: 16,
children: [
const CircularProgressIndicator(color: Color.fromRGBO(255, 255, 255, 1)),
TextWidget(
text: 'Fetching $text',
size: 16,
)
TextWidget(text: 'Fetching $text', size: 16, footer: true)
],
),
],

View file

@ -26,6 +26,7 @@ class InputWidget extends StatelessWidget {
)),
const Gap(8),
TextField(
textInputAction: TextInputAction.go,
controller: controller,
decoration: InputDecoration(
filled: true,