This commit is contained in:
Patrick Alvin Alcala 2025-02-03 15:52:50 +08:00
parent cf2ce36f87
commit 50d2cba7f2
9 changed files with 156 additions and 83 deletions

View file

@ -90,16 +90,9 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp.router( return MaterialApp.router(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
// initialRoute: '/', theme: ThemeData(
// routes: { useMaterial3: true,
// '/': (context) => const IndexPage(), ),
// '/login': (context) => const LoginPage(),
// },
// debugShowCheckedModeBanner: false,
// theme: ThemeData(
// colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
// useMaterial3: true,
// )
routerConfig: _router, routerConfig: _router,
); );
} }

View file

@ -1,13 +1,11 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:intl/intl.dart';
import 'package:pharmacy_mobile/tables/stocks.dart'; import 'package:pharmacy_mobile/tables/stocks.dart';
import 'package:pharmacy_mobile/widgets/datatable_widget.dart'; import 'package:pharmacy_mobile/widgets/datatable_widget.dart';
import 'package:pharmacy_mobile/widgets/page_background_widget.dart'; import 'package:pharmacy_mobile/widgets/page_background_widget.dart';
import 'package:pharmacy_mobile/widgets/text_widget.dart'; import 'package:pharmacy_mobile/widgets/text_widget.dart';
import 'package:pharmacy_mobile/widgets/title_widget.dart'; import 'package:pharmacy_mobile/widgets/title_widget.dart';
import 'package:intl/intl.dart';
class ListStocksPage extends StatefulWidget { class ListStocksPage extends StatefulWidget {
const ListStocksPage({super.key}); const ListStocksPage({super.key});
@ -20,18 +18,36 @@ class _ListStocksPageState extends State<ListStocksPage> {
final _stocks = Stocks(); final _stocks = Stocks();
late List _stockList = []; late List _stockList = [];
bool _isLoading = false;
List<DataRow> _createRows() { List<DataRow> _createRows() {
final today = DateTime.now().toUtc();
return _stockList.map((item) { return _stockList.map((item) {
final dateString = item['expiration_date']; final dateString = item['expiration_date'];
final date = DateTime.parse(dateString); final date = DateTime.parse(dateString).toUtc();
final formattedDate = DateFormat('MMMM d, yyyy').format(date); final formattedDate = DateFormat('MMMM d, yyyy').format(date);
return DataRow(cells: [ if (date.isBefore(today)) {
return DataRow(
cells: [
DataCell(Text(item['medicine_name'], style: const TextStyle(color: Color.fromRGBO(188, 59, 50, 1)))),
DataCell(Text(item['quantity'].toString(), style: const TextStyle(color: Color.fromRGBO(188, 59, 50, 1)))),
DataCell(
Text(formattedDate,
style: const TextStyle(color: Color.fromRGBO(188, 59, 50, 1))), // Highlight expired items
),
],
);
} else {
return DataRow(
cells: [
DataCell(Text(item['medicine_name'])), DataCell(Text(item['medicine_name'])),
DataCell(Text(item['quantity'].toString())), DataCell(Text(item['quantity'].toString())),
DataCell(Text(formattedDate)), DataCell(Text(formattedDate)),
]); ],
);
}
}).toList(); }).toList();
} }
@ -44,8 +60,13 @@ class _ListStocksPageState extends State<ListStocksPage> {
} }
void autoRun() async { void autoRun() async {
setState(() {
_isLoading = true;
});
_stockList = await _stocks.getList(); _stockList = await _stocks.getList();
setState(() {}); setState(() {
_isLoading = false;
});
} }
@override @override
@ -64,13 +85,26 @@ class _ListStocksPageState extends State<ListStocksPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: PageBackgroundWidget( body: PageBackgroundWidget(
child: Column(children: [ child: Column(
children: [
const Gap(104), const Gap(104),
const TitleWidget(firstTextSize: 20, secondTextSize: 32), const TitleWidget(firstTextSize: 20, secondTextSize: 32),
const Gap(32), const Gap(32),
const TextWidget(text: 'List of Stocks'), const TextWidget(text: 'List of Stocks'),
const Gap(16), const Gap(16),
DataTableWidget(column: _createColumns(), row: _createRows()), if (_isLoading)
]))); Center(
child: CircularProgressIndicator(
color: Colors.white,
))
else
DataTableWidget(
column: _createColumns(),
row: _createRows(),
),
],
),
),
);
} }
} }

View file

@ -6,6 +6,7 @@ import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart'; import 'package:pharmacy_mobile/widgets/button_widget.dart';
import 'package:pharmacy_mobile/widgets/input_widget.dart'; import 'package:pharmacy_mobile/widgets/input_widget.dart';
import 'package:pharmacy_mobile/widgets/page_background_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/text_widget.dart';
import 'package:pharmacy_mobile/widgets/title_widget.dart'; import 'package:pharmacy_mobile/widgets/title_widget.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart'; import 'package:internet_connection_checker/internet_connection_checker.dart';
@ -37,13 +38,7 @@ class _LoginPageState extends State<LoginPage> {
if (await InternetConnectionChecker.instance.hasConnection) { if (await InternetConnectionChecker.instance.hasConnection) {
await _authService.signIn(email, password); await _authService.signIn(email, password);
if (mounted) { if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( showNotification(context, 'Login Successful', true);
content: Text('Login Successful'),
backgroundColor: const Color.fromRGBO(37, 106, 32, 1),
elevation: 4.0,
behavior: SnackBarBehavior.floating,
duration: Duration(seconds: 5),
));
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) { if (mounted) {
@ -53,24 +48,12 @@ class _LoginPageState extends State<LoginPage> {
} }
} else { } else {
if (mounted) { if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( showNotification(context, 'Error: No Internet Connection', false);
content: Text('No Internet Connection'),
backgroundColor: const Color.fromRGBO(188, 59, 50, 1),
elevation: 4.0,
behavior: SnackBarBehavior.floating,
duration: Duration(seconds: 5),
));
} }
} }
} catch (e) { } catch (e) {
if (mounted) { if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( showNotification(context, 'Error: $e', false);
content: Text('Error: $e'),
backgroundColor: const Color.fromRGBO(188, 59, 50, 1),
elevation: 4.0,
behavior: SnackBarBehavior.floating,
duration: Duration(seconds: 5),
));
} }
} finally { } finally {
setState(() => _isLoading = false); setState(() => _isLoading = false);
@ -110,7 +93,8 @@ class _LoginPageState extends State<LoginPage> {
child: Container( child: Container(
padding: EdgeInsets.fromLTRB(32, 32, 32, 40), padding: EdgeInsets.fromLTRB(32, 32, 32, 40),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color.fromRGBO(38, 17, 46, 0.859), // color: const Color.fromRGBO(38, 17, 46, 0.859),
color: const Color.fromRGBO(57, 38, 62, 0.9),
borderRadius: BorderRadius.all(Radius.circular(16)), borderRadius: BorderRadius.all(Radius.circular(16)),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(

View file

@ -1,9 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:pharmacy_mobile/auth/auth_service.dart'; import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/main.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/page_background_widget.dart';
import 'package:pharmacy_mobile/widgets/text_widget.dart';
import 'package:pharmacy_mobile/widgets/title_widget.dart';
class RegisterPage extends StatefulWidget { class RegisterPage extends StatefulWidget {
const RegisterPage({super.key}); const RegisterPage({super.key});
@ -17,6 +19,9 @@ class _RegisterPageState extends State<RegisterPage> {
final _emailController = TextEditingController(); final _emailController = TextEditingController();
final _passwordController = TextEditingController(); final _passwordController = TextEditingController();
final _confirmPasswordController = TextEditingController(); final _confirmPasswordController = TextEditingController();
final FocusNode _focusNode = FocusNode();
bool _isLoading = false;
Future<void> _signUp() async { Future<void> _signUp() async {
final email = _emailController.text; final email = _emailController.text;
@ -47,6 +52,8 @@ class _RegisterPageState extends State<RegisterPage> {
_emailController.dispose(); _emailController.dispose();
_passwordController.dispose(); _passwordController.dispose();
_confirmPasswordController.dispose(); _confirmPasswordController.dispose();
_focusNode.dispose();
_isLoading = false;
super.dispose(); super.dispose();
} }
@ -54,8 +61,58 @@ class _RegisterPageState extends State<RegisterPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: PageBackgroundWidget( body: PageBackgroundWidget(
child: Center(
child: Column( child: Column(
children: [], mainAxisAlignment: MainAxisAlignment.start,
children: [
const Gap(104),
const TitleWidget(firstTextSize: 20, secondTextSize: 32),
const Gap(32),
const TextWidget(text: 'Register'),
const Gap(16),
Padding(
padding: const EdgeInsets.only(left: 32, right: 32),
child: Container(
padding: EdgeInsets.fromLTRB(32, 32, 32, 40),
decoration: BoxDecoration(
color: const Color.fromRGBO(57, 38, 62, 0.9),
borderRadius: BorderRadius.all(Radius.circular(16)),
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(0, 0, 0, 0.4), // Subtle shadow to give depth
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
)
]),
child: Form(
child: Column(
children: [
InputWidget(label: 'Email', controller: _emailController),
const Gap(16),
InputWidget(
label: 'Password',
controller: _passwordController,
password: true,
),
const Gap(16),
InputWidget(
label: 'Confirm Password',
controller: _confirmPasswordController,
password: true,
),
const Gap(40),
// TextButton(onPressed: () => {_signIn()}, child: const Text('Login'))
if (_isLoading)
Center(child: CircularProgressIndicator(color: Colors.white))
else
ButtonWidget(text: 'Create Account', onPressed: _signUp)
],
)),
),
),
],
),
)), )),
); );
} }

View file

@ -13,29 +13,38 @@ class ButtonWidget extends StatelessWidget {
return ElevatedButton( return ElevatedButton(
style: outline == true style: outline == true
? OutlinedButton.styleFrom( ? OutlinedButton.styleFrom(
foregroundColor: Color.fromRGBO(0, 0, 0, 1), // text color foregroundColor: const Color.fromRGBO(0, 0, 0, 1),
side: const BorderSide(color: Color.fromRGBO(79, 51, 94, 1)), // border color backgroundColor: Colors.transparent,
side: const BorderSide(color: Color.fromRGBO(198, 133, 232, 1)),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), // rounded corners borderRadius: BorderRadius.circular(12),
), ),
minimumSize: Size(MediaQuery.of(context).size.width - 96, 44), // minimum size minimumSize: Size(MediaQuery.of(context).size.width - 96, 44), // minimum size
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
) )
: ElevatedButton.styleFrom( : ElevatedButton.styleFrom(
foregroundColor: Color.fromRGBO(0, 0, 0, 1), // text color foregroundColor: const Color.fromRGBO(0, 0, 0, 1), // text color
backgroundColor: const Color.fromRGBO(198, 133, 232, 1), // background color backgroundColor: const Color.fromRGBO(198, 133, 232, 1), // background color
side: const BorderSide(color: Color.fromRGBO(79, 51, 94, 1)), // border color side: const BorderSide(color: Color.fromRGBO(79, 51, 94, 1)), // border color
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), // rounded corners borderRadius: BorderRadius.circular(12), // rounded corners
), ),
minimumSize: Size(MediaQuery.of(context).size.width - 96, 44), // minimum size minimumSize: Size(MediaQuery.of(context).size.width - 96, 44), // minimum size
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
), ),
onPressed: onPressed, onPressed: onPressed,
child: Text( child: Text(
text, text,
style: GoogleFonts.outfit(textStyle: const TextStyle(fontSize: 14)), style: _textStyle(outline),
), ),
); );
} }
TextStyle _textStyle(bool? outline) {
if (outline == true) {
return GoogleFonts.outfit(textStyle: const TextStyle(fontSize: 14, color: Color.fromRGBO(198, 133, 232, 1)));
} else {
return GoogleFonts.outfit(textStyle: const TextStyle(fontSize: 14, color: Color.fromRGBO(0, 0, 0, 1)));
}
}
} }

View file

@ -16,7 +16,8 @@ class InputWidget extends StatelessWidget {
children: [ children: [
Text('$label:', Text('$label:',
style: GoogleFonts.outfit( style: GoogleFonts.outfit(
textStyle: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500), textStyle:
const TextStyle(color: Color.fromRGBO(255, 255, 255, 1), fontSize: 12, fontWeight: FontWeight.w500),
)), )),
const Gap(8), const Gap(8),
TextField( TextField(

View file

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
void showNotification(BuildContext context, String text, bool isPositive) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(text),
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),
),
);
}

View file

@ -57,14 +57,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
bottom_picker:
dependency: "direct main"
description:
name: bottom_picker
sha256: "8ede549685825df389135bebc7984416ed95f24d4f19631d21ad25c9c23db482"
url: "https://pub.dev"
source: hosted
version: "2.10.1"
characters: characters:
dependency: transitive dependency: transitive
description: description:
@ -113,14 +105,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.6" version: "3.0.6"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev"
source: hosted
version: "1.0.8"
dbus: dbus:
dependency: transitive dependency: transitive
description: description:
@ -774,5 +758,5 @@ packages:
source: hosted source: hosted
version: "2.0.3" version: "2.0.3"
sdks: sdks:
dart: ">=3.6.0 <4.0.0" dart: ">=3.6.1 <4.0.0"
flutter: ">=3.27.0" flutter: ">=3.27.0"

View file

@ -5,20 +5,18 @@ publish_to: "none"
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: ^3.6.0 sdk: ^3.6.1
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
cupertino_icons: ^1.0.8
google_fonts: ^6.2.1 google_fonts: ^6.2.1
gap: ^3.0.1 gap: ^3.0.1
go_router: ^14.6.3 go_router: ^14.6.3
supabase_flutter: ^2.8.3 supabase_flutter: ^2.8.3
font_awesome_flutter: ^10.8.0 font_awesome_flutter: ^10.8.0
uuid: ^4.5.1 uuid: ^4.5.1
bottom_picker: ^2.10.1
intl: ^0.20.2 intl: ^0.20.2
visibility_detector: ^0.4.0+2 visibility_detector: ^0.4.0+2
internet_connection_checker: ^3.0.1 internet_connection_checker: ^3.0.1