Add explicit types and improve type safety across codebase
This commit adds explicit type annotations to variables, function parameters, and return types throughout the codebase, particularly in widget trees, Bloc logic, and repository implementations. The changes improve code readability, maintainability, and type safety, and align with Dart best practices. No business logic was changed.
This commit is contained in:
@@ -23,7 +23,7 @@ export 'package:core_localization/core_localization.dart';
|
||||
/// A [Module] for the client authentication feature.
|
||||
class ClientAuthenticationModule extends Module {
|
||||
@override
|
||||
List<Module> get imports => [DataConnectModule()];
|
||||
List<Module> get imports => <Module>[DataConnectModule()];
|
||||
|
||||
@override
|
||||
void binds(Injector i) {
|
||||
@@ -59,7 +59,7 @@ class ClientAuthenticationModule extends Module {
|
||||
}
|
||||
|
||||
@override
|
||||
void routes(r) {
|
||||
void routes(RouteManager r) {
|
||||
r.child('/', child: (_) => const ClientGetStartedPage());
|
||||
r.child('/client-sign-in', child: (_) => const ClientSignInPage());
|
||||
r.child('/client-sign-up', child: (_) => const ClientSignUpPage());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
||||
import 'package:firebase_data_connect/src/core/ref.dart';
|
||||
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||
import 'package:krow_domain/krow_domain.dart' as domain;
|
||||
import '../../domain/repositories/auth_repository_interface.dart';
|
||||
@@ -24,12 +25,12 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
required String password,
|
||||
}) async {
|
||||
try {
|
||||
final credential = await _firebaseAuth.signInWithEmailAndPassword(
|
||||
final firebase.UserCredential credential = await _firebaseAuth.signInWithEmailAndPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
|
||||
final firebaseUser = credential.user;
|
||||
final firebase.User? firebaseUser = credential.user;
|
||||
if (firebaseUser == null) {
|
||||
throw Exception('Sign-in failed, no Firebase user received.');
|
||||
}
|
||||
@@ -59,12 +60,12 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
required String password,
|
||||
}) async {
|
||||
try {
|
||||
final credential = await _firebaseAuth.createUserWithEmailAndPassword(
|
||||
final firebase.UserCredential credential = await _firebaseAuth.createUserWithEmailAndPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
|
||||
final firebaseUser = credential.user;
|
||||
final firebase.User? firebaseUser = credential.user;
|
||||
if (firebaseUser == null) {
|
||||
throw Exception('Sign-up failed, Firebase user could not be created.');
|
||||
}
|
||||
@@ -72,20 +73,20 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
// Client-specific business logic:
|
||||
// 1. Create a `Business` entity.
|
||||
// 2. Create a `User` entity associated with the business.
|
||||
final createBusinessResponse = await _dataConnect.createBusiness(
|
||||
final OperationResult<dc.CreateBusinessData, dc.CreateBusinessVariables> createBusinessResponse = await _dataConnect.createBusiness(
|
||||
businessName: companyName,
|
||||
userId: firebaseUser.uid,
|
||||
rateGroup: dc.BusinessRateGroup.STANDARD,
|
||||
status: dc.BusinessStatus.PENDING,
|
||||
).execute();
|
||||
|
||||
final businessData = createBusinessResponse.data?.business_insert;
|
||||
final dc.CreateBusinessBusinessInsert? businessData = createBusinessResponse.data?.business_insert;
|
||||
if (businessData == null) {
|
||||
await firebaseUser.delete(); // Rollback if business creation fails
|
||||
throw Exception('Business creation failed after Firebase user registration.');
|
||||
}
|
||||
|
||||
final createUserResponse = await _dataConnect.createUser(
|
||||
final OperationResult<dc.CreateUserData, dc.CreateUserVariables> createUserResponse = await _dataConnect.createUser(
|
||||
id: firebaseUser.uid,
|
||||
role: dc.UserBaseRole.USER,
|
||||
)
|
||||
@@ -93,7 +94,7 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
.userRole('BUSINESS')
|
||||
.execute();
|
||||
|
||||
final newUserData = createUserResponse.data?.user_insert;
|
||||
final dc.CreateUserUserInsert? newUserData = createUserResponse.data?.user_insert;
|
||||
if (newUserData == null) {
|
||||
await firebaseUser.delete(); // Rollback if user profile creation fails
|
||||
// TO-DO: Also delete the created Business if this fails
|
||||
@@ -137,27 +138,27 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
required String firebaseUserId,
|
||||
required String? fallbackEmail,
|
||||
}) async {
|
||||
final response = await _dataConnect.getUserById(id: firebaseUserId).execute();
|
||||
final user = response.data?.user;
|
||||
final QueryResult<dc.GetUserByIdData, dc.GetUserByIdVariables> response = await _dataConnect.getUserById(id: firebaseUserId).execute();
|
||||
final dc.GetUserByIdUser? user = response.data?.user;
|
||||
if (user == null) {
|
||||
throw Exception('Authenticated user profile not found in database.');
|
||||
}
|
||||
|
||||
final email = user.email ?? fallbackEmail;
|
||||
final String? email = user.email ?? fallbackEmail;
|
||||
if (email == null || email.isEmpty) {
|
||||
throw Exception('User email is missing in profile data.');
|
||||
}
|
||||
|
||||
final domainUser = domain.User(
|
||||
final domain.User domainUser = domain.User(
|
||||
id: user.id,
|
||||
email: email,
|
||||
role: user.role.stringValue,
|
||||
);
|
||||
|
||||
final businessResponse = await _dataConnect.getBusinessesByUserId(
|
||||
final QueryResult<dc.GetBusinessesByUserIdData, dc.GetBusinessesByUserIdVariables> businessResponse = await _dataConnect.getBusinessesByUserId(
|
||||
userId: firebaseUserId,
|
||||
).execute();
|
||||
final business = businessResponse.data.businesses.isNotEmpty
|
||||
final dc.GetBusinessesByUserIdBusinesses? business = businessResponse.data.businesses.isNotEmpty
|
||||
? businessResponse.data.businesses.first
|
||||
: null;
|
||||
|
||||
|
||||
@@ -11,5 +11,5 @@ class SignInWithEmailArguments extends UseCaseArgument {
|
||||
const SignInWithEmailArguments({required this.email, required this.password});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [email, password];
|
||||
List<Object?> get props => <Object?>[email, password];
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ class SignInWithSocialArguments extends UseCaseArgument {
|
||||
const SignInWithSocialArguments({required this.provider});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [provider];
|
||||
List<Object?> get props => <Object?>[provider];
|
||||
}
|
||||
|
||||
@@ -18,5 +18,5 @@ class SignUpWithEmailArguments extends UseCaseArgument {
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [companyName, email, password];
|
||||
List<Object?> get props => <Object?>[companyName, email, password];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:krow_domain/src/entities/users/user.dart';
|
||||
import '../../domain/arguments/sign_in_with_email_arguments.dart';
|
||||
import '../../domain/arguments/sign_in_with_social_arguments.dart';
|
||||
import '../../domain/arguments/sign_up_with_email_arguments.dart';
|
||||
@@ -50,7 +51,7 @@ class ClientAuthBloc extends Bloc<ClientAuthEvent, ClientAuthState> {
|
||||
) async {
|
||||
emit(state.copyWith(status: ClientAuthStatus.loading));
|
||||
try {
|
||||
final user = await _signInWithEmail(
|
||||
final User user = await _signInWithEmail(
|
||||
SignInWithEmailArguments(email: event.email, password: event.password),
|
||||
);
|
||||
emit(state.copyWith(status: ClientAuthStatus.authenticated, user: user));
|
||||
@@ -71,7 +72,7 @@ class ClientAuthBloc extends Bloc<ClientAuthEvent, ClientAuthState> {
|
||||
) async {
|
||||
emit(state.copyWith(status: ClientAuthStatus.loading));
|
||||
try {
|
||||
final user = await _signUpWithEmail(
|
||||
final User user = await _signUpWithEmail(
|
||||
SignUpWithEmailArguments(
|
||||
companyName: event.companyName,
|
||||
email: event.email,
|
||||
@@ -96,7 +97,7 @@ class ClientAuthBloc extends Bloc<ClientAuthEvent, ClientAuthState> {
|
||||
) async {
|
||||
emit(state.copyWith(status: ClientAuthStatus.loading));
|
||||
try {
|
||||
final user = await _signInWithSocial(
|
||||
final User user = await _signInWithSocial(
|
||||
SignInWithSocialArguments(provider: event.provider),
|
||||
);
|
||||
emit(state.copyWith(status: ClientAuthStatus.authenticated, user: user));
|
||||
|
||||
@@ -5,7 +5,7 @@ abstract class ClientAuthEvent extends Equatable {
|
||||
const ClientAuthEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
List<Object?> get props => <Object?>[];
|
||||
}
|
||||
|
||||
/// Event dispatched when a user attempts to sign in with email and password.
|
||||
@@ -16,7 +16,7 @@ class ClientSignInRequested extends ClientAuthEvent {
|
||||
const ClientSignInRequested({required this.email, required this.password});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [email, password];
|
||||
List<Object?> get props => <Object?>[email, password];
|
||||
}
|
||||
|
||||
/// Event dispatched when a user attempts to create a new business account.
|
||||
@@ -32,7 +32,7 @@ class ClientSignUpRequested extends ClientAuthEvent {
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [companyName, email, password];
|
||||
List<Object?> get props => <Object?>[companyName, email, password];
|
||||
}
|
||||
|
||||
/// Event dispatched for third-party authentication (Google/Apple).
|
||||
@@ -42,7 +42,7 @@ class ClientSocialSignInRequested extends ClientAuthEvent {
|
||||
const ClientSocialSignInRequested({required this.provider});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [provider];
|
||||
List<Object?> get props => <Object?>[provider];
|
||||
}
|
||||
|
||||
/// Event dispatched when the user requests to terminate their session.
|
||||
|
||||
@@ -50,5 +50,5 @@ class ClientAuthState extends Equatable {
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [status, user, errorMessage];
|
||||
List<Object?> get props => <Object?>[status, user, errorMessage];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class ClientGetStartedPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
// Background Illustration/Visuals from prototype
|
||||
Positioned(
|
||||
top: -100,
|
||||
@@ -28,7 +28,7 @@ class ClientGetStartedPage extends StatelessWidget {
|
||||
|
||||
SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
const SizedBox(height: UiConstants.space10),
|
||||
// Logo
|
||||
Center(
|
||||
@@ -48,7 +48,7 @@ class ClientGetStartedPage extends StatelessWidget {
|
||||
horizontal: UiConstants.space6,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
// Representative cards from prototype
|
||||
Positioned(
|
||||
top: 20,
|
||||
@@ -76,7 +76,7 @@ class ClientGetStartedPage extends StatelessWidget {
|
||||
vertical: UiConstants.space10,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Text(
|
||||
t.client_authentication.get_started_page.title,
|
||||
textAlign: TextAlign.center,
|
||||
@@ -132,7 +132,7 @@ class _ShiftOrderCard extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.white,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
boxShadow: [
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
@@ -143,9 +143,9 @@ class _ShiftOrderCard extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space1),
|
||||
decoration: BoxDecoration(
|
||||
@@ -195,7 +195,7 @@ class _WorkerProfileCard extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.white,
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
boxShadow: [
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
@@ -204,7 +204,7 @@ class _WorkerProfileCard extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 16,
|
||||
backgroundColor: UiColors.primary.withOpacity(0.1),
|
||||
@@ -214,7 +214,7 @@ class _WorkerProfileCard extends StatelessWidget {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Text('Alex Thompson', style: UiTypography.footnote1b),
|
||||
Text(
|
||||
'Professional Waiter • 4.9★',
|
||||
@@ -236,7 +236,7 @@ class _CalendarCard extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.accent,
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
boxShadow: [
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
|
||||
@@ -35,13 +35,13 @@ class ClientSignInPage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.client_authentication.sign_in_page;
|
||||
final authBloc = Modular.get<ClientAuthBloc>();
|
||||
final TranslationsClientAuthenticationSignInPageEn i18n = t.client_authentication.sign_in_page;
|
||||
final ClientAuthBloc authBloc = Modular.get<ClientAuthBloc>();
|
||||
|
||||
return BlocProvider.value(
|
||||
value: authBloc,
|
||||
child: BlocConsumer<ClientAuthBloc, ClientAuthState>(
|
||||
listener: (context, state) {
|
||||
listener: (BuildContext context, ClientAuthState state) {
|
||||
if (state.status == ClientAuthStatus.authenticated) {
|
||||
Modular.to.navigateClientHome();
|
||||
} else if (state.status == ClientAuthStatus.error) {
|
||||
@@ -52,8 +52,8 @@ class ClientSignInPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
final isLoading = state.status == ClientAuthStatus.loading;
|
||||
builder: (BuildContext context, ClientAuthState state) {
|
||||
final bool isLoading = state.status == ClientAuthStatus.loading;
|
||||
|
||||
return Scaffold(
|
||||
appBar: const UiAppBar(showBackButton: true),
|
||||
@@ -69,14 +69,14 @@ class ClientSignInPage extends StatelessWidget {
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
SectionTitle(title: i18n.title, subtitle: i18n.subtitle),
|
||||
const SizedBox(height: UiConstants.space8),
|
||||
|
||||
// Sign In Form
|
||||
ClientSignInForm(
|
||||
isLoading: isLoading,
|
||||
onSignIn: ({required email, required password}) =>
|
||||
onSignIn: ({required String email, required String password}) =>
|
||||
_handleSignIn(
|
||||
context,
|
||||
email: email,
|
||||
@@ -99,7 +99,7 @@ class ClientSignInPage extends StatelessWidget {
|
||||
// Sign Up Link
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Text(
|
||||
i18n.no_account,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
|
||||
@@ -39,13 +39,13 @@ class ClientSignUpPage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.client_authentication.sign_up_page;
|
||||
final authBloc = Modular.get<ClientAuthBloc>();
|
||||
final TranslationsClientAuthenticationSignUpPageEn i18n = t.client_authentication.sign_up_page;
|
||||
final ClientAuthBloc authBloc = Modular.get<ClientAuthBloc>();
|
||||
|
||||
return BlocProvider.value(
|
||||
value: authBloc,
|
||||
child: BlocConsumer<ClientAuthBloc, ClientAuthState>(
|
||||
listener: (context, state) {
|
||||
listener: (BuildContext context, ClientAuthState state) {
|
||||
if (state.status == ClientAuthStatus.authenticated) {
|
||||
Modular.to.navigateClientHome();
|
||||
} else if (state.status == ClientAuthStatus.error) {
|
||||
@@ -56,8 +56,8 @@ class ClientSignUpPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
final isLoading = state.status == ClientAuthStatus.loading;
|
||||
builder: (BuildContext context, ClientAuthState state) {
|
||||
final bool isLoading = state.status == ClientAuthStatus.loading;
|
||||
|
||||
return Scaffold(
|
||||
appBar: const UiAppBar(showBackButton: true),
|
||||
@@ -73,7 +73,7 @@ class ClientSignUpPage extends StatelessWidget {
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
SectionTitle(title: i18n.title, subtitle: i18n.subtitle),
|
||||
const SizedBox(height: UiConstants.space8),
|
||||
|
||||
@@ -82,9 +82,9 @@ class ClientSignUpPage extends StatelessWidget {
|
||||
isLoading: isLoading,
|
||||
onSignUp:
|
||||
({
|
||||
required companyName,
|
||||
required email,
|
||||
required password,
|
||||
required String companyName,
|
||||
required String email,
|
||||
required String password,
|
||||
}) => _handleSignUp(
|
||||
context,
|
||||
companyName: companyName,
|
||||
@@ -108,7 +108,7 @@ class ClientSignUpPage extends StatelessWidget {
|
||||
// Sign In Link
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Text(
|
||||
i18n.has_account,
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
|
||||
@@ -26,8 +26,8 @@ class ClientSignInForm extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ClientSignInFormState extends State<ClientSignInForm> {
|
||||
final _emailController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
final TextEditingController _emailController = TextEditingController();
|
||||
final TextEditingController _passwordController = TextEditingController();
|
||||
bool _obscurePassword = true;
|
||||
|
||||
@override
|
||||
@@ -46,10 +46,10 @@ class _ClientSignInFormState extends State<ClientSignInForm> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.client_authentication.sign_in_page;
|
||||
final TranslationsClientAuthenticationSignInPageEn i18n = t.client_authentication.sign_in_page;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
// Email Field
|
||||
UiTextField(
|
||||
label: i18n.email_label,
|
||||
|
||||
@@ -30,10 +30,10 @@ class ClientSignUpForm extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ClientSignUpFormState extends State<ClientSignUpForm> {
|
||||
final _companyController = TextEditingController();
|
||||
final _emailController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
final _confirmPasswordController = TextEditingController();
|
||||
final TextEditingController _companyController = TextEditingController();
|
||||
final TextEditingController _emailController = TextEditingController();
|
||||
final TextEditingController _passwordController = TextEditingController();
|
||||
final TextEditingController _confirmPasswordController = TextEditingController();
|
||||
bool _obscurePassword = true;
|
||||
|
||||
@override
|
||||
@@ -62,10 +62,10 @@ class _ClientSignUpFormState extends State<ClientSignUpForm> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.client_authentication.sign_up_page;
|
||||
final TranslationsClientAuthenticationSignUpPageEn i18n = t.client_authentication.sign_up_page;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
// Company Name Field
|
||||
UiTextField(
|
||||
label: i18n.company_label,
|
||||
|
||||
@@ -15,7 +15,7 @@ class AuthDivider extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
const Expanded(child: Divider()),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space4),
|
||||
|
||||
@@ -15,7 +15,7 @@ class SectionTitle extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Text(title, style: UiTypography.headline1m),
|
||||
Text(subtitle, style: UiTypography.body2r.textSecondary),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user