feat: Refactor session management and improve user session data retrieval
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
import 'package:krow_domain/krow_domain.dart' as domain;
|
|
||||||
|
|
||||||
class ClientBusinessSession {
|
class ClientBusinessSession {
|
||||||
final String id;
|
final String id;
|
||||||
final String businessName;
|
final String businessName;
|
||||||
@@ -19,15 +17,9 @@ class ClientBusinessSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ClientSession {
|
class ClientSession {
|
||||||
final domain.User user;
|
|
||||||
final String? userPhotoUrl;
|
|
||||||
final ClientBusinessSession? business;
|
final ClientBusinessSession? business;
|
||||||
|
|
||||||
const ClientSession({
|
const ClientSession({required this.business});
|
||||||
required this.user,
|
|
||||||
required this.userPhotoUrl,
|
|
||||||
required this.business,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClientSessionStore {
|
class ClientSessionStore {
|
||||||
|
|||||||
@@ -24,9 +24,8 @@ import '../../domain/repositories/auth_repository_interface.dart';
|
|||||||
/// identity management and Krow's Data Connect SDK for storing user profile data.
|
/// identity management and Krow's Data Connect SDK for storing user profile data.
|
||||||
class AuthRepositoryImpl implements AuthRepositoryInterface {
|
class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||||
/// Creates an [AuthRepositoryImpl] with the real dependencies.
|
/// Creates an [AuthRepositoryImpl] with the real dependencies.
|
||||||
AuthRepositoryImpl({
|
AuthRepositoryImpl({dc.DataConnectService? service})
|
||||||
dc.DataConnectService? service,
|
: _service = service ?? dc.DataConnectService.instance;
|
||||||
}) : _service = service ?? dc.DataConnectService.instance;
|
|
||||||
|
|
||||||
final dc.DataConnectService _service;
|
final dc.DataConnectService _service;
|
||||||
|
|
||||||
@@ -36,11 +35,8 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
required String password,
|
required String password,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
final firebase.UserCredential credential =
|
final firebase.UserCredential credential = await _service.auth
|
||||||
await _service.auth.signInWithEmailAndPassword(
|
.signInWithEmailAndPassword(email: email, password: password);
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
);
|
|
||||||
|
|
||||||
final firebase.User? firebaseUser = credential.user;
|
final firebase.User? firebaseUser = credential.user;
|
||||||
if (firebaseUser == null) {
|
if (firebaseUser == null) {
|
||||||
@@ -60,9 +56,7 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
technicalMessage: 'Firebase error code: ${e.code}',
|
technicalMessage: 'Firebase error code: ${e.code}',
|
||||||
);
|
);
|
||||||
} else if (e.code == 'network-request-failed') {
|
} else if (e.code == 'network-request-failed') {
|
||||||
throw NetworkException(
|
throw NetworkException(technicalMessage: 'Firebase: ${e.message}');
|
||||||
technicalMessage: 'Firebase: ${e.message}',
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
throw SignInFailedException(
|
throw SignInFailedException(
|
||||||
technicalMessage: 'Firebase auth error: ${e.message}',
|
technicalMessage: 'Firebase auth error: ${e.message}',
|
||||||
@@ -71,9 +65,7 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
} on domain.AppException {
|
} on domain.AppException {
|
||||||
rethrow;
|
rethrow;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw SignInFailedException(
|
throw SignInFailedException(technicalMessage: 'Unexpected error: $e');
|
||||||
technicalMessage: 'Unexpected error: $e',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,11 +80,8 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 1: Try to create Firebase Auth user
|
// Step 1: Try to create Firebase Auth user
|
||||||
final firebase.UserCredential credential =
|
final firebase.UserCredential credential = await _service.auth
|
||||||
await _service.auth.createUserWithEmailAndPassword(
|
.createUserWithEmailAndPassword(email: email, password: password);
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
);
|
|
||||||
|
|
||||||
firebaseUser = credential.user;
|
firebaseUser = credential.user;
|
||||||
if (firebaseUser == null) {
|
if (firebaseUser == null) {
|
||||||
@@ -111,9 +100,7 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
);
|
);
|
||||||
} on firebase.FirebaseAuthException catch (e) {
|
} on firebase.FirebaseAuthException catch (e) {
|
||||||
if (e.code == 'weak-password') {
|
if (e.code == 'weak-password') {
|
||||||
throw WeakPasswordException(
|
throw WeakPasswordException(technicalMessage: 'Firebase: ${e.message}');
|
||||||
technicalMessage: 'Firebase: ${e.message}',
|
|
||||||
);
|
|
||||||
} else if (e.code == 'email-already-in-use') {
|
} else if (e.code == 'email-already-in-use') {
|
||||||
// Email exists in Firebase Auth - try to sign in and complete registration
|
// Email exists in Firebase Auth - try to sign in and complete registration
|
||||||
return await _handleExistingFirebaseAccount(
|
return await _handleExistingFirebaseAccount(
|
||||||
@@ -122,9 +109,7 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
companyName: companyName,
|
companyName: companyName,
|
||||||
);
|
);
|
||||||
} else if (e.code == 'network-request-failed') {
|
} else if (e.code == 'network-request-failed') {
|
||||||
throw NetworkException(
|
throw NetworkException(technicalMessage: 'Firebase: ${e.message}');
|
||||||
technicalMessage: 'Firebase: ${e.message}',
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
throw SignUpFailedException(
|
throw SignUpFailedException(
|
||||||
technicalMessage: 'Firebase auth error: ${e.message}',
|
technicalMessage: 'Firebase auth error: ${e.message}',
|
||||||
@@ -133,15 +118,17 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
} on domain.AppException {
|
} on domain.AppException {
|
||||||
// Rollback for our known exceptions
|
// Rollback for our known exceptions
|
||||||
await _rollbackSignUp(
|
await _rollbackSignUp(
|
||||||
firebaseUser: firebaseUser, businessId: createdBusinessId);
|
firebaseUser: firebaseUser,
|
||||||
|
businessId: createdBusinessId,
|
||||||
|
);
|
||||||
rethrow;
|
rethrow;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Rollback: Clean up any partially created resources
|
// Rollback: Clean up any partially created resources
|
||||||
await _rollbackSignUp(
|
await _rollbackSignUp(
|
||||||
firebaseUser: firebaseUser, businessId: createdBusinessId);
|
firebaseUser: firebaseUser,
|
||||||
throw SignUpFailedException(
|
businessId: createdBusinessId,
|
||||||
technicalMessage: 'Unexpected error: $e',
|
|
||||||
);
|
);
|
||||||
|
throw SignUpFailedException(technicalMessage: 'Unexpected error: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,16 +148,15 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
required String password,
|
required String password,
|
||||||
required String companyName,
|
required String companyName,
|
||||||
}) async {
|
}) async {
|
||||||
developer.log('Email exists in Firebase, attempting sign-in: $email',
|
developer.log(
|
||||||
name: 'AuthRepository');
|
'Email exists in Firebase, attempting sign-in: $email',
|
||||||
|
name: 'AuthRepository',
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try to sign in with the provided password
|
// Try to sign in with the provided password
|
||||||
final firebase.UserCredential credential =
|
final firebase.UserCredential credential = await _service.auth
|
||||||
await _service.auth.signInWithEmailAndPassword(
|
.signInWithEmailAndPassword(email: email, password: password);
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
);
|
|
||||||
|
|
||||||
final firebase.User? firebaseUser = credential.user;
|
final firebase.User? firebaseUser = credential.user;
|
||||||
if (firebaseUser == null) {
|
if (firebaseUser == null) {
|
||||||
@@ -180,32 +166,40 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sign-in succeeded! Check if user already has a BUSINESS account in PostgreSQL
|
// Sign-in succeeded! Check if user already has a BUSINESS account in PostgreSQL
|
||||||
final bool hasBusinessAccount =
|
final bool hasBusinessAccount = await _checkBusinessUserExists(
|
||||||
await _checkBusinessUserExists(firebaseUser.uid);
|
firebaseUser.uid,
|
||||||
|
);
|
||||||
|
|
||||||
if (hasBusinessAccount) {
|
if (hasBusinessAccount) {
|
||||||
// User already has a KROW Client account
|
// User already has a KROW Client account
|
||||||
developer.log('User already has BUSINESS account: ${firebaseUser.uid}',
|
developer.log(
|
||||||
name: 'AuthRepository');
|
'User already has BUSINESS account: ${firebaseUser.uid}',
|
||||||
|
name: 'AuthRepository',
|
||||||
|
);
|
||||||
throw AccountExistsException(
|
throw AccountExistsException(
|
||||||
technicalMessage: 'User ${firebaseUser.uid} already has BUSINESS role',
|
technicalMessage:
|
||||||
|
'User ${firebaseUser.uid} already has BUSINESS role',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// User exists in Firebase but not in KROW PostgreSQL - create the entities
|
// User exists in Firebase but not in KROW PostgreSQL - create the entities
|
||||||
developer.log(
|
developer.log(
|
||||||
'Creating BUSINESS account for existing Firebase user: ${firebaseUser.uid}',
|
'Creating BUSINESS account for existing Firebase user: ${firebaseUser.uid}',
|
||||||
name: 'AuthRepository');
|
name: 'AuthRepository',
|
||||||
|
);
|
||||||
return await _createBusinessAndUser(
|
return await _createBusinessAndUser(
|
||||||
firebaseUser: firebaseUser,
|
firebaseUser: firebaseUser,
|
||||||
companyName: companyName,
|
companyName: companyName,
|
||||||
email: email,
|
email: email,
|
||||||
onBusinessCreated: (_) {}, // No rollback needed for existing Firebase user
|
onBusinessCreated:
|
||||||
|
(_) {}, // No rollback needed for existing Firebase user
|
||||||
);
|
);
|
||||||
} on firebase.FirebaseAuthException catch (e) {
|
} on firebase.FirebaseAuthException catch (e) {
|
||||||
// Sign-in failed - check why
|
// Sign-in failed - check why
|
||||||
developer.log('Sign-in failed with code: ${e.code}',
|
developer.log(
|
||||||
name: 'AuthRepository');
|
'Sign-in failed with code: ${e.code}',
|
||||||
|
name: 'AuthRepository',
|
||||||
|
);
|
||||||
|
|
||||||
if (e.code == 'wrong-password' || e.code == 'invalid-credential') {
|
if (e.code == 'wrong-password' || e.code == 'invalid-credential') {
|
||||||
// Password doesn't match - check what providers are available
|
// Password doesn't match - check what providers are available
|
||||||
@@ -229,8 +223,10 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
// We can't distinguish between "wrong password" and "no password provider"
|
// We can't distinguish between "wrong password" and "no password provider"
|
||||||
// due to Firebase deprecating fetchSignInMethodsForEmail.
|
// due to Firebase deprecating fetchSignInMethodsForEmail.
|
||||||
// The PasswordMismatchException message covers both scenarios.
|
// The PasswordMismatchException message covers both scenarios.
|
||||||
developer.log('Password mismatch or different provider for: $email',
|
developer.log(
|
||||||
name: 'AuthRepository');
|
'Password mismatch or different provider for: $email',
|
||||||
|
name: 'AuthRepository',
|
||||||
|
);
|
||||||
throw PasswordMismatchException(
|
throw PasswordMismatchException(
|
||||||
technicalMessage:
|
technicalMessage:
|
||||||
'Email $email: password mismatch or different auth provider',
|
'Email $email: password mismatch or different auth provider',
|
||||||
@@ -242,7 +238,8 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
Future<bool> _checkBusinessUserExists(String firebaseUserId) async {
|
Future<bool> _checkBusinessUserExists(String firebaseUserId) async {
|
||||||
final QueryResult<dc.GetUserByIdData, dc.GetUserByIdVariables> response =
|
final QueryResult<dc.GetUserByIdData, dc.GetUserByIdVariables> response =
|
||||||
await _service.run(
|
await _service.run(
|
||||||
() => _service.connector.getUserById(id: firebaseUserId).execute());
|
() => _service.connector.getUserById(id: firebaseUserId).execute(),
|
||||||
|
);
|
||||||
final dc.GetUserByIdUser? user = response.data.user;
|
final dc.GetUserByIdUser? user = response.data.user;
|
||||||
return user != null &&
|
return user != null &&
|
||||||
(user.userRole == 'BUSINESS' || user.userRole == 'BOTH');
|
(user.userRole == 'BUSINESS' || user.userRole == 'BOTH');
|
||||||
@@ -258,14 +255,16 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
// Create Business entity in PostgreSQL
|
// Create Business entity in PostgreSQL
|
||||||
|
|
||||||
final OperationResult<dc.CreateBusinessData, dc.CreateBusinessVariables>
|
final OperationResult<dc.CreateBusinessData, dc.CreateBusinessVariables>
|
||||||
createBusinessResponse = await _service.run(() => _service.connector
|
createBusinessResponse = await _service.run(
|
||||||
.createBusiness(
|
() => _service.connector
|
||||||
businessName: companyName,
|
.createBusiness(
|
||||||
userId: firebaseUser.uid,
|
businessName: companyName,
|
||||||
rateGroup: dc.BusinessRateGroup.STANDARD,
|
userId: firebaseUser.uid,
|
||||||
status: dc.BusinessStatus.PENDING,
|
rateGroup: dc.BusinessRateGroup.STANDARD,
|
||||||
)
|
status: dc.BusinessStatus.PENDING,
|
||||||
.execute());
|
)
|
||||||
|
.execute(),
|
||||||
|
);
|
||||||
|
|
||||||
final dc.CreateBusinessBusinessInsert businessData =
|
final dc.CreateBusinessBusinessInsert businessData =
|
||||||
createBusinessResponse.data.business_insert;
|
createBusinessResponse.data.business_insert;
|
||||||
@@ -273,28 +272,28 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
|
|
||||||
// Check if User entity already exists in PostgreSQL
|
// Check if User entity already exists in PostgreSQL
|
||||||
final QueryResult<dc.GetUserByIdData, dc.GetUserByIdVariables> userResult =
|
final QueryResult<dc.GetUserByIdData, dc.GetUserByIdVariables> userResult =
|
||||||
await _service.run(() =>
|
await _service.run(
|
||||||
_service.connector.getUserById(id: firebaseUser.uid).execute());
|
() => _service.connector.getUserById(id: firebaseUser.uid).execute(),
|
||||||
|
);
|
||||||
final dc.GetUserByIdUser? existingUser = userResult.data.user;
|
final dc.GetUserByIdUser? existingUser = userResult.data.user;
|
||||||
|
|
||||||
if (existingUser != null) {
|
if (existingUser != null) {
|
||||||
// User exists (likely in another app like STAFF). Update role to BOTH.
|
// User exists (likely in another app like STAFF). Update role to BOTH.
|
||||||
await _service.run(() => _service.connector
|
await _service.run(
|
||||||
.updateUser(
|
() => _service.connector
|
||||||
id: firebaseUser.uid,
|
.updateUser(id: firebaseUser.uid)
|
||||||
)
|
.userRole('BOTH')
|
||||||
.userRole('BOTH')
|
.execute(),
|
||||||
.execute());
|
);
|
||||||
} else {
|
} else {
|
||||||
// Create new User entity in PostgreSQL
|
// Create new User entity in PostgreSQL
|
||||||
await _service.run(() => _service.connector
|
await _service.run(
|
||||||
.createUser(
|
() => _service.connector
|
||||||
id: firebaseUser.uid,
|
.createUser(id: firebaseUser.uid, role: dc.UserBaseRole.USER)
|
||||||
role: dc.UserBaseRole.USER,
|
.email(email)
|
||||||
)
|
.userRole('BUSINESS')
|
||||||
.email(email)
|
.execute(),
|
||||||
.userRole('BUSINESS')
|
);
|
||||||
.execute());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return _getUserProfile(
|
return _getUserProfile(
|
||||||
@@ -340,7 +339,8 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
@override
|
@override
|
||||||
Future<domain.User> signInWithSocial({required String provider}) {
|
Future<domain.User> signInWithSocial({required String provider}) {
|
||||||
throw UnimplementedError(
|
throw UnimplementedError(
|
||||||
'Social authentication with $provider is not yet implemented.');
|
'Social authentication with $provider is not yet implemented.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<domain.User> _getUserProfile({
|
Future<domain.User> _getUserProfile({
|
||||||
@@ -349,8 +349,9 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
bool requireBusinessRole = false,
|
bool requireBusinessRole = false,
|
||||||
}) async {
|
}) async {
|
||||||
final QueryResult<dc.GetUserByIdData, dc.GetUserByIdVariables> response =
|
final QueryResult<dc.GetUserByIdData, dc.GetUserByIdVariables> response =
|
||||||
await _service.run(() =>
|
await _service.run(
|
||||||
_service.connector.getUserById(id: firebaseUserId).execute());
|
() => _service.connector.getUserById(id: firebaseUserId).execute(),
|
||||||
|
);
|
||||||
final dc.GetUserByIdUser? user = response.data.user;
|
final dc.GetUserByIdUser? user = response.data.user;
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw UserNotFoundException(
|
throw UserNotFoundException(
|
||||||
@@ -383,22 +384,22 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
role: user.role.stringValue,
|
role: user.role.stringValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
final QueryResult<dc.GetBusinessesByUserIdData,
|
final QueryResult<
|
||||||
dc.GetBusinessesByUserIdVariables> businessResponse =
|
dc.GetBusinessesByUserIdData,
|
||||||
await _service.run(() => _service.connector
|
dc.GetBusinessesByUserIdVariables
|
||||||
.getBusinessesByUserId(
|
>
|
||||||
userId: firebaseUserId,
|
businessResponse = await _service.run(
|
||||||
)
|
() => _service.connector
|
||||||
.execute());
|
.getBusinessesByUserId(userId: firebaseUserId)
|
||||||
|
.execute(),
|
||||||
|
);
|
||||||
final dc.GetBusinessesByUserIdBusinesses? business =
|
final dc.GetBusinessesByUserIdBusinesses? business =
|
||||||
businessResponse.data.businesses.isNotEmpty
|
businessResponse.data.businesses.isNotEmpty
|
||||||
? businessResponse.data.businesses.first
|
? businessResponse.data.businesses.first
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
dc.ClientSessionStore.instance.setSession(
|
dc.ClientSessionStore.instance.setSession(
|
||||||
dc.ClientSession(
|
dc.ClientSession(
|
||||||
user: domainUser,
|
|
||||||
userPhotoUrl: user.photoUrl,
|
|
||||||
business: business == null
|
business: business == null
|
||||||
? null
|
? null
|
||||||
: dc.ClientBusinessSession(
|
: dc.ClientBusinessSession(
|
||||||
|
|||||||
@@ -19,26 +19,43 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
|
|||||||
|
|
||||||
final DateTime now = DateTime.now();
|
final DateTime now = DateTime.now();
|
||||||
final int daysFromMonday = now.weekday - DateTime.monday;
|
final int daysFromMonday = now.weekday - DateTime.monday;
|
||||||
final DateTime monday =
|
final DateTime monday = DateTime(
|
||||||
DateTime(now.year, now.month, now.day).subtract(Duration(days: daysFromMonday));
|
now.year,
|
||||||
final DateTime weekRangeStart = DateTime(monday.year, monday.month, monday.day);
|
now.month,
|
||||||
final DateTime weekRangeEnd =
|
now.day,
|
||||||
DateTime(monday.year, monday.month, monday.day + 13, 23, 59, 59, 999);
|
).subtract(Duration(days: daysFromMonday));
|
||||||
final fdc.QueryResult<dc.GetCompletedShiftsByBusinessIdData,
|
final DateTime weekRangeStart = DateTime(
|
||||||
dc.GetCompletedShiftsByBusinessIdVariables> completedResult =
|
monday.year,
|
||||||
await _service.connector
|
monday.month,
|
||||||
.getCompletedShiftsByBusinessId(
|
monday.day,
|
||||||
businessId: businessId,
|
);
|
||||||
dateFrom: _service.toTimestamp(weekRangeStart),
|
final DateTime weekRangeEnd = DateTime(
|
||||||
dateTo: _service.toTimestamp(weekRangeEnd),
|
monday.year,
|
||||||
)
|
monday.month,
|
||||||
.execute();
|
monday.day + 13,
|
||||||
|
23,
|
||||||
|
59,
|
||||||
|
59,
|
||||||
|
999,
|
||||||
|
);
|
||||||
|
final fdc.QueryResult<
|
||||||
|
dc.GetCompletedShiftsByBusinessIdData,
|
||||||
|
dc.GetCompletedShiftsByBusinessIdVariables
|
||||||
|
>
|
||||||
|
completedResult = await _service.connector
|
||||||
|
.getCompletedShiftsByBusinessId(
|
||||||
|
businessId: businessId,
|
||||||
|
dateFrom: _service.toTimestamp(weekRangeStart),
|
||||||
|
dateTo: _service.toTimestamp(weekRangeEnd),
|
||||||
|
)
|
||||||
|
.execute();
|
||||||
|
|
||||||
double weeklySpending = 0.0;
|
double weeklySpending = 0.0;
|
||||||
double next7DaysSpending = 0.0;
|
double next7DaysSpending = 0.0;
|
||||||
int weeklyShifts = 0;
|
int weeklyShifts = 0;
|
||||||
int next7DaysScheduled = 0;
|
int next7DaysScheduled = 0;
|
||||||
for (final dc.GetCompletedShiftsByBusinessIdShifts shift in completedResult.data.shifts) {
|
for (final dc.GetCompletedShiftsByBusinessIdShifts shift
|
||||||
|
in completedResult.data.shifts) {
|
||||||
final DateTime? shiftDate = shift.date?.toDateTime();
|
final DateTime? shiftDate = shift.date?.toDateTime();
|
||||||
if (shiftDate == null) {
|
if (shiftDate == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -58,17 +75,27 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final DateTime start = DateTime(now.year, now.month, now.day);
|
final DateTime start = DateTime(now.year, now.month, now.day);
|
||||||
final DateTime end = DateTime(now.year, now.month, now.day, 23, 59, 59, 999);
|
final DateTime end = DateTime(
|
||||||
|
now.year,
|
||||||
|
now.month,
|
||||||
|
now.day,
|
||||||
|
23,
|
||||||
|
59,
|
||||||
|
59,
|
||||||
|
999,
|
||||||
|
);
|
||||||
|
|
||||||
final fdc.QueryResult<dc.ListShiftRolesByBusinessAndDateRangeData,
|
final fdc.QueryResult<
|
||||||
dc.ListShiftRolesByBusinessAndDateRangeVariables> result =
|
dc.ListShiftRolesByBusinessAndDateRangeData,
|
||||||
await _service.connector
|
dc.ListShiftRolesByBusinessAndDateRangeVariables
|
||||||
.listShiftRolesByBusinessAndDateRange(
|
>
|
||||||
businessId: businessId,
|
result = await _service.connector
|
||||||
start: _service.toTimestamp(start),
|
.listShiftRolesByBusinessAndDateRange(
|
||||||
end: _service.toTimestamp(end),
|
businessId: businessId,
|
||||||
)
|
start: _service.toTimestamp(start),
|
||||||
.execute();
|
end: _service.toTimestamp(end),
|
||||||
|
)
|
||||||
|
.execute();
|
||||||
|
|
||||||
int totalNeeded = 0;
|
int totalNeeded = 0;
|
||||||
int totalFilled = 0;
|
int totalFilled = 0;
|
||||||
@@ -90,12 +117,47 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
UserSessionData getUserSessionData() {
|
Future<UserSessionData> getUserSessionData() async {
|
||||||
final dc.ClientSession? session = dc.ClientSessionStore.instance.session;
|
final dc.ClientSession? session = dc.ClientSessionStore.instance.session;
|
||||||
return UserSessionData(
|
final dc.ClientBusinessSession? business = session?.business;
|
||||||
businessName: session?.business?.businessName ?? '',
|
|
||||||
photoUrl: null, // Business photo isn't currently in session
|
// If session data is available, return it immediately
|
||||||
);
|
if (business != null) {
|
||||||
|
return UserSessionData(
|
||||||
|
businessName: business.businessName,
|
||||||
|
photoUrl: business.companyLogoUrl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await _service.run(() async {
|
||||||
|
// If session is not initialized, attempt to fetch business data to populate session
|
||||||
|
final String businessId = await _service.getBusinessId();
|
||||||
|
final fdc.QueryResult<dc.GetBusinessByIdData, dc.GetBusinessByIdVariables>
|
||||||
|
businessResult = await _service.connector
|
||||||
|
.getBusinessById(id: businessId)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
if (businessResult.data.business == null) {
|
||||||
|
throw Exception('Business data not found for ID: $businessId');
|
||||||
|
}
|
||||||
|
|
||||||
|
final dc.ClientSession updatedSession = dc.ClientSession(
|
||||||
|
business: dc.ClientBusinessSession(
|
||||||
|
id: businessResult.data.business!.id,
|
||||||
|
businessName: businessResult.data.business?.businessName ?? '',
|
||||||
|
email: businessResult.data.business?.email ?? '',
|
||||||
|
city: businessResult.data.business?.city ?? '',
|
||||||
|
contactName: businessResult.data.business?.contactName ?? '',
|
||||||
|
companyLogoUrl: businessResult.data.business?.companyLogoUrl,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
dc.ClientSessionStore.instance.setSession(updatedSession);
|
||||||
|
|
||||||
|
return UserSessionData(
|
||||||
|
businessName: businessResult.data.business!.businessName,
|
||||||
|
photoUrl: businessResult.data.business!.companyLogoUrl,
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -108,33 +170,34 @@ class HomeRepositoryImpl implements HomeRepositoryInterface {
|
|||||||
final fdc.Timestamp startTimestamp = _service.toTimestamp(start);
|
final fdc.Timestamp startTimestamp = _service.toTimestamp(start);
|
||||||
final fdc.Timestamp endTimestamp = _service.toTimestamp(now);
|
final fdc.Timestamp endTimestamp = _service.toTimestamp(now);
|
||||||
|
|
||||||
final fdc.QueryResult<dc.ListShiftRolesByBusinessDateRangeCompletedOrdersData,
|
final fdc.QueryResult<
|
||||||
dc.ListShiftRolesByBusinessDateRangeCompletedOrdersVariables> result =
|
dc.ListShiftRolesByBusinessDateRangeCompletedOrdersData,
|
||||||
await _service.connector
|
dc.ListShiftRolesByBusinessDateRangeCompletedOrdersVariables
|
||||||
.listShiftRolesByBusinessDateRangeCompletedOrders(
|
>
|
||||||
businessId: businessId,
|
result = await _service.connector
|
||||||
start: startTimestamp,
|
.listShiftRolesByBusinessDateRangeCompletedOrders(
|
||||||
end: endTimestamp,
|
businessId: businessId,
|
||||||
)
|
start: startTimestamp,
|
||||||
.execute();
|
end: endTimestamp,
|
||||||
|
)
|
||||||
|
.execute();
|
||||||
|
|
||||||
return result.data.shiftRoles
|
return result.data.shiftRoles.map((
|
||||||
.map((
|
dc.ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles shiftRole,
|
||||||
dc.ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles shiftRole,
|
) {
|
||||||
) {
|
final String location =
|
||||||
final String location = shiftRole.shift.location ?? shiftRole.shift.locationAddress ?? '';
|
shiftRole.shift.location ?? shiftRole.shift.locationAddress ?? '';
|
||||||
final String type = shiftRole.shift.order.orderType.stringValue;
|
final String type = shiftRole.shift.order.orderType.stringValue;
|
||||||
return ReorderItem(
|
return ReorderItem(
|
||||||
orderId: shiftRole.shift.order.id,
|
orderId: shiftRole.shift.order.id,
|
||||||
title: '${shiftRole.role.name} - ${shiftRole.shift.title}',
|
title: '${shiftRole.role.name} - ${shiftRole.shift.title}',
|
||||||
location: location,
|
location: location,
|
||||||
hourlyRate: shiftRole.role.costPerHour,
|
hourlyRate: shiftRole.role.costPerHour,
|
||||||
hours: shiftRole.hours ?? 0,
|
hours: shiftRole.hours ?? 0,
|
||||||
workers: shiftRole.count,
|
workers: shiftRole.count,
|
||||||
type: type,
|
type: type,
|
||||||
);
|
);
|
||||||
})
|
}).toList();
|
||||||
.toList();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ abstract interface class HomeRepositoryInterface {
|
|||||||
Future<HomeDashboardData> getDashboardData();
|
Future<HomeDashboardData> getDashboardData();
|
||||||
|
|
||||||
/// Fetches the user's session data (business name and photo).
|
/// Fetches the user's session data (business name and photo).
|
||||||
UserSessionData getUserSessionData();
|
Future<UserSessionData> getUserSessionData();
|
||||||
|
|
||||||
/// Fetches recently completed shift roles for reorder suggestions.
|
/// Fetches recently completed shift roles for reorder suggestions.
|
||||||
Future<List<ReorderItem>> getRecentReorders();
|
Future<List<ReorderItem>> getRecentReorders();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class GetUserSessionDataUseCase {
|
|||||||
final HomeRepositoryInterface _repository;
|
final HomeRepositoryInterface _repository;
|
||||||
|
|
||||||
/// Executes the use case to get session data.
|
/// Executes the use case to get session data.
|
||||||
UserSessionData call() {
|
Future<UserSessionData> call() {
|
||||||
return _repository.getUserSessionData();
|
return _repository.getUserSessionData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class ClientHomeBloc extends Bloc<ClientHomeEvent, ClientHomeState>
|
|||||||
emit: emit,
|
emit: emit,
|
||||||
action: () async {
|
action: () async {
|
||||||
// Get session data
|
// Get session data
|
||||||
final UserSessionData sessionData = _getUserSessionDataUseCase();
|
final UserSessionData sessionData = await _getUserSessionDataUseCase();
|
||||||
|
|
||||||
// Get dashboard data
|
// Get dashboard data
|
||||||
final HomeDashboardData data = await _getDashboardDataUseCase();
|
final HomeDashboardData data = await _getDashboardDataUseCase();
|
||||||
|
|||||||
@@ -16,16 +16,16 @@ import '../../domain/repositories/hub_repository_interface.dart';
|
|||||||
|
|
||||||
/// Implementation of [HubRepositoryInterface] backed by Data Connect.
|
/// Implementation of [HubRepositoryInterface] backed by Data Connect.
|
||||||
class HubRepositoryImpl implements HubRepositoryInterface {
|
class HubRepositoryImpl implements HubRepositoryInterface {
|
||||||
HubRepositoryImpl({
|
HubRepositoryImpl({required dc.DataConnectService service})
|
||||||
required dc.DataConnectService service,
|
: _service = service;
|
||||||
}) : _service = service;
|
|
||||||
|
|
||||||
final dc.DataConnectService _service;
|
final dc.DataConnectService _service;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<domain.Hub>> getHubs() async {
|
Future<List<domain.Hub>> getHubs() async {
|
||||||
return _service.run(() async {
|
return _service.run(() async {
|
||||||
final dc.GetBusinessesByUserIdBusinesses business = await _getBusinessForCurrentUser();
|
final dc.GetBusinessesByUserIdBusinesses business =
|
||||||
|
await _getBusinessForCurrentUser();
|
||||||
final String teamId = await _getOrCreateTeamId(business);
|
final String teamId = await _getOrCreateTeamId(business);
|
||||||
return _fetchHubsForTeam(teamId: teamId, businessId: business.id);
|
return _fetchHubsForTeam(teamId: teamId, businessId: business.id);
|
||||||
});
|
});
|
||||||
@@ -45,10 +45,12 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
String? zipCode,
|
String? zipCode,
|
||||||
}) async {
|
}) async {
|
||||||
return _service.run(() async {
|
return _service.run(() async {
|
||||||
final dc.GetBusinessesByUserIdBusinesses business = await _getBusinessForCurrentUser();
|
final dc.GetBusinessesByUserIdBusinesses business =
|
||||||
|
await _getBusinessForCurrentUser();
|
||||||
final String teamId = await _getOrCreateTeamId(business);
|
final String teamId = await _getOrCreateTeamId(business);
|
||||||
final _PlaceAddress? placeAddress =
|
final _PlaceAddress? placeAddress = placeId == null || placeId.isEmpty
|
||||||
placeId == null || placeId.isEmpty ? null : await _fetchPlaceAddress(placeId);
|
? null
|
||||||
|
: await _fetchPlaceAddress(placeId);
|
||||||
final String? cityValue = city ?? placeAddress?.city ?? business.city;
|
final String? cityValue = city ?? placeAddress?.city ?? business.city;
|
||||||
final String? stateValue = state ?? placeAddress?.state;
|
final String? stateValue = state ?? placeAddress?.state;
|
||||||
final String? streetValue = street ?? placeAddress?.street;
|
final String? streetValue = street ?? placeAddress?.street;
|
||||||
@@ -56,21 +58,17 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
final String? zipCodeValue = zipCode ?? placeAddress?.zipCode;
|
final String? zipCodeValue = zipCode ?? placeAddress?.zipCode;
|
||||||
|
|
||||||
final OperationResult<dc.CreateTeamHubData, dc.CreateTeamHubVariables>
|
final OperationResult<dc.CreateTeamHubData, dc.CreateTeamHubVariables>
|
||||||
result = await _service.connector
|
result = await _service.connector
|
||||||
.createTeamHub(
|
.createTeamHub(teamId: teamId, hubName: name, address: address)
|
||||||
teamId: teamId,
|
.placeId(placeId)
|
||||||
hubName: name,
|
.latitude(latitude)
|
||||||
address: address,
|
.longitude(longitude)
|
||||||
)
|
.city(cityValue?.isNotEmpty == true ? cityValue : '')
|
||||||
.placeId(placeId)
|
.state(stateValue)
|
||||||
.latitude(latitude)
|
.street(streetValue)
|
||||||
.longitude(longitude)
|
.country(countryValue)
|
||||||
.city(cityValue?.isNotEmpty == true ? cityValue : '')
|
.zipCode(zipCodeValue)
|
||||||
.state(stateValue)
|
.execute();
|
||||||
.street(streetValue)
|
|
||||||
.country(countryValue)
|
|
||||||
.zipCode(zipCodeValue)
|
|
||||||
.execute();
|
|
||||||
final String createdId = result.data.teamHub_insert.id;
|
final String createdId = result.data.teamHub_insert.id;
|
||||||
|
|
||||||
final List<domain.Hub> hubs = await _fetchHubsForTeam(
|
final List<domain.Hub> hubs = await _fetchHubsForTeam(
|
||||||
@@ -101,14 +99,13 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
return _service.run(() async {
|
return _service.run(() async {
|
||||||
final String businessId = await _service.getBusinessId();
|
final String businessId = await _service.getBusinessId();
|
||||||
|
|
||||||
final QueryResult<dc.ListOrdersByBusinessAndTeamHubData,
|
final QueryResult<
|
||||||
dc.ListOrdersByBusinessAndTeamHubVariables> result =
|
dc.ListOrdersByBusinessAndTeamHubData,
|
||||||
await _service.connector
|
dc.ListOrdersByBusinessAndTeamHubVariables
|
||||||
.listOrdersByBusinessAndTeamHub(
|
>
|
||||||
businessId: businessId,
|
result = await _service.connector
|
||||||
teamHubId: id,
|
.listOrdersByBusinessAndTeamHub(businessId: businessId, teamHubId: id)
|
||||||
)
|
.execute();
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (result.data.orders.isNotEmpty) {
|
if (result.data.orders.isNotEmpty) {
|
||||||
throw HubHasOrdersException(
|
throw HubHasOrdersException(
|
||||||
@@ -121,14 +118,14 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> assignNfcTag({
|
Future<void> assignNfcTag({required String hubId, required String nfcTagId}) {
|
||||||
required String hubId,
|
throw UnimplementedError(
|
||||||
required String nfcTagId,
|
'NFC tag assignment is not supported for team hubs.',
|
||||||
}) {
|
);
|
||||||
throw UnimplementedError('NFC tag assignment is not supported for team hubs.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dc.GetBusinessesByUserIdBusinesses> _getBusinessForCurrentUser() async {
|
Future<dc.GetBusinessesByUserIdBusinesses>
|
||||||
|
_getBusinessForCurrentUser() async {
|
||||||
final dc.ClientSession? session = dc.ClientSessionStore.instance.session;
|
final dc.ClientSession? session = dc.ClientSessionStore.instance.session;
|
||||||
final dc.ClientBusinessSession? cachedBusiness = session?.business;
|
final dc.ClientBusinessSession? cachedBusiness = session?.business;
|
||||||
if (cachedBusiness != null) {
|
if (cachedBusiness != null) {
|
||||||
@@ -136,7 +133,9 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
id: cachedBusiness.id,
|
id: cachedBusiness.id,
|
||||||
businessName: cachedBusiness.businessName,
|
businessName: cachedBusiness.businessName,
|
||||||
userId: _service.auth.currentUser?.uid ?? '',
|
userId: _service.auth.currentUser?.uid ?? '',
|
||||||
rateGroup: const dc.Known<dc.BusinessRateGroup>(dc.BusinessRateGroup.STANDARD),
|
rateGroup: const dc.Known<dc.BusinessRateGroup>(
|
||||||
|
dc.BusinessRateGroup.STANDARD,
|
||||||
|
),
|
||||||
status: const dc.Known<dc.BusinessStatus>(dc.BusinessStatus.ACTIVE),
|
status: const dc.Known<dc.BusinessStatus>(dc.BusinessStatus.ACTIVE),
|
||||||
contactName: cachedBusiness.contactName,
|
contactName: cachedBusiness.contactName,
|
||||||
companyLogoUrl: cachedBusiness.companyLogoUrl,
|
companyLogoUrl: cachedBusiness.companyLogoUrl,
|
||||||
@@ -160,11 +159,13 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final QueryResult<dc.GetBusinessesByUserIdData,
|
final QueryResult<
|
||||||
dc.GetBusinessesByUserIdVariables> result =
|
dc.GetBusinessesByUserIdData,
|
||||||
await _service.connector.getBusinessesByUserId(
|
dc.GetBusinessesByUserIdVariables
|
||||||
userId: user.uid,
|
>
|
||||||
).execute();
|
result = await _service.connector
|
||||||
|
.getBusinessesByUserId(userId: user.uid)
|
||||||
|
.execute();
|
||||||
if (result.data.businesses.isEmpty) {
|
if (result.data.businesses.isEmpty) {
|
||||||
await _service.auth.signOut();
|
await _service.auth.signOut();
|
||||||
throw BusinessNotFoundException(
|
throw BusinessNotFoundException(
|
||||||
@@ -172,12 +173,11 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final dc.GetBusinessesByUserIdBusinesses business = result.data.businesses.first;
|
final dc.GetBusinessesByUserIdBusinesses business =
|
||||||
|
result.data.businesses.first;
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
dc.ClientSessionStore.instance.setSession(
|
dc.ClientSessionStore.instance.setSession(
|
||||||
dc.ClientSession(
|
dc.ClientSession(
|
||||||
user: session.user,
|
|
||||||
userPhotoUrl: session.userPhotoUrl,
|
|
||||||
business: dc.ClientBusinessSession(
|
business: dc.ClientBusinessSession(
|
||||||
id: business.id,
|
id: business.id,
|
||||||
businessName: business.businessName,
|
businessName: business.businessName,
|
||||||
@@ -197,26 +197,26 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
dc.GetBusinessesByUserIdBusinesses business,
|
dc.GetBusinessesByUserIdBusinesses business,
|
||||||
) async {
|
) async {
|
||||||
final QueryResult<dc.GetTeamsByOwnerIdData, dc.GetTeamsByOwnerIdVariables>
|
final QueryResult<dc.GetTeamsByOwnerIdData, dc.GetTeamsByOwnerIdVariables>
|
||||||
teamsResult = await _service.connector.getTeamsByOwnerId(
|
teamsResult = await _service.connector
|
||||||
ownerId: business.id,
|
.getTeamsByOwnerId(ownerId: business.id)
|
||||||
).execute();
|
.execute();
|
||||||
if (teamsResult.data.teams.isNotEmpty) {
|
if (teamsResult.data.teams.isNotEmpty) {
|
||||||
return teamsResult.data.teams.first.id;
|
return teamsResult.data.teams.first.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
final dc.CreateTeamVariablesBuilder createTeamBuilder = _service.connector.createTeam(
|
final dc.CreateTeamVariablesBuilder createTeamBuilder = _service.connector
|
||||||
teamName: '${business.businessName} Team',
|
.createTeam(
|
||||||
ownerId: business.id,
|
teamName: '${business.businessName} Team',
|
||||||
ownerName: business.contactName ?? '',
|
ownerId: business.id,
|
||||||
ownerRole: 'OWNER',
|
ownerName: business.contactName ?? '',
|
||||||
);
|
ownerRole: 'OWNER',
|
||||||
|
);
|
||||||
if (business.email != null) {
|
if (business.email != null) {
|
||||||
createTeamBuilder.email(business.email);
|
createTeamBuilder.email(business.email);
|
||||||
}
|
}
|
||||||
|
|
||||||
final OperationResult<dc.CreateTeamData, dc.CreateTeamVariables>
|
final OperationResult<dc.CreateTeamData, dc.CreateTeamVariables>
|
||||||
createTeamResult =
|
createTeamResult = await createTeamBuilder.execute();
|
||||||
await createTeamBuilder.execute();
|
|
||||||
final String teamId = createTeamResult.data.team_insert.id;
|
final String teamId = createTeamResult.data.team_insert.id;
|
||||||
|
|
||||||
return teamId;
|
return teamId;
|
||||||
@@ -226,11 +226,13 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
required String teamId,
|
required String teamId,
|
||||||
required String businessId,
|
required String businessId,
|
||||||
}) async {
|
}) async {
|
||||||
final QueryResult<dc.GetTeamHubsByTeamIdData,
|
final QueryResult<
|
||||||
dc.GetTeamHubsByTeamIdVariables> hubsResult =
|
dc.GetTeamHubsByTeamIdData,
|
||||||
await _service.connector.getTeamHubsByTeamId(
|
dc.GetTeamHubsByTeamIdVariables
|
||||||
teamId: teamId,
|
>
|
||||||
).execute();
|
hubsResult = await _service.connector
|
||||||
|
.getTeamHubsByTeamId(teamId: teamId)
|
||||||
|
.execute();
|
||||||
|
|
||||||
return hubsResult.data.teamHubs
|
return hubsResult.data.teamHubs
|
||||||
.map(
|
.map(
|
||||||
@@ -240,10 +242,9 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
name: hub.hubName,
|
name: hub.hubName,
|
||||||
address: hub.address,
|
address: hub.address,
|
||||||
nfcTagId: null,
|
nfcTagId: null,
|
||||||
status:
|
status: hub.isActive
|
||||||
hub.isActive
|
? domain.HubStatus.active
|
||||||
? domain.HubStatus.active
|
: domain.HubStatus.inactive,
|
||||||
: domain.HubStatus.inactive,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
@@ -288,7 +289,8 @@ class HubRepositoryImpl implements HubRepositoryInterface {
|
|||||||
|
|
||||||
for (final dynamic entry in components) {
|
for (final dynamic entry in components) {
|
||||||
final Map<String, dynamic> component = entry as Map<String, dynamic>;
|
final Map<String, dynamic> component = entry as Map<String, dynamic>;
|
||||||
final List<dynamic> types = component['types'] as List<dynamic>? ?? <dynamic>[];
|
final List<dynamic> types =
|
||||||
|
component['types'] as List<dynamic>? ?? <dynamic>[];
|
||||||
final String? longName = component['long_name'] as String?;
|
final String? longName = component['long_name'] as String?;
|
||||||
final String? shortName = component['short_name'] as String?;
|
final String? shortName = component['short_name'] as String?;
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ class SettingsProfileHeader extends StatelessWidget {
|
|||||||
final dc.ClientSession? session = dc.ClientSessionStore.instance.session;
|
final dc.ClientSession? session = dc.ClientSessionStore.instance.session;
|
||||||
final String businessName =
|
final String businessName =
|
||||||
session?.business?.businessName ?? 'Your Company';
|
session?.business?.businessName ?? 'Your Company';
|
||||||
final String email = session?.user.email ?? 'client@example.com';
|
final String email = session?.business?.email ?? 'client@example.com';
|
||||||
final String? photoUrl = session?.userPhotoUrl;
|
final String? photoUrl = session?.business?.companyLogoUrl;
|
||||||
final String avatarLetter = businessName.trim().isNotEmpty
|
final String avatarLetter = businessName.trim().isNotEmpty
|
||||||
? businessName.trim()[0].toUpperCase()
|
? businessName.trim()[0].toUpperCase()
|
||||||
: 'C';
|
: 'C';
|
||||||
|
|||||||
Reference in New Issue
Block a user