This commit is contained in:
Patrick Alvin Alcala 2025-03-12 18:09:04 +08:00
parent a76d3a0f35
commit e3dc94a768
33 changed files with 368 additions and 184 deletions

View file

@ -20,4 +20,10 @@ class AuthService {
final user = session?.user;
return user?.email;
}
String? getCurrentUserId() {
final session = _supabase.auth.currentSession;
final user = session?.user;
return user?.id;
}
}

View file

@ -0,0 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_event.dart';
Future<bool> blocGetGuestStatus(BuildContext context) async {
try {
final guestBloc = context.read<GuestBloc>();
guestBloc.add(GuestGetStatus());
return guestBloc.state.value;
} catch (e) {
return false;
}
}

View file

@ -0,0 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_event.dart';
Future<bool> blocSetGuestOff(BuildContext context) async {
try {
final guestBloc = context.read<GuestBloc>();
guestBloc.add(GuestSetOff());
return true;
} catch (e) {
return false;
}
}

View file

@ -0,0 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_event.dart';
Future<bool> blocSetGuestOn(BuildContext context) async {
try {
final guestBloc = context.read<GuestBloc>();
guestBloc.add(GuestSetOn());
return true;
} catch (e) {
return false;
}
}

View file

@ -0,0 +1,17 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'guest_event.dart';
import 'guest_state.dart';
class GuestBloc extends Bloc<GuestEvent, GuestState> {
GuestBloc() : super(GuestState(false)) {
on<GuestSetOn>((event, emit) {
emit(GuestState(true));
});
on<GuestSetOff>((event, emit) {
emit(GuestState(false));
});
on<GuestGetStatus>((event, emit) {
emit(state);
});
}
}

View file

@ -0,0 +1,7 @@
abstract class GuestEvent {}
class GuestSetOn extends GuestEvent {}
class GuestSetOff extends GuestEvent {}
class GuestGetStatus extends GuestEvent {}

View file

@ -0,0 +1,5 @@
class GuestState {
final bool value;
GuestState(this.value);
}

View file

@ -0,0 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/user/user_bloc.dart';
import 'package:pharmacy_mobile/blocs/user/user_event.dart';
Future<String> blocGetUser(BuildContext context) async {
try {
final userBloc = context.read<UserBloc>();
userBloc.add(UserGetValue());
return userBloc.state.value;
} catch (e) {
return '';
}
}

View file

@ -0,0 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/user/user_bloc.dart';
import 'package:pharmacy_mobile/blocs/user/user_event.dart';
Future<bool> blocSetUser(BuildContext context, String value) async {
try {
final userBloc = context.read<UserBloc>();
userBloc.add(UserSetValue(value));
return true;
} catch (e) {
return false;
}
}

View file

@ -0,0 +1,14 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pharmacy_mobile/blocs/user/user_event.dart';
import 'package:pharmacy_mobile/blocs/user/user_state.dart';
class UserBloc extends Bloc<UserEvent, UserState> {
UserBloc() : super(UserState('')) {
on<UserSetValue>((event, emit) {
emit(UserState(event.value));
});
on<UserGetValue>((event, emit) {
emit(state);
});
}
}

View file

@ -0,0 +1,8 @@
abstract class UserEvent {}
class UserSetValue extends UserEvent {
final String value;
UserSetValue(this.value);
}
class UserGetValue extends UserEvent {}

View file

@ -0,0 +1,5 @@
class UserState {
final String value;
UserState(this.value);
}

View file

@ -1,28 +0,0 @@
// import 'package:supabase_flutter/supabase_flutter.dart';
// import 'package:pharmacy_mobile/main.dart';
// Future<void> signUp() async {
// try {
// await supabase.auth.signUp(
// email: email,
// password: password,
// );
// // if (mounted) {
// // context.showSnackBar('Check your email for a login link!');
// // _emailController.clear();
// // }
// } on AuthException catch (error) {
// if (mounted) context.showSnackBar(error.message, isError: true);
// } catch (error) {
// if (mounted) {
// context.showSnackBar('Unexpected error occurred', isError: true);
// }
// } finally {
// if (mounted) {
// setState(() {
// _isLoading = false;
// });
// }
// }
// }

View file

@ -1,5 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:pharmacy_mobile/auth/auth_gate.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart';
import 'package:pharmacy_mobile/blocs/user/user_bloc.dart';
import 'package:pharmacy_mobile/pages/add_category_page.dart';
import 'package:pharmacy_mobile/pages/add_generics_page.dart';
import 'package:pharmacy_mobile/pages/add_manufacturer.dart';
@ -15,13 +18,14 @@ import 'package:go_router/go_router.dart';
import 'package:pharmacy_mobile/pages/main_page.dart';
import 'package:pharmacy_mobile/pages/register_page.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Future<void> main() async {
await dotenv.load(fileName: ".env");
WidgetsFlutterBinding.ensureInitialized();
final supUrl = "https://lijihnvjlucyvxfhghqd.supabase.co";
final supAnonkey =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImxpamlobnZqbHVjeXZ4ZmhnaHFkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MjQ1NjEyODYsImV4cCI6MjA0MDEzNzI4Nn0.N3_FLKm02OdprL9m3P0CzuV8kdbCrrJKaVdtgVR3PSk";
final supUrl = dotenv.env['SUPABASE_URL']!;
final supAnonkey = dotenv.env['SUPABASE_ANON_KEY']!;
await Supabase.initialize(
url: supUrl,
@ -112,12 +116,22 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => GuestBloc(),
),
BlocProvider(
create: (context) => UserBloc(),
),
],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
),
routerConfig: _router,
),
routerConfig: _router,
);
}
}

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/blocs/guest/functions/bloc_getgueststatus.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart';
import 'package:pharmacy_mobile/widgets/customer_pagebackground_widget.dart';
import 'package:pharmacy_mobile/widgets/customer_title_widget.dart';
@ -16,11 +17,25 @@ class CustomerProfilePage extends StatefulWidget {
}
class _CustomerProfilePageState extends State<CustomerProfilePage> {
final authService = AuthService();
final _authService = AuthService();
late bool _isGuest = false;
void _signOut() async {
// ignore: use_build_context_synchronously
await authService.signOut().then((_) => {context.go('/'), showNotification(context, 'Logged Out', true)});
await _authService.signOut().then((_) => {context.go('/'), showNotification(context, 'Logged Out', true)});
}
void checkGuest() async {
final guest = await blocGetGuestStatus(context);
setState(() {
_isGuest = guest;
});
}
@override
void initState() {
checkGuest();
super.initState();
}
@override
@ -34,7 +49,7 @@ class _CustomerProfilePageState extends State<CustomerProfilePage> {
const Gap(68),
const CustomerTitleWidget(),
const Gap(32),
const TextWidget(text: 'My Profile'),
_isGuest ? const TextWidget(text: 'Guest Profile') : const TextWidget(text: 'My Profile'),
const Gap(16),
const Gap(32),
ButtonWidget(text: 'Log Out', onPressed: _signOut)

View file

@ -1,8 +1,13 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/blocs/user/functions/bloc_getuser.dart';
import 'package:pharmacy_mobile/blocs/user/functions/bloc_setuser.dart';
import 'package:pharmacy_mobile/blocs/user/user_bloc.dart';
import 'package:pharmacy_mobile/blocs/user/user_event.dart';
import 'package:pharmacy_mobile/tables/cart.dart';
import 'package:pharmacy_mobile/tables/stocks.dart';
import 'package:pharmacy_mobile/tables/storage.dart';
@ -43,16 +48,14 @@ class _CustomerSearchPageState extends State<CustomerSearchPage> {
_stockList = await _stocks.getList();
}
Future<String> _getCurrentUser() async {
final result = _authService.getCurrentUser();
Future<String> _getCurrentUserId() async {
final result = _authService.getCurrentUserId();
return result.toString();
}
Future<void> _getCarts() async {
final currentUser = await _getCurrentUser();
log('currentUser: $currentUser');
final currentUser = await _getCurrentUserId();
_cartList = await _carts.getCart(currentUser);
log('cart: ${_cartList.toString()}');
}
// Future<void> _getAllMedicines() async {
@ -82,7 +85,7 @@ class _CustomerSearchPageState extends State<CustomerSearchPage> {
void autoRun() async {
await _getAllStocks();
await _getCarts();
// await _getAllMedicines();
// // // await _getAllMedicines();
await _getURL();
}
@ -125,31 +128,6 @@ class _CustomerSearchPageState extends State<CustomerSearchPage> {
),
),
const Gap(32),
// Row(
// mainAxisAlignment: MainAxisAlignment.end,
// children: [
// ToggleSwitch(
// fontSize: 12,
// minWidth: 64,
// minHeight: 32,
// initialLabelIndex: 1,
// cornerRadius: 20,
// activeFgColor: Colors.white,
// inactiveBgColor: const Color.fromRGBO(81, 81, 81, 1),
// inactiveFgColor: const Color.fromRGBO(177, 175, 175, 1),
// totalSwitches: 2,
// labels: ['All', 'Stocks'],
// activeBgColors: [
// [const Color.fromRGBO(40, 112, 143, 1)],
// [const Color.fromRGBO(40, 112, 143, 1)],
// ],
// // onToggle: (index) {
// // print('switched to: $index');
// // },
// ),
// const Gap(8)
// ],
// ),
const IndicatorWidget(text: 'All Stocks'),
const Gap(8),
SingleChildScrollView(

View file

@ -1,6 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:gap/gap.dart';
import 'package:pharmacy_mobile/blocs/guest/functions/bloc_setgueston.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_event.dart';
import 'package:pharmacy_mobile/widgets/button_widget.dart';
import 'package:pharmacy_mobile/widgets/image_widget.dart';
import 'package:pharmacy_mobile/widgets/page_background_widget.dart';
@ -21,6 +25,14 @@ class IndexPage extends StatelessWidget {
context.push('/register');
}
void loginAsGuest() async {
final setGuest = await blocSetGuestOn(context);
if (setGuest) {
// ignore: use_build_context_synchronously
context.push('/customer');
}
}
return Scaffold(
resizeToAvoidBottomInset: false,
body: PageBackgroundWidget(
@ -41,6 +53,16 @@ class IndexPage extends StatelessWidget {
ButtonWidget(text: 'Login', onPressed: gotoLogin),
const Gap(8),
ButtonWidget(text: 'Register', onPressed: gotoRegister, outline: true),
const Gap(16),
GestureDetector(
onTap: loginAsGuest,
child: const TextWidget(
text: "Login as Guest",
size: 12,
underlined: true,
color: Color.fromRGBO(198, 133, 232, 1),
),
),
const Gap(32),
const SloganWidget(),
const Gap(32),

View file

@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:gap/gap.dart';
import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/blocs/guest/functions/bloc_getgueststatus.dart';
import 'package:pharmacy_mobile/blocs/guest/functions/bloc_setguestoff.dart';
import 'package:pharmacy_mobile/widgets/buttonwithprogress_widget.dart';
import 'package:pharmacy_mobile/widgets/glossy_container_widget.dart';
import 'package:pharmacy_mobile/widgets/input_form_widget.dart';
@ -55,10 +57,14 @@ class _LoginPageState extends State<LoginPage> {
if (await InternetConnectionChecker.instance.hasConnection) {
await _authService.signIn(email, password);
if (mounted) {
final user = _authService.getCurrentUser();
final user = _authService.getCurrentUser();
if (user != null) {
if (user != null) {
// ignore: use_build_context_synchronously
final disableGuest = await blocSetGuestOff(context);
if (disableGuest) {
// ignore: use_build_context_synchronously
showNotification(context, 'Login Successful', true);
WidgetsBinding.instance.addPostFrameCallback((_) {
@ -68,6 +74,9 @@ class _LoginPageState extends State<LoginPage> {
if (mounted) context.push('/customer');
}
});
} else {
// ignore: use_build_context_synchronously
showNotification(context, 'Error: Login failed', false);
}
}
} else {

View file

@ -1,7 +1,12 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:pharmacy_mobile/auth/auth_service.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_bloc.dart';
import 'package:pharmacy_mobile/blocs/guest/guest_event.dart';
import 'package:pharmacy_mobile/widgets/buttonwithprogress_widget.dart';
import 'package:pharmacy_mobile/widgets/glossy_container_widget.dart';
import 'package:pharmacy_mobile/widgets/input_form_widget.dart';

View file

@ -5,9 +5,9 @@ import 'package:supabase_flutter/supabase_flutter.dart';
class Carts {
final SupabaseClient _supabase = Supabase.instance.client;
Future<List> getCart(String email) async {
Future<List> getCart(String uuid) async {
try {
final data = await _supabase.from('carts').select('carts_uuid').eq('email', email);
final data = await _supabase.from('carts').select('carts_uuid').eq('user_id', uuid);
log('data: $data');
return data.toList();
} catch (e) {

View file

@ -26,7 +26,7 @@ class ButtonWidget extends StatelessWidget {
)
: ElevatedButton.styleFrom(
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),
side: const BorderSide(color: Color.fromRGBO(79, 51, 94, 0.4)), // border color
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20), // rounded corners

View file

@ -20,8 +20,8 @@ class TextWidget extends StatelessWidget {
fontSize: size ?? 28,
fontWeight: bold == true ? FontWeight.bold : FontWeight.normal,
decoration: underlined == true ? TextDecoration.underline : TextDecoration.none,
decorationColor: const Color.fromRGBO(255, 255, 255, 1),
decorationThickness: 2);
decorationColor: color ?? const Color.fromRGBO(255, 255, 255, 1),
decorationThickness: 1);
return title == true
? Text(text, style: GoogleFonts.outfit(textStyle: textStyle))