This commit is contained in:
Patrick Alvin Alcala 2025-02-05 17:06:13 +08:00
parent 87d8bb483e
commit 17a1430ef0
11 changed files with 271 additions and 25 deletions

View file

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:pharmacy_mobile/pages/add_category.dart';
import 'package:pharmacy_mobile/pages/add_generics.dart';
import 'package:pharmacy_mobile/pages/add_medicine.dart';
import 'package:pharmacy_mobile/pages/add_stock.dart';
@ -35,7 +36,7 @@ final _router = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
name: 'index', // Optional, add name to your routes. Allows you navigate by name instead of path
name: 'index',
path: '/',
builder: (context, state) => IndexPage(),
),
@ -69,6 +70,11 @@ final _router = GoRouter(
path: '/addtype',
builder: (context, state) => AddTypePage(),
),
GoRoute(
name: 'addcategory',
path: '/addcategory',
builder: (context, state) => AddCategoryPage(),
),
GoRoute(
name: 'addstock',
path: '/addstock',

View file

@ -0,0 +1,91 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:pharmacy_mobile/tables/ref_categories.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart';
import 'package:pharmacy_mobile/widgets/form_border_widget.dart';
import 'package:pharmacy_mobile/widgets/input_widget.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';
class AddCategoryPage extends StatefulWidget {
const AddCategoryPage({super.key});
@override
State<AddCategoryPage> createState() => _AddCategoryPageState();
}
class _AddCategoryPageState extends State<AddCategoryPage> {
final _formKey = GlobalKey<FormState>();
final _categoryController = TextEditingController();
final _refCategories = RefCategories();
bool _isLoading = false;
void _saveCategory() async {
setState(() => _isLoading = true);
try {
if (await InternetConnectionChecker.instance.hasConnection) {
await _refCategories.postCategory(_categoryController.text.toUpperCase());
if (mounted) {
showNotification(context, 'Category Saved', true);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
context.push('/main');
}
});
}
} else {
if (mounted) {
showNotification(context, 'Error: No Internet Connection', false);
}
}
} catch (e) {
if (mounted) {
showNotification(context, 'Error: $e', false);
}
} finally {
setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageBackgroundWidget(
child: Center(
child: Column(
children: [
const Gap(96),
const TitleWidget(firstTextSize: 20, secondTextSize: 32),
const Gap(32),
const TextWidget(text: 'Add Category'),
const Gap(16),
FormBorderWidget(
color: 'blue',
child: Form(
key: _formKey,
child: Center(
child: Column(
children: [
InputWidget(label: 'Category Name', controller: _categoryController),
const Gap(32),
if (_isLoading)
Center(child: CircularProgressIndicator(color: Colors.white))
else
ButtonWidget(text: 'Save Category', onPressed: _saveCategory)
],
),
)),
)
],
),
)),
);
}
}

View file

@ -1,6 +1,6 @@
import 'package:gap/gap.dart';
import 'package:flutter/material.dart';
// import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:pharmacy_mobile/tables/ref_categories.dart';
import 'package:pharmacy_mobile/tables/ref_generic_names.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart';
@ -8,9 +8,11 @@ import 'package:pharmacy_mobile/widgets/dropdown_widget.dart';
import 'package:pharmacy_mobile/widgets/form_border_widget.dart';
import 'package:pharmacy_mobile/widgets/input_widget.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:visibility_detector/visibility_detector.dart';
import 'package:go_router/go_router.dart';
class AddGenericsPage extends StatefulWidget {
const AddGenericsPage({super.key});
@ -26,6 +28,7 @@ class _AddGenericsPageState extends State<AddGenericsPage> {
final _nameController = TextEditingController();
final _formKey = GlobalKey<FormState>();
bool _isVisible = false;
bool _isLoading = false;
late List _categoryList = [];
late String _selectedCategory = '';
@ -40,9 +43,35 @@ class _AddGenericsPageState extends State<AddGenericsPage> {
}
void saveGeneric() async {
setState(() => _isLoading = true);
try {
if (await InternetConnectionChecker.instance.hasConnection) {
_categoryUUID = await _refCategories.getUUID(_selectedCategory);
await _refGenericNames.postGeneric(_nameController.text, _categoryUUID);
if (mounted) {
showNotification(context, 'Generic Name Saved', true);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
context.push('/main');
}
});
}
} else {
if (mounted) {
showNotification(context, 'Error: No Internet Connection', false);
}
}
} catch (e) {
if (mounted) {
showNotification(context, 'Error: $e', false);
}
} finally {
setState(() => _isLoading = false);
}
}
@override
@ -58,6 +87,7 @@ class _AddGenericsPageState extends State<AddGenericsPage> {
_selectedCategory = '';
_categoryUUID = '';
_isVisible = false;
_isLoading = false;
super.dispose();
}
@ -96,7 +126,10 @@ class _AddGenericsPageState extends State<AddGenericsPage> {
list: _categoryList,
listTitle: 'category_name',
onChanged: _updateCategory),
const Gap(16),
const Gap(32),
if (_isLoading)
Center(child: CircularProgressIndicator(color: Colors.white))
else
ButtonWidget(text: 'Add', onPressed: saveGeneric)
],
)),

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:internet_connection_checker/internet_connection_checker.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';
@ -10,6 +11,7 @@ import 'package:pharmacy_mobile/widgets/dropdown_widget.dart';
import 'package:pharmacy_mobile/widgets/form_border_widget.dart';
import 'package:pharmacy_mobile/widgets/input_widget.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:visibility_detector/visibility_detector.dart';
@ -32,6 +34,7 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
final _nameController = TextEditingController();
final FocusNode _focusNode = FocusNode();
bool _isVisible = false;
bool _isLoading = false;
late List _genericNameList = [];
late String _selectedGeneric = '';
@ -42,9 +45,15 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
late String _selectedManufactorer = '';
void autoRun() async {
if (await InternetConnectionChecker.instance.hasConnection) {
_genericNameList = await _refGenericNames.getList();
_typeList = await _refTypes.getList();
_manufactorerList = await _refManufactorer.getList();
} else {
if (mounted) {
showNotification(context, 'Error: No Internet Connection', false);
}
}
}
void _updateGeneric(dynamic generic) async {
@ -52,9 +61,7 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
final catuuid = await _refGenericNames.getCategoryUUID(_selectedGeneric);
final catname = await _refCategories.getName(catuuid);
setState(() {
_selectedCategory = catname;
});
setState(() => _selectedCategory = catname);
}
void _updateType(dynamic type) {
@ -66,12 +73,28 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
}
void _saveMedicine() async {
setState(() => _isLoading = true);
try {
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(medName, medGenericUUID, medManufactorerUUID, medTypeUUID);
} else {
if (mounted) {
showNotification(context, 'Error: No Internet Connection', false);
}
}
} catch (e) {
if (mounted) {
showNotification(context, 'Error: $e', false);
}
} finally {
setState(() => _isLoading = false);
}
}
@override
@ -147,7 +170,10 @@ class _AddMedicinePageState extends State<AddMedicinePage> {
list: _manufactorerList,
listTitle: 'manufactorer_name',
onChanged: _updateManufactorer),
const Gap(16),
const Gap(32),
if (_isLoading)
Center(child: CircularProgressIndicator(color: Colors.white))
else
ButtonWidget(text: 'Save Medicine', onPressed: _saveMedicine)
],
),

View file

@ -1,12 +1,15 @@
import 'package:gap/gap.dart';
import 'package:flutter/material.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:pharmacy_mobile/tables/ref_types.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart';
import 'package:pharmacy_mobile/widgets/form_border_widget.dart';
import 'package:pharmacy_mobile/widgets/input_widget.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';
class AddTypePage extends StatefulWidget {
const AddTypePage({super.key});
@ -20,8 +23,35 @@ class _AddTypePageState extends State<AddTypePage> {
final _typeController = TextEditingController();
final _refTypes = RefTypes();
bool _isLoading = false;
void saveType() async {
setState(() => _isLoading = true);
try {
if (await InternetConnectionChecker.instance.hasConnection) {
await _refTypes.postType(_typeController.text);
if (mounted) {
showNotification(context, 'Medicine Type Saved', true);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
context.push('/main');
}
});
}
} else {
if (mounted) {
showNotification(context, 'Error: No Internet Connection', false);
}
}
} catch (e) {
if (mounted) {
showNotification(context, 'Error: $e', false);
}
} finally {
setState(() => _isLoading = false);
}
}
@override
@ -52,6 +82,9 @@ class _AddTypePageState extends State<AddTypePage> {
children: [
InputWidget(label: 'Type Name', controller: _typeController),
const Gap(16),
if (_isLoading)
Center(child: CircularProgressIndicator(color: Colors.white))
else
ButtonWidget(text: 'Save Type', onPressed: saveType)
],
),

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:pharmacy_mobile/tables/stocks.dart';
import 'package:pharmacy_mobile/widgets/datatable_widget.dart';
@ -97,6 +98,23 @@ class _ListStocksPageState extends State<ListStocksPage> {
child: CircularProgressIndicator(
color: Colors.white,
))
else if (_stockList.isEmpty)
// TextWidget(text: 'No Stock Listed')
Container(
decoration: BoxDecoration(
border: Border.all(color: const Color.fromRGBO(205, 59, 208, 0.702), width: 2),
borderRadius: BorderRadius.circular(12),
),
padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16.0),
child: Text(
'No Stock Listed',
style: GoogleFonts.outfit(
color: Color.fromRGBO(255, 255, 255, 1),
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
)
else
DataTableWidget(
column: _createColumns(),

View file

@ -10,6 +10,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:internet_connection_checker/internet_connection_checker.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@ -32,11 +33,26 @@ class _LoginPageState extends State<LoginPage> {
final email = _emailController.text;
final password = _passwordController.text;
if (email.isEmpty) {
if (mounted) {
showNotification(context, 'Error: Please enter a valid email', false);
}
return;
}
if (password.isEmpty) {
if (mounted) {
showNotification(context, 'Error: Please enter a password', false);
}
return;
}
setState(() => _isLoading = true);
try {
if (await InternetConnectionChecker.instance.hasConnection) {
await _authService.signIn(email, password);
if (mounted) {
showNotification(context, 'Login Successful', true);
@ -52,8 +68,15 @@ class _LoginPageState extends State<LoginPage> {
}
}
} catch (e) {
if (e is AuthException) {
final errorMessage = e.message;
if (mounted) {
showNotification(context, 'Error: $e', false);
// showNotification(context, 'Error: $errorMessage', false);
if (errorMessage == 'Invalid login credentials') {
showNotification(context, 'Error: Invalid Email or Password', false);
}
}
}
} finally {
setState(() => _isLoading = false);

View file

@ -47,6 +47,12 @@ class MainPage extends StatelessWidget {
onPressed: () => {context.push('/addtype')},
color: 'blue'),
const Gap(16),
MenuWidget(
icon: FontAwesomeIcons.squarePlus,
text: 'Add Category',
onPressed: () => {context.push('/addcategory')},
color: 'blue'),
const Gap(16),
MenuWidget(
icon: FontAwesomeIcons.squarePlus, text: 'Add Generics', onPressed: gotoAddGenerics, color: 'blue'),
const Gap(32),

View file

@ -11,7 +11,7 @@ class RegisterPage extends StatefulWidget {
const RegisterPage({super.key});
@override
_RegisterPageState createState() => _RegisterPageState();
State<RegisterPage> createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {

View file

@ -1,4 +1,5 @@
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:uuid/uuid.dart';
class RefCategories {
final SupabaseClient _supabase = Supabase.instance.client;
@ -17,4 +18,9 @@ class RefCategories {
final data = await _supabase.from('ref_categories').select('category_name').eq('ref_categories_uuid', uuid);
return data.first['category_name'];
}
Future<void> postCategory(String name) async {
final categoryUUID = Uuid().v4();
await _supabase.from('ref_categories').insert({'ref_categories_uuid': categoryUUID, 'category_name': name});
}
}

View file

@ -1,13 +1,17 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
void showNotification(BuildContext context, String text, bool isPositive) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(text),
content: Text(text, style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.w600)),
backgroundColor: isPositive ? const Color.fromRGBO(37, 106, 32, 1) : const Color.fromRGBO(188, 59, 50, 1),
elevation: 4.0,
behavior: SnackBarBehavior.floating,
duration: const Duration(seconds: 3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), // Adjust the radius value as needed
),
),
);
}