This commit is contained in:
Patrick Alvin Alcala 2025-02-20 17:20:01 +08:00
parent 5164d55905
commit 6f54a6f9fc
65 changed files with 313 additions and 137 deletions

View file

@ -7,7 +7,7 @@ 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/delete_stock_page.dart';
import 'package:pharmacy_mobile/pages/list_stocks.dart';
import 'package:pharmacy_mobile/pages/list_stocks_page.dart';
import 'package:pharmacy_mobile/pages/login_page.dart';
import 'package:go_router/go_router.dart';
import 'package:pharmacy_mobile/pages/main_page.dart';
@ -95,10 +95,10 @@ final _router = GoRouter(
],
);
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(

View file

@ -1,3 +1,6 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:image_picker/image_picker.dart';
@ -19,6 +22,7 @@ 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:uuid/uuid.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
class AddMedicinePage extends StatefulWidget {
const AddMedicinePage({super.key});
@ -66,6 +70,17 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
}
}
// Future<Uint8List> compressFile(XFile file) async {
// var result = await FlutterImageCompress.compressWithFile(
// file.path,
// minWidth: 1020,
// minHeight: 765,
// quality: 90,
// format: CompressFormat.webp,
// );
// return result;
// }
void _getGenerics() async {
_genericNameList = await _refGenericNames.getList();
_checkResult(_genericNameList, 'Generics');
@ -155,7 +170,7 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
return;
}
imageUrl = await _storage.uploadImage(storageName, image, '$imageName.webp');
imageUrl = await _storage.uploadImage(context, storageName, image, '$imageName.webp');
setState(() {
if (imageUrl.isEmpty) {

View file

@ -23,9 +23,7 @@ class _CustomerPageState extends State<CustomerPage> {
@override
Widget build(BuildContext context) {
final List<Widget> bottomBarPages = [
CustomerMainPage(
controller: _notchController,
),
const CustomerMainPage(),
const CustomerSearchPage(),
const CustomerCartPage(),
const CustomerProfilePage()

View file

@ -1,19 +1,17 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:gap/gap.dart';
import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart';
import 'package:pharmacy_mobile/widgets/menu_widget.dart';
import 'package:pharmacy_mobile/widgets/menu_widget2.dart';
import 'package:pharmacy_mobile/widgets/page_background_widget.dart';
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:animated_notch_bottom_bar/animated_notch_bottom_bar/animated_notch_bottom_bar.dart';
class CustomerMainPage extends StatefulWidget {
final NotchBottomBarController? controller;
const CustomerMainPage({super.key, this.controller});
// final NotchBottomBarController? controller;
const CustomerMainPage({super.key});
@override
State<CustomerMainPage> createState() => _CustomerMainPageState();
@ -44,10 +42,12 @@ class _CustomerMainPageState extends State<CustomerMainPage> {
const Gap(32),
const TextWidget(text: 'Menu'),
const Gap(16),
MenuWidget(
icon: FontAwesomeIcons.eraser,
text: 'Remove Stock',
MenuWidget2(
// icon: FontAwesomeIcons.diagramNext,
text: 'Diagnose by ',
description: 'aaa',
onPressed: () => {context.push('/deletestock')},
color: 'green',
),
const Gap(32),
ButtonWidget(text: 'Log Out', onPressed: signOut)

View file

@ -1,13 +1,73 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:pharmacy_mobile/tables/ref_medicines.dart';
import 'package:pharmacy_mobile/tables/storage.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart';
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:animated_notch_bottom_bar/animated_notch_bottom_bar/animated_notch_bottom_bar.dart';
class CustomerSearchPage extends StatelessWidget {
final NotchBottomBarController? controller;
const CustomerSearchPage({super.key, this.controller});
class CustomerSearchPage extends StatefulWidget {
// final NotchBottomBarController? controller;
// final
const CustomerSearchPage({super.key});
@override
State<CustomerSearchPage> createState() => _CustomerSearchPageState();
}
class _CustomerSearchPageState extends State<CustomerSearchPage> {
final _searchController = TextEditingController();
final _storage = Storage();
final _refMedicines = RefMedicines();
late String imageUrl = '';
// List<String> imageUrl = [];
void getURL() async {
final image = await _storage.getPublicURL('ref_medicines_images', 'cb6eafdb-d86f-460a-9571-44446570d4cb.webp');
log(image);
setState(() {
imageUrl = image;
});
final meds = await _refMedicines.getList2();
log(meds.toString());
}
// void getURLs() async {
// try {
// for (int i = 1; i <= 4; i++) {
// final image = await _storage.getPublicURL(
// context,
// 'ref_medicines_images',
// 'ca3e2949-4964-4d25-a274-2a18608b7bdb.webp', // Replace with your actual image path
// );
// log(image);
// setState(() {
// imageUrl.add(image);
// });
// }
// } catch (e, stackTrace) {
// log('Error getting URLs: $e', stackTrace: stackTrace);
// }
// }
void _filterList() {}
@override
void initState() {
getURL();
super.initState();
}
@override
void dispose() {
_searchController.dispose();
imageUrl = '';
super.dispose();
}
@override
Widget build(BuildContext context) {
@ -24,8 +84,36 @@ class CustomerSearchPage extends StatelessWidget {
logoSize: 90,
),
const Gap(32),
const TextWidget(text: 'Search'),
const Gap(16),
Container(
padding: EdgeInsets.only(left: 32, right: 32),
child: Column(
children: [
InputWidget(label: '', controller: _searchController),
const Gap(8),
ButtonWidget(
text: 'Search',
onPressed: _filterList,
width: 160,
)
],
),
),
const Gap(32),
Center(
child: imageUrl.isNotEmpty
? ClipRRect(
borderRadius: BorderRadius.circular(12), // Add your desired border radius here
child: Image.network(imageUrl,
fit: BoxFit.cover,
width: 250,
height: 250,
cacheWidth: (250 * MediaQuery.of(context).devicePixelRatio).round()))
: const CircularProgressIndicator(
color: Colors.white,
strokeWidth: 4,
padding: EdgeInsets.all(8),
),
)
],
)
],

View file

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:gap/gap.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart';
import 'package:pharmacy_mobile/widgets/logo_widget.dart';
import 'package:pharmacy_mobile/widgets/page_background_widget.dart';
import 'package:pharmacy_mobile/widgets/slogan_widget.dart';
import 'package:pharmacy_mobile/widgets/text_widget.dart';
@ -29,8 +28,8 @@ class IndexPage extends StatelessWidget {
const Gap(88),
const TitleWidget(
firstTextSize: 24,
secondTextSize: 32,
logoSize: 90,
secondTextSize: 40,
logoSize: 124,
),
const Gap(32),
Padding(

View file

@ -1,5 +1,4 @@
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:uuid/uuid.dart';
class RefMedicines {
final SupabaseClient _supabase = Supabase.instance.client;
@ -17,14 +16,20 @@ class RefMedicines {
return data.toList();
}
Future<List> getListWithUUID() async {
final data = await _supabase
.from('ref_medicines')
.select('ref_medicines_uuid, medicine_name')
.order('medicine_name', ascending: true);
return data.toList();
}
Future<String> getUUID(String name) async {
final data = await _supabase.from('ref_medicines').select('ref_medicines_uuid').eq('medicine_name', name);
return data.first['ref_medicines_uuid'];
}
Future<void> postMedicine(String uuid, String name, String muuid, String guuid, String tuuid) async {
// final uuid = Uuid().v4();
final medicine = {
'ref_medicines_uuid': uuid,
'medicine_name': name,

View file

@ -1,7 +1,10 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:pharmacy_mobile/widgets/snackbar_widget.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
class Storage {
@ -39,7 +42,7 @@ class Storage {
}
}
Future<String> uploadImage(String storage, XFile image, String name) async {
Future<String> uploadImage(BuildContext context, String storage, XFile image, String name) async {
try {
final imageBytes = await image.readAsBytes();
final imagePath = name;
@ -48,8 +51,19 @@ class Storage {
final imageUrl = _supabase.storage.from(storage).getPublicUrl(imagePath);
return imageUrl;
} catch (e) {
log('Error uploading image: $e');
// ignore: use_build_context_synchronously
showNotification(context, 'Error uploading image: $e', false);
rethrow;
}
}
Future<Uint8List> downloadImage(String storage, String name) async {
final Uint8List file = await _supabase.storage.from(storage).download(name);
return file;
}
Future<String> getPublicURL(String storage, String name) async {
final String file = _supabase.storage.from(storage).getPublicUrl(name);
return file;
}
}

View file

@ -5,8 +5,9 @@ class ButtonWidget extends StatelessWidget {
final String text;
final VoidCallback onPressed;
final bool? outline;
final double? width;
const ButtonWidget({super.key, required this.text, required this.onPressed, this.outline});
const ButtonWidget({super.key, required this.text, required this.onPressed, this.outline, this.width});
@override
Widget build(BuildContext context) {
@ -30,8 +31,10 @@ class ButtonWidget extends StatelessWidget {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20), // rounded corners
),
minimumSize: Size(MediaQuery.of(context).size.width <= 768 ? MediaQuery.of(context).size.width - 96 : 320,
44), // minimum size
minimumSize: Size(
width ?? (MediaQuery.of(context).size.width <= 768 ? MediaQuery.of(context).size.width - 96 : 320),
44),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
),
onPressed: onPressed,

View file

@ -42,7 +42,6 @@ class _DatePickerWidgetState extends State<DatePickerWidget> {
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16),
decoration: BoxDecoration(
// border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(8),
color: Colors.transparent,

View file

@ -16,16 +16,17 @@ class InputWidget extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('$label:',
style: GoogleFonts.outfit(
textStyle:
const TextStyle(color: Color.fromRGBO(255, 255, 255, 1), fontSize: 12, fontWeight: FontWeight.w500),
)),
if (label.isNotEmpty)
Text('$label:',
style: GoogleFonts.outfit(
textStyle:
const TextStyle(color: Color.fromRGBO(255, 255, 255, 1), fontSize: 12, fontWeight: FontWeight.w500),
)),
const Gap(8),
TextField(
controller: controller,
decoration: InputDecoration(
filled: true, // Enable filling the background
filled: true,
fillColor: const Color.fromRGBO(255, 255, 255, 1),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
contentPadding: const EdgeInsets.symmetric(vertical: 10, horizontal: 24)),

View file

@ -46,7 +46,7 @@ class MenuWidget2 extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
gradient: LinearGradient(
colors: _getColorList(color!),
colors: _getColorList(color ?? ''),
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),