add auth register
This commit is contained in:
58
docs/auth.sh
Normal file
58
docs/auth.sh
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
GET SESSION
|
||||||
|
curl --location --request POST 'https://land.dbiz.com//api/method/dbiz_common.dbiz_common.api.auth.get_session' \
|
||||||
|
--data ''
|
||||||
|
|
||||||
|
DATA RETURN
|
||||||
|
{
|
||||||
|
"message": {
|
||||||
|
"data": {
|
||||||
|
"sid": "edb6059ecf147f268176cd4aff8ca034a75ebb8ff23464f9913c9537",
|
||||||
|
"csrf_token": "d0077178c349f69bc1456401d9a3d90ef0f7b9df3e08cfd26794a53f"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"home_page": "/app",
|
||||||
|
"full_name": "PublicAPI"
|
||||||
|
}
|
||||||
|
|
||||||
|
GET CITY
|
||||||
|
curl --location 'https://land.dbiz.com//api/method/frappe.client.get_list' \
|
||||||
|
--header 'X-Frappe-Csrf-Token: 3d072ea39d245c2340ecc42d0825f6cbb7e674943c9c74346c8e4629' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Cookie: full_name=PublicAPI; sid=b5a564f45d2fbe8b47dab89382801bf9a6e5c618500feb84a738f205; system_user=no; user_id=public_api%40dbiz.com; user_image=' \
|
||||||
|
--data '{
|
||||||
|
"doctype": "City",
|
||||||
|
"fields": ["city_name","name","code"],
|
||||||
|
"limit_page_length": 0
|
||||||
|
}'
|
||||||
|
|
||||||
|
GET ROLE
|
||||||
|
curl --location 'https://land.dbiz.com//api/method/frappe.client.get_list' \
|
||||||
|
--header 'X-Frappe-Csrf-Token: 3d072ea39d245c2340ecc42d0825f6cbb7e674943c9c74346c8e4629' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Cookie: full_name=PublicAPI; sid=b5a564f45d2fbe8b47dab89382801bf9a6e5c618500feb84a738f205; system_user=no; user_id=public_api%40dbiz.com; user_image=' \
|
||||||
|
--data '{
|
||||||
|
"doctype": "Customer Group",
|
||||||
|
"fields": ["customer_group_name","name","value"],
|
||||||
|
"filters": {"is_group": 0, "is_active" : 1, "customer" : 1},
|
||||||
|
"limit_page_length": 0
|
||||||
|
}'
|
||||||
|
|
||||||
|
REGISTER
|
||||||
|
curl --location 'https://land.dbiz.com//api/method/building_material.building_material.api.user.register' \
|
||||||
|
--header 'X-Frappe-Csrf-Token: 3d072ea39d245c2340ecc42d0825f6cbb7e674943c9c74346c8e4629' \
|
||||||
|
--header 'Cookie: sid=b5a564f45d2fbe8b47dab89382801bf9a6e5c618500feb84a738f205; full_name=PublicAPI; sid=b5a564f45d2fbe8b47dab89382801bf9a6e5c618500feb84a738f205; system_user=no; user_id=public_api%40dbiz.com; user_image=' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"full_name" : "Nguyễn Lê Duy Tiến",
|
||||||
|
"phone" : "091321236",
|
||||||
|
"email" : "tiennld6@dbiz.com",
|
||||||
|
"customer_group_code" : "ACT",
|
||||||
|
"company_name" : null,
|
||||||
|
"city_code" : "01",
|
||||||
|
"tax_code" : "091231",
|
||||||
|
"id_card_front_base64" : "base64 tr",
|
||||||
|
"id_card_back_base64" : "base64 str",
|
||||||
|
"certificates_base64" : [
|
||||||
|
"bas64_1 str","base64_2 str"
|
||||||
|
]
|
||||||
|
}'
|
||||||
245
lib/features/auth/data/datasources/auth_remote_datasource.dart
Normal file
245
lib/features/auth/data/datasources/auth_remote_datasource.dart
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
/// Authentication Remote Data Source
|
||||||
|
///
|
||||||
|
/// Handles all authentication-related API calls.
|
||||||
|
library;
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:worker/core/errors/exceptions.dart';
|
||||||
|
import 'package:worker/features/auth/data/models/auth_session_model.dart';
|
||||||
|
import 'package:worker/features/auth/domain/entities/city.dart';
|
||||||
|
import 'package:worker/features/auth/domain/entities/customer_group.dart';
|
||||||
|
|
||||||
|
/// Authentication Remote Data Source
|
||||||
|
///
|
||||||
|
/// Provides methods for:
|
||||||
|
/// - Getting session (CSRF token and SID)
|
||||||
|
/// - Fetching cities for registration
|
||||||
|
/// - Fetching customer groups (roles) for registration
|
||||||
|
/// - User registration
|
||||||
|
class AuthRemoteDataSource {
|
||||||
|
final Dio _dio;
|
||||||
|
|
||||||
|
AuthRemoteDataSource(this._dio);
|
||||||
|
|
||||||
|
/// Get Session
|
||||||
|
///
|
||||||
|
/// Fetches session data including SID and CSRF token.
|
||||||
|
/// This should be called before making authenticated requests.
|
||||||
|
///
|
||||||
|
/// API: POST /api/method/dbiz_common.dbiz_common.api.auth.get_session
|
||||||
|
Future<GetSessionResponse> getSession() async {
|
||||||
|
try {
|
||||||
|
final response = await _dio.post<Map<String, dynamic>>(
|
||||||
|
'/api/method/dbiz_common.dbiz_common.api.auth.get_session',
|
||||||
|
data: '',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200 && response.data != null) {
|
||||||
|
return GetSessionResponse.fromJson(response.data!);
|
||||||
|
} else {
|
||||||
|
throw ServerException(
|
||||||
|
'Failed to get session: ${response.statusCode}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
if (e.response?.statusCode == 401) {
|
||||||
|
throw const UnauthorizedException();
|
||||||
|
} else if (e.response?.statusCode == 404) {
|
||||||
|
throw NotFoundException('Session endpoint not found');
|
||||||
|
} else {
|
||||||
|
throw NetworkException(
|
||||||
|
e.message ?? 'Failed to get session',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw ServerException('Unexpected error: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Cities
|
||||||
|
///
|
||||||
|
/// Fetches list of cities/provinces for address selection.
|
||||||
|
/// Requires authenticated session (CSRF token and Cookie).
|
||||||
|
///
|
||||||
|
/// API: POST /api/method/frappe.client.get_list
|
||||||
|
/// DocType: City
|
||||||
|
Future<List<City>> getCities({
|
||||||
|
required String csrfToken,
|
||||||
|
required String sid,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final response = await _dio.post<Map<String, dynamic>>(
|
||||||
|
'/api/method/frappe.client.get_list',
|
||||||
|
data: {
|
||||||
|
'doctype': 'City',
|
||||||
|
'fields': ['city_name', 'name', 'code'],
|
||||||
|
'limit_page_length': 0,
|
||||||
|
},
|
||||||
|
options: Options(
|
||||||
|
headers: {
|
||||||
|
'X-Frappe-Csrf-Token': csrfToken,
|
||||||
|
'Cookie': 'sid=$sid',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200 && response.data != null) {
|
||||||
|
final message = response.data!['message'];
|
||||||
|
if (message is List) {
|
||||||
|
return message
|
||||||
|
.map((json) => City.fromJson(json as Map<String, dynamic>))
|
||||||
|
.toList();
|
||||||
|
} else {
|
||||||
|
throw ServerException('Invalid response format for cities');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw ServerException(
|
||||||
|
'Failed to get cities: ${response.statusCode}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
if (e.response?.statusCode == 401) {
|
||||||
|
throw const UnauthorizedException();
|
||||||
|
} else if (e.response?.statusCode == 404) {
|
||||||
|
throw NotFoundException('Cities endpoint not found');
|
||||||
|
} else {
|
||||||
|
throw NetworkException(
|
||||||
|
e.message ?? 'Failed to get cities',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw ServerException('Unexpected error: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Customer Groups (Roles)
|
||||||
|
///
|
||||||
|
/// Fetches list of customer groups for user role selection.
|
||||||
|
/// Requires authenticated session (CSRF token and Cookie).
|
||||||
|
///
|
||||||
|
/// API: POST /api/method/frappe.client.get_list
|
||||||
|
/// DocType: Customer Group
|
||||||
|
Future<List<CustomerGroup>> getCustomerGroups({
|
||||||
|
required String csrfToken,
|
||||||
|
required String sid,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final response = await _dio.post<Map<String, dynamic>>(
|
||||||
|
'/api/method/frappe.client.get_list',
|
||||||
|
data: {
|
||||||
|
'doctype': 'Customer Group',
|
||||||
|
'fields': ['customer_group_name', 'name', 'value'],
|
||||||
|
'filters': {
|
||||||
|
'is_group': 0,
|
||||||
|
'is_active': 1,
|
||||||
|
'customer': 1,
|
||||||
|
},
|
||||||
|
'limit_page_length': 0,
|
||||||
|
},
|
||||||
|
options: Options(
|
||||||
|
headers: {
|
||||||
|
'X-Frappe-Csrf-Token': csrfToken,
|
||||||
|
'Cookie': 'sid=$sid',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200 && response.data != null) {
|
||||||
|
final message = response.data!['message'];
|
||||||
|
if (message is List) {
|
||||||
|
return message
|
||||||
|
.map((json) =>
|
||||||
|
CustomerGroup.fromJson(json as Map<String, dynamic>))
|
||||||
|
.toList();
|
||||||
|
} else {
|
||||||
|
throw ServerException('Invalid response format for customer groups');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw ServerException(
|
||||||
|
'Failed to get customer groups: ${response.statusCode}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
if (e.response?.statusCode == 401) {
|
||||||
|
throw const UnauthorizedException();
|
||||||
|
} else if (e.response?.statusCode == 404) {
|
||||||
|
throw NotFoundException('Customer groups endpoint not found');
|
||||||
|
} else {
|
||||||
|
throw NetworkException(
|
||||||
|
e.message ?? 'Failed to get customer groups',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw ServerException('Unexpected error: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register User
|
||||||
|
///
|
||||||
|
/// Registers a new user with the provided information.
|
||||||
|
/// Requires authenticated session (CSRF token and Cookie).
|
||||||
|
///
|
||||||
|
/// API: POST /api/method/building_material.building_material.api.user.register
|
||||||
|
Future<Map<String, dynamic>> register({
|
||||||
|
required String csrfToken,
|
||||||
|
required String sid,
|
||||||
|
required String fullName,
|
||||||
|
required String phone,
|
||||||
|
required String email,
|
||||||
|
required String customerGroupCode,
|
||||||
|
required String cityCode,
|
||||||
|
String? companyName,
|
||||||
|
String? taxCode,
|
||||||
|
String? idCardFrontBase64,
|
||||||
|
String? idCardBackBase64,
|
||||||
|
List<String>? certificatesBase64,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final response = await _dio.post<Map<String, dynamic>>(
|
||||||
|
'/api/method/building_material.building_material.api.user.register',
|
||||||
|
data: {
|
||||||
|
'full_name': fullName,
|
||||||
|
'phone': phone,
|
||||||
|
'email': email,
|
||||||
|
'customer_group_code': customerGroupCode,
|
||||||
|
'city_code': cityCode,
|
||||||
|
'company_name': companyName,
|
||||||
|
'tax_code': taxCode,
|
||||||
|
'id_card_front_base64': idCardFrontBase64,
|
||||||
|
'id_card_back_base64': idCardBackBase64,
|
||||||
|
'certificates_base64': certificatesBase64 ?? [],
|
||||||
|
},
|
||||||
|
options: Options(
|
||||||
|
headers: {
|
||||||
|
'X-Frappe-Csrf-Token': csrfToken,
|
||||||
|
'Cookie': 'sid=$sid',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200 && response.data != null) {
|
||||||
|
return response.data!;
|
||||||
|
} else {
|
||||||
|
throw ServerException(
|
||||||
|
'Failed to register: ${response.statusCode}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
if (e.response?.statusCode == 401) {
|
||||||
|
throw const UnauthorizedException();
|
||||||
|
} else if (e.response?.statusCode == 400) {
|
||||||
|
throw ValidationException(
|
||||||
|
e.response?.data?['message'] as String? ?? 'Validation error',
|
||||||
|
);
|
||||||
|
} else if (e.response?.statusCode == 404) {
|
||||||
|
throw NotFoundException('Register endpoint not found');
|
||||||
|
} else {
|
||||||
|
throw NetworkException(
|
||||||
|
e.message ?? 'Failed to register',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw ServerException('Unexpected error: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,6 +57,48 @@ sealed class AuthSessionResponse with _$AuthSessionResponse {
|
|||||||
_$AuthSessionResponseFromJson(json);
|
_$AuthSessionResponseFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Session Data (for GET SESSION API)
|
||||||
|
///
|
||||||
|
/// Represents the session data structure from get_session API.
|
||||||
|
@freezed
|
||||||
|
sealed class GetSessionData with _$GetSessionData {
|
||||||
|
const factory GetSessionData({
|
||||||
|
required String sid,
|
||||||
|
@JsonKey(name: 'csrf_token') required String csrfToken,
|
||||||
|
}) = _GetSessionData;
|
||||||
|
|
||||||
|
factory GetSessionData.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$GetSessionDataFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Session Message
|
||||||
|
///
|
||||||
|
/// Wrapper for session data in get_session API response.
|
||||||
|
@freezed
|
||||||
|
sealed class GetSessionMessage with _$GetSessionMessage {
|
||||||
|
const factory GetSessionMessage({
|
||||||
|
required GetSessionData data,
|
||||||
|
}) = _GetSessionMessage;
|
||||||
|
|
||||||
|
factory GetSessionMessage.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$GetSessionMessageFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Session Response
|
||||||
|
///
|
||||||
|
/// Complete response from get_session API.
|
||||||
|
@freezed
|
||||||
|
sealed class GetSessionResponse with _$GetSessionResponse {
|
||||||
|
const factory GetSessionResponse({
|
||||||
|
required GetSessionMessage message,
|
||||||
|
@JsonKey(name: 'home_page') required String homePage,
|
||||||
|
@JsonKey(name: 'full_name') required String fullName,
|
||||||
|
}) = _GetSessionResponse;
|
||||||
|
|
||||||
|
factory GetSessionResponse.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$GetSessionResponseFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
/// Session Storage Model
|
/// Session Storage Model
|
||||||
///
|
///
|
||||||
/// Simplified model for storing session data in Hive.
|
/// Simplified model for storing session data in Hive.
|
||||||
@@ -73,7 +115,17 @@ sealed class SessionData with _$SessionData {
|
|||||||
factory SessionData.fromJson(Map<String, dynamic> json) =>
|
factory SessionData.fromJson(Map<String, dynamic> json) =>
|
||||||
_$SessionDataFromJson(json);
|
_$SessionDataFromJson(json);
|
||||||
|
|
||||||
/// Create from API response
|
/// Create from get_session API response
|
||||||
|
factory SessionData.fromGetSessionResponse(GetSessionResponse response) {
|
||||||
|
return SessionData(
|
||||||
|
sid: response.message.data.sid,
|
||||||
|
csrfToken: response.message.data.csrfToken,
|
||||||
|
fullName: response.fullName,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create from auth login API response
|
||||||
factory SessionData.fromAuthResponse(AuthSessionResponse response) {
|
factory SessionData.fromAuthResponse(AuthSessionResponse response) {
|
||||||
return SessionData(
|
return SessionData(
|
||||||
sid: response.message.sid,
|
sid: response.message.sid,
|
||||||
|
|||||||
@@ -834,6 +834,822 @@ $LoginMessageCopyWith<$Res> get message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$GetSessionData {
|
||||||
|
|
||||||
|
String get sid;@JsonKey(name: 'csrf_token') String get csrfToken;
|
||||||
|
/// Create a copy of GetSessionData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GetSessionDataCopyWith<GetSessionData> get copyWith => _$GetSessionDataCopyWithImpl<GetSessionData>(this as GetSessionData, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this GetSessionData to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is GetSessionData&&(identical(other.sid, sid) || other.sid == sid)&&(identical(other.csrfToken, csrfToken) || other.csrfToken == csrfToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,sid,csrfToken);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'GetSessionData(sid: $sid, csrfToken: $csrfToken)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $GetSessionDataCopyWith<$Res> {
|
||||||
|
factory $GetSessionDataCopyWith(GetSessionData value, $Res Function(GetSessionData) _then) = _$GetSessionDataCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
String sid,@JsonKey(name: 'csrf_token') String csrfToken
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$GetSessionDataCopyWithImpl<$Res>
|
||||||
|
implements $GetSessionDataCopyWith<$Res> {
|
||||||
|
_$GetSessionDataCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final GetSessionData _self;
|
||||||
|
final $Res Function(GetSessionData) _then;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? sid = null,Object? csrfToken = null,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
sid: null == sid ? _self.sid : sid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,csrfToken: null == csrfToken ? _self.csrfToken : csrfToken // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [GetSessionData].
|
||||||
|
extension GetSessionDataPatterns on GetSessionData {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _GetSessionData value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionData() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _GetSessionData value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionData():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _GetSessionData value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionData() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String sid, @JsonKey(name: 'csrf_token') String csrfToken)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionData() when $default != null:
|
||||||
|
return $default(_that.sid,_that.csrfToken);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String sid, @JsonKey(name: 'csrf_token') String csrfToken) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionData():
|
||||||
|
return $default(_that.sid,_that.csrfToken);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String sid, @JsonKey(name: 'csrf_token') String csrfToken)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionData() when $default != null:
|
||||||
|
return $default(_that.sid,_that.csrfToken);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _GetSessionData implements GetSessionData {
|
||||||
|
const _GetSessionData({required this.sid, @JsonKey(name: 'csrf_token') required this.csrfToken});
|
||||||
|
factory _GetSessionData.fromJson(Map<String, dynamic> json) => _$GetSessionDataFromJson(json);
|
||||||
|
|
||||||
|
@override final String sid;
|
||||||
|
@override@JsonKey(name: 'csrf_token') final String csrfToken;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$GetSessionDataCopyWith<_GetSessionData> get copyWith => __$GetSessionDataCopyWithImpl<_GetSessionData>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$GetSessionDataToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetSessionData&&(identical(other.sid, sid) || other.sid == sid)&&(identical(other.csrfToken, csrfToken) || other.csrfToken == csrfToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,sid,csrfToken);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'GetSessionData(sid: $sid, csrfToken: $csrfToken)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$GetSessionDataCopyWith<$Res> implements $GetSessionDataCopyWith<$Res> {
|
||||||
|
factory _$GetSessionDataCopyWith(_GetSessionData value, $Res Function(_GetSessionData) _then) = __$GetSessionDataCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
String sid,@JsonKey(name: 'csrf_token') String csrfToken
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$GetSessionDataCopyWithImpl<$Res>
|
||||||
|
implements _$GetSessionDataCopyWith<$Res> {
|
||||||
|
__$GetSessionDataCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _GetSessionData _self;
|
||||||
|
final $Res Function(_GetSessionData) _then;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? sid = null,Object? csrfToken = null,}) {
|
||||||
|
return _then(_GetSessionData(
|
||||||
|
sid: null == sid ? _self.sid : sid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,csrfToken: null == csrfToken ? _self.csrfToken : csrfToken // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$GetSessionMessage {
|
||||||
|
|
||||||
|
GetSessionData get data;
|
||||||
|
/// Create a copy of GetSessionMessage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GetSessionMessageCopyWith<GetSessionMessage> get copyWith => _$GetSessionMessageCopyWithImpl<GetSessionMessage>(this as GetSessionMessage, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this GetSessionMessage to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is GetSessionMessage&&(identical(other.data, data) || other.data == data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,data);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'GetSessionMessage(data: $data)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $GetSessionMessageCopyWith<$Res> {
|
||||||
|
factory $GetSessionMessageCopyWith(GetSessionMessage value, $Res Function(GetSessionMessage) _then) = _$GetSessionMessageCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
GetSessionData data
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$GetSessionDataCopyWith<$Res> get data;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$GetSessionMessageCopyWithImpl<$Res>
|
||||||
|
implements $GetSessionMessageCopyWith<$Res> {
|
||||||
|
_$GetSessionMessageCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final GetSessionMessage _self;
|
||||||
|
final $Res Function(GetSessionMessage) _then;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionMessage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? data = null,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
data: null == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
|
||||||
|
as GetSessionData,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
/// Create a copy of GetSessionMessage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GetSessionDataCopyWith<$Res> get data {
|
||||||
|
|
||||||
|
return $GetSessionDataCopyWith<$Res>(_self.data, (value) {
|
||||||
|
return _then(_self.copyWith(data: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [GetSessionMessage].
|
||||||
|
extension GetSessionMessagePatterns on GetSessionMessage {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _GetSessionMessage value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionMessage() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _GetSessionMessage value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionMessage():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _GetSessionMessage value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionMessage() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( GetSessionData data)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionMessage() when $default != null:
|
||||||
|
return $default(_that.data);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( GetSessionData data) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionMessage():
|
||||||
|
return $default(_that.data);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( GetSessionData data)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionMessage() when $default != null:
|
||||||
|
return $default(_that.data);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _GetSessionMessage implements GetSessionMessage {
|
||||||
|
const _GetSessionMessage({required this.data});
|
||||||
|
factory _GetSessionMessage.fromJson(Map<String, dynamic> json) => _$GetSessionMessageFromJson(json);
|
||||||
|
|
||||||
|
@override final GetSessionData data;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionMessage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$GetSessionMessageCopyWith<_GetSessionMessage> get copyWith => __$GetSessionMessageCopyWithImpl<_GetSessionMessage>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$GetSessionMessageToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetSessionMessage&&(identical(other.data, data) || other.data == data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,data);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'GetSessionMessage(data: $data)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$GetSessionMessageCopyWith<$Res> implements $GetSessionMessageCopyWith<$Res> {
|
||||||
|
factory _$GetSessionMessageCopyWith(_GetSessionMessage value, $Res Function(_GetSessionMessage) _then) = __$GetSessionMessageCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
GetSessionData data
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@override $GetSessionDataCopyWith<$Res> get data;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$GetSessionMessageCopyWithImpl<$Res>
|
||||||
|
implements _$GetSessionMessageCopyWith<$Res> {
|
||||||
|
__$GetSessionMessageCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _GetSessionMessage _self;
|
||||||
|
final $Res Function(_GetSessionMessage) _then;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionMessage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? data = null,}) {
|
||||||
|
return _then(_GetSessionMessage(
|
||||||
|
data: null == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
|
||||||
|
as GetSessionData,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionMessage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GetSessionDataCopyWith<$Res> get data {
|
||||||
|
|
||||||
|
return $GetSessionDataCopyWith<$Res>(_self.data, (value) {
|
||||||
|
return _then(_self.copyWith(data: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$GetSessionResponse {
|
||||||
|
|
||||||
|
GetSessionMessage get message;@JsonKey(name: 'home_page') String get homePage;@JsonKey(name: 'full_name') String get fullName;
|
||||||
|
/// Create a copy of GetSessionResponse
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GetSessionResponseCopyWith<GetSessionResponse> get copyWith => _$GetSessionResponseCopyWithImpl<GetSessionResponse>(this as GetSessionResponse, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this GetSessionResponse to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is GetSessionResponse&&(identical(other.message, message) || other.message == message)&&(identical(other.homePage, homePage) || other.homePage == homePage)&&(identical(other.fullName, fullName) || other.fullName == fullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,message,homePage,fullName);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'GetSessionResponse(message: $message, homePage: $homePage, fullName: $fullName)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $GetSessionResponseCopyWith<$Res> {
|
||||||
|
factory $GetSessionResponseCopyWith(GetSessionResponse value, $Res Function(GetSessionResponse) _then) = _$GetSessionResponseCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
GetSessionMessage message,@JsonKey(name: 'home_page') String homePage,@JsonKey(name: 'full_name') String fullName
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$GetSessionMessageCopyWith<$Res> get message;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$GetSessionResponseCopyWithImpl<$Res>
|
||||||
|
implements $GetSessionResponseCopyWith<$Res> {
|
||||||
|
_$GetSessionResponseCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final GetSessionResponse _self;
|
||||||
|
final $Res Function(GetSessionResponse) _then;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionResponse
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? message = null,Object? homePage = null,Object? fullName = null,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable
|
||||||
|
as GetSessionMessage,homePage: null == homePage ? _self.homePage : homePage // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,fullName: null == fullName ? _self.fullName : fullName // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
/// Create a copy of GetSessionResponse
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GetSessionMessageCopyWith<$Res> get message {
|
||||||
|
|
||||||
|
return $GetSessionMessageCopyWith<$Res>(_self.message, (value) {
|
||||||
|
return _then(_self.copyWith(message: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [GetSessionResponse].
|
||||||
|
extension GetSessionResponsePatterns on GetSessionResponse {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _GetSessionResponse value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionResponse() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _GetSessionResponse value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionResponse():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _GetSessionResponse value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionResponse() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( GetSessionMessage message, @JsonKey(name: 'home_page') String homePage, @JsonKey(name: 'full_name') String fullName)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionResponse() when $default != null:
|
||||||
|
return $default(_that.message,_that.homePage,_that.fullName);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( GetSessionMessage message, @JsonKey(name: 'home_page') String homePage, @JsonKey(name: 'full_name') String fullName) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionResponse():
|
||||||
|
return $default(_that.message,_that.homePage,_that.fullName);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( GetSessionMessage message, @JsonKey(name: 'home_page') String homePage, @JsonKey(name: 'full_name') String fullName)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _GetSessionResponse() when $default != null:
|
||||||
|
return $default(_that.message,_that.homePage,_that.fullName);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _GetSessionResponse implements GetSessionResponse {
|
||||||
|
const _GetSessionResponse({required this.message, @JsonKey(name: 'home_page') required this.homePage, @JsonKey(name: 'full_name') required this.fullName});
|
||||||
|
factory _GetSessionResponse.fromJson(Map<String, dynamic> json) => _$GetSessionResponseFromJson(json);
|
||||||
|
|
||||||
|
@override final GetSessionMessage message;
|
||||||
|
@override@JsonKey(name: 'home_page') final String homePage;
|
||||||
|
@override@JsonKey(name: 'full_name') final String fullName;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionResponse
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$GetSessionResponseCopyWith<_GetSessionResponse> get copyWith => __$GetSessionResponseCopyWithImpl<_GetSessionResponse>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$GetSessionResponseToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetSessionResponse&&(identical(other.message, message) || other.message == message)&&(identical(other.homePage, homePage) || other.homePage == homePage)&&(identical(other.fullName, fullName) || other.fullName == fullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,message,homePage,fullName);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'GetSessionResponse(message: $message, homePage: $homePage, fullName: $fullName)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$GetSessionResponseCopyWith<$Res> implements $GetSessionResponseCopyWith<$Res> {
|
||||||
|
factory _$GetSessionResponseCopyWith(_GetSessionResponse value, $Res Function(_GetSessionResponse) _then) = __$GetSessionResponseCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
GetSessionMessage message,@JsonKey(name: 'home_page') String homePage,@JsonKey(name: 'full_name') String fullName
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@override $GetSessionMessageCopyWith<$Res> get message;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$GetSessionResponseCopyWithImpl<$Res>
|
||||||
|
implements _$GetSessionResponseCopyWith<$Res> {
|
||||||
|
__$GetSessionResponseCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _GetSessionResponse _self;
|
||||||
|
final $Res Function(_GetSessionResponse) _then;
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionResponse
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? message = null,Object? homePage = null,Object? fullName = null,}) {
|
||||||
|
return _then(_GetSessionResponse(
|
||||||
|
message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable
|
||||||
|
as GetSessionMessage,homePage: null == homePage ? _self.homePage : homePage // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,fullName: null == fullName ? _self.fullName : fullName // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of GetSessionResponse
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$GetSessionMessageCopyWith<$Res> get message {
|
||||||
|
|
||||||
|
return $GetSessionMessageCopyWith<$Res>(_self.message, (value) {
|
||||||
|
return _then(_self.copyWith(message: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SessionData {
|
mixin _$SessionData {
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,57 @@ Map<String, dynamic> _$AuthSessionResponseToJson(
|
|||||||
'full_name': instance.fullName,
|
'full_name': instance.fullName,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_GetSessionData _$GetSessionDataFromJson(Map<String, dynamic> json) =>
|
||||||
|
$checkedCreate('_GetSessionData', json, ($checkedConvert) {
|
||||||
|
final val = _GetSessionData(
|
||||||
|
sid: $checkedConvert('sid', (v) => v as String),
|
||||||
|
csrfToken: $checkedConvert('csrf_token', (v) => v as String),
|
||||||
|
);
|
||||||
|
return val;
|
||||||
|
}, fieldKeyMap: const {'csrfToken': 'csrf_token'});
|
||||||
|
|
||||||
|
Map<String, dynamic> _$GetSessionDataToJson(_GetSessionData instance) =>
|
||||||
|
<String, dynamic>{'sid': instance.sid, 'csrf_token': instance.csrfToken};
|
||||||
|
|
||||||
|
_GetSessionMessage _$GetSessionMessageFromJson(Map<String, dynamic> json) =>
|
||||||
|
$checkedCreate('_GetSessionMessage', json, ($checkedConvert) {
|
||||||
|
final val = _GetSessionMessage(
|
||||||
|
data: $checkedConvert(
|
||||||
|
'data',
|
||||||
|
(v) => GetSessionData.fromJson(v as Map<String, dynamic>),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, dynamic> _$GetSessionMessageToJson(_GetSessionMessage instance) =>
|
||||||
|
<String, dynamic>{'data': instance.data.toJson()};
|
||||||
|
|
||||||
|
_GetSessionResponse _$GetSessionResponseFromJson(Map<String, dynamic> json) =>
|
||||||
|
$checkedCreate(
|
||||||
|
'_GetSessionResponse',
|
||||||
|
json,
|
||||||
|
($checkedConvert) {
|
||||||
|
final val = _GetSessionResponse(
|
||||||
|
message: $checkedConvert(
|
||||||
|
'message',
|
||||||
|
(v) => GetSessionMessage.fromJson(v as Map<String, dynamic>),
|
||||||
|
),
|
||||||
|
homePage: $checkedConvert('home_page', (v) => v as String),
|
||||||
|
fullName: $checkedConvert('full_name', (v) => v as String),
|
||||||
|
);
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
fieldKeyMap: const {'homePage': 'home_page', 'fullName': 'full_name'},
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$GetSessionResponseToJson(_GetSessionResponse instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'message': instance.message.toJson(),
|
||||||
|
'home_page': instance.homePage,
|
||||||
|
'full_name': instance.fullName,
|
||||||
|
};
|
||||||
|
|
||||||
_SessionData _$SessionDataFromJson(Map<String, dynamic> json) => $checkedCreate(
|
_SessionData _$SessionDataFromJson(Map<String, dynamic> json) => $checkedCreate(
|
||||||
'_SessionData',
|
'_SessionData',
|
||||||
json,
|
json,
|
||||||
|
|||||||
60
lib/features/auth/domain/entities/city.dart
Normal file
60
lib/features/auth/domain/entities/city.dart
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/// Domain Entity: City
|
||||||
|
///
|
||||||
|
/// Represents a city/province for address selection.
|
||||||
|
library;
|
||||||
|
|
||||||
|
/// City Entity
|
||||||
|
class City {
|
||||||
|
/// Unique city identifier
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
/// City code (e.g., "01", "02")
|
||||||
|
final String code;
|
||||||
|
|
||||||
|
/// Display name
|
||||||
|
final String cityName;
|
||||||
|
|
||||||
|
const City({
|
||||||
|
required this.name,
|
||||||
|
required this.code,
|
||||||
|
required this.cityName,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create from JSON map
|
||||||
|
factory City.fromJson(Map<String, dynamic> json) {
|
||||||
|
return City(
|
||||||
|
name: json['name'] as String,
|
||||||
|
code: json['code'] as String,
|
||||||
|
cityName: json['city_name'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert to JSON map
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'code': code,
|
||||||
|
'city_name': cityName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
|
return other is City &&
|
||||||
|
other.name == name &&
|
||||||
|
other.code == code &&
|
||||||
|
other.cityName == cityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return Object.hash(name, code, cityName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'City(name: $name, code: $code, cityName: $cityName)';
|
||||||
|
}
|
||||||
|
}
|
||||||
60
lib/features/auth/domain/entities/customer_group.dart
Normal file
60
lib/features/auth/domain/entities/customer_group.dart
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/// Domain Entity: Customer Group (Role)
|
||||||
|
///
|
||||||
|
/// Represents a customer group/role for user registration.
|
||||||
|
library;
|
||||||
|
|
||||||
|
/// Customer Group Entity
|
||||||
|
class CustomerGroup {
|
||||||
|
/// Unique identifier
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
/// Display name
|
||||||
|
final String customerGroupName;
|
||||||
|
|
||||||
|
/// Group value/code
|
||||||
|
final String? value;
|
||||||
|
|
||||||
|
const CustomerGroup({
|
||||||
|
required this.name,
|
||||||
|
required this.customerGroupName,
|
||||||
|
this.value,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create from JSON map
|
||||||
|
factory CustomerGroup.fromJson(Map<String, dynamic> json) {
|
||||||
|
return CustomerGroup(
|
||||||
|
name: json['name'] as String,
|
||||||
|
customerGroupName: json['customer_group_name'] as String,
|
||||||
|
value: json['value'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert to JSON map
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'customer_group_name': customerGroupName,
|
||||||
|
if (value != null) 'value': value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
|
return other is CustomerGroup &&
|
||||||
|
other.name == name &&
|
||||||
|
other.customerGroupName == customerGroupName &&
|
||||||
|
other.value == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return Object.hash(name, customerGroupName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'CustomerGroup(name: $name, customerGroupName: $customerGroupName, value: $value)';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
/// Matches design from html/register.html
|
/// Matches design from html/register.html
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -12,12 +13,17 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
|
||||||
import 'package:worker/core/constants/ui_constants.dart';
|
import 'package:worker/core/constants/ui_constants.dart';
|
||||||
|
import 'package:worker/core/router/app_router.dart';
|
||||||
import 'package:worker/core/theme/colors.dart';
|
import 'package:worker/core/theme/colors.dart';
|
||||||
import 'package:worker/core/utils/validators.dart';
|
import 'package:worker/core/utils/validators.dart';
|
||||||
import 'package:worker/features/auth/domain/entities/business_unit.dart';
|
import 'package:worker/features/auth/domain/entities/business_unit.dart';
|
||||||
|
import 'package:worker/features/auth/domain/entities/city.dart';
|
||||||
|
import 'package:worker/features/auth/domain/entities/customer_group.dart';
|
||||||
|
import 'package:worker/features/auth/presentation/providers/cities_provider.dart';
|
||||||
|
import 'package:worker/features/auth/presentation/providers/customer_groups_provider.dart';
|
||||||
|
import 'package:worker/features/auth/presentation/providers/session_provider.dart';
|
||||||
import 'package:worker/features/auth/presentation/widgets/phone_input_field.dart';
|
import 'package:worker/features/auth/presentation/widgets/phone_input_field.dart';
|
||||||
import 'package:worker/features/auth/presentation/widgets/file_upload_card.dart';
|
import 'package:worker/features/auth/presentation/widgets/file_upload_card.dart';
|
||||||
import 'package:worker/features/auth/presentation/widgets/role_dropdown.dart';
|
|
||||||
|
|
||||||
/// Registration Page
|
/// Registration Page
|
||||||
///
|
///
|
||||||
@@ -65,16 +71,60 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
final _companyFocus = FocusNode();
|
final _companyFocus = FocusNode();
|
||||||
|
|
||||||
// State
|
// State
|
||||||
String? _selectedRole;
|
CustomerGroup? _selectedRole;
|
||||||
String? _selectedCity;
|
City? _selectedCity;
|
||||||
File? _idCardFile;
|
File? _idCardFile;
|
||||||
File? _certificateFile;
|
File? _certificateFile;
|
||||||
bool _termsAccepted = false;
|
bool _termsAccepted = false;
|
||||||
bool _passwordVisible = false;
|
bool _passwordVisible = false;
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
bool _isLoadingData = true;
|
||||||
|
bool _hasInitialized = false;
|
||||||
|
|
||||||
final _imagePicker = ImagePicker();
|
final _imagePicker = ImagePicker();
|
||||||
|
|
||||||
|
/// Initialize session and load data
|
||||||
|
/// This should be called from build method or after widget is mounted
|
||||||
|
Future<void> _initializeData() async {
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isLoadingData = true;
|
||||||
|
_hasInitialized = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Step 1: Get session (public API user)
|
||||||
|
await ref.read(sessionProvider.notifier).getSession();
|
||||||
|
|
||||||
|
// Step 2: Fetch cities and customer groups in parallel using the session
|
||||||
|
await Future.wait([
|
||||||
|
ref.read(citiesProvider.notifier).fetchCities(),
|
||||||
|
ref.read(customerGroupsProvider.notifier).fetchCustomerGroups(),
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Lỗi tải dữ liệu: $e'),
|
||||||
|
backgroundColor: AppColors.danger,
|
||||||
|
action: SnackBarAction(
|
||||||
|
label: 'Thử lại',
|
||||||
|
textColor: AppColors.white,
|
||||||
|
onPressed: _initializeData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isLoadingData = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_fullNameController.dispose();
|
_fullNameController.dispose();
|
||||||
@@ -95,8 +145,23 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if verification section should be shown
|
/// Check if verification section should be shown
|
||||||
|
/// Note: This is based on the old role system
|
||||||
|
/// TODO: Update this logic based on actual customer group requirements
|
||||||
bool get _shouldShowVerification {
|
bool get _shouldShowVerification {
|
||||||
return _selectedRole == 'worker' || _selectedRole == 'dealer';
|
// For now, always hide verification section since we're using customer groups
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert file to base64 string
|
||||||
|
Future<String?> _fileToBase64(File? file) async {
|
||||||
|
if (file == null) return null;
|
||||||
|
try {
|
||||||
|
final bytes = await file.readAsBytes();
|
||||||
|
return base64Encode(bytes);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Error converting file to base64: $e');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pick image from gallery or camera
|
/// Pick image from gallery or camera
|
||||||
@@ -238,48 +303,60 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: Implement actual registration API call
|
// Get session state for CSRF token and SID
|
||||||
// Include widget.selectedBusinessUnit?.id in the API request
|
final sessionState = ref.read(sessionProvider);
|
||||||
// Example:
|
|
||||||
// final result = await authRepository.register(
|
|
||||||
// fullName: _fullNameController.text.trim(),
|
|
||||||
// phone: _phoneController.text.trim(),
|
|
||||||
// email: _emailController.text.trim(),
|
|
||||||
// password: _passwordController.text,
|
|
||||||
// role: _selectedRole,
|
|
||||||
// businessUnitId: widget.selectedBusinessUnit?.id,
|
|
||||||
// ...
|
|
||||||
// );
|
|
||||||
|
|
||||||
// For now, simulate API delay
|
if (!sessionState.hasSession) {
|
||||||
await Future.delayed(const Duration(seconds: 2));
|
throw Exception('Session không hợp lệ. Vui lòng thử lại.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert files to base64
|
||||||
|
final idCardFrontBase64 = await _fileToBase64(_idCardFile);
|
||||||
|
final certificatesBase64 = _certificateFile != null
|
||||||
|
? [await _fileToBase64(_certificateFile)]
|
||||||
|
: <String?>[];
|
||||||
|
|
||||||
|
// Remove null values from certificates list
|
||||||
|
final validCertificates = certificatesBase64
|
||||||
|
.whereType<String>()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// Call registration API
|
||||||
|
final dataSource = ref.read(authRemoteDataSourceProvider);
|
||||||
|
final response = await dataSource.register(
|
||||||
|
csrfToken: sessionState.csrfToken!,
|
||||||
|
sid: sessionState.sid!,
|
||||||
|
fullName: _fullNameController.text.trim(),
|
||||||
|
phone: _phoneController.text.trim(),
|
||||||
|
email: _emailController.text.trim(),
|
||||||
|
customerGroupCode: _selectedRole?.value ?? _selectedRole?.name ?? '',
|
||||||
|
cityCode: _selectedCity?.code ?? '',
|
||||||
|
companyName: _companyController.text.trim().isEmpty
|
||||||
|
? null
|
||||||
|
: _companyController.text.trim(),
|
||||||
|
taxCode: _taxCodeController.text.trim().isEmpty
|
||||||
|
? null
|
||||||
|
: _taxCodeController.text.trim(),
|
||||||
|
idCardFrontBase64: idCardFrontBase64,
|
||||||
|
idCardBackBase64: null, // Not collecting back side in current UI
|
||||||
|
certificatesBase64: validCertificates,
|
||||||
|
);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
// Navigate based on role
|
// Show success message
|
||||||
if (_shouldShowVerification) {
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
// For workers/dealers with verification, show pending page
|
const SnackBar(
|
||||||
// TODO: Navigate to pending approval page
|
content: Text(
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
'Đăng ký thành công!',
|
||||||
const SnackBar(
|
// response['message']?.toString() ?? 'Đăng ký thành công!',
|
||||||
content: Text(
|
|
||||||
'Đăng ký thành công! Tài khoản đang chờ xét duyệt.',
|
|
||||||
),
|
|
||||||
backgroundColor: AppColors.success,
|
|
||||||
),
|
),
|
||||||
);
|
duration: Duration(seconds: 1),
|
||||||
context.pop();
|
backgroundColor: AppColors.success,
|
||||||
} else {
|
),
|
||||||
// For other roles, navigate to OTP verification
|
);
|
||||||
// TODO: Navigate to OTP verification page
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
Future<void>.delayed(const Duration(seconds: 1)).then((_) => context.goLogin());
|
||||||
const SnackBar(
|
|
||||||
content: Text('Đăng ký thành công! Vui lòng xác thực OTP.'),
|
|
||||||
backgroundColor: AppColors.success,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
// context.push('/otp-verification');
|
|
||||||
context.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
@@ -301,6 +378,14 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// Initialize data on first build
|
||||||
|
if (!_hasInitialized) {
|
||||||
|
// Use addPostFrameCallback to avoid calling setState during build
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_initializeData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xFFF4F6F8),
|
backgroundColor: const Color(0xFFF4F6F8),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
@@ -320,8 +405,22 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
),
|
),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: _isLoadingData
|
||||||
child: Form(
|
? const Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
CircularProgressIndicator(),
|
||||||
|
SizedBox(height: AppSpacing.md),
|
||||||
|
Text(
|
||||||
|
'Đang tải dữ liệu...',
|
||||||
|
style: TextStyle(color: AppColors.grey500),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: SafeArea(
|
||||||
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(AppSpacing.md),
|
padding: const EdgeInsets.all(AppSpacing.md),
|
||||||
@@ -442,29 +541,9 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: AppSpacing.md),
|
const SizedBox(height: AppSpacing.md),
|
||||||
|
|
||||||
// Role Selection
|
// Role Selection (Customer Groups)
|
||||||
_buildLabel('Vai trò *'),
|
_buildLabel('Vai trò *'),
|
||||||
RoleDropdown(
|
_buildCustomerGroupDropdown(),
|
||||||
value: _selectedRole,
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
_selectedRole = value;
|
|
||||||
// Clear verification fields when role changes
|
|
||||||
if (!_shouldShowVerification) {
|
|
||||||
_idNumberController.clear();
|
|
||||||
_taxCodeController.clear();
|
|
||||||
_idCardFile = null;
|
|
||||||
_certificateFile = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Vui lòng chọn vai trò';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: AppSpacing.md),
|
const SizedBox(height: AppSpacing.md),
|
||||||
|
|
||||||
// Verification Section (conditional)
|
// Verification Section (conditional)
|
||||||
@@ -488,47 +567,7 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
|
|
||||||
// City/Province
|
// City/Province
|
||||||
_buildLabel('Tỉnh/Thành phố *'),
|
_buildLabel('Tỉnh/Thành phố *'),
|
||||||
DropdownButtonFormField<String>(
|
_buildCityDropdown(),
|
||||||
value: _selectedCity,
|
|
||||||
decoration: _buildInputDecoration(
|
|
||||||
hintText: 'Chọn tỉnh/thành phố',
|
|
||||||
prefixIcon: Icons.location_city,
|
|
||||||
),
|
|
||||||
items: const [
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: 'hanoi',
|
|
||||||
child: Text('Hà Nội'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: 'hcm',
|
|
||||||
child: Text('TP. Hồ Chí Minh'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: 'danang',
|
|
||||||
child: Text('Đà Nẵng'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: 'haiphong',
|
|
||||||
child: Text('Hải Phòng'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: 'cantho',
|
|
||||||
child: Text('Cần Thơ'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(value: 'other', child: Text('Khác')),
|
|
||||||
],
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
_selectedCity = value;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Vui lòng chọn tỉnh/thành phố';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: AppSpacing.md),
|
const SizedBox(height: AppSpacing.md),
|
||||||
|
|
||||||
// Terms and Conditions
|
// Terms and Conditions
|
||||||
@@ -648,8 +687,8 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,6 +751,143 @@ class _RegisterPageState extends ConsumerState<RegisterPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build customer group dropdown
|
||||||
|
Widget _buildCustomerGroupDropdown() {
|
||||||
|
final customerGroupsAsync = ref.watch(customerGroupsProvider);
|
||||||
|
|
||||||
|
return customerGroupsAsync.when(
|
||||||
|
data: (groups) {
|
||||||
|
return DropdownButtonFormField<CustomerGroup>(
|
||||||
|
value: _selectedRole,
|
||||||
|
decoration: _buildInputDecoration(
|
||||||
|
hintText: 'Chọn vai trò',
|
||||||
|
prefixIcon: Icons.work,
|
||||||
|
),
|
||||||
|
items: groups
|
||||||
|
.map(
|
||||||
|
(group) => DropdownMenuItem(
|
||||||
|
value: group,
|
||||||
|
child: Text(group.customerGroupName),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_selectedRole = value;
|
||||||
|
// Clear verification fields when role changes
|
||||||
|
if (!_shouldShowVerification) {
|
||||||
|
_idNumberController.clear();
|
||||||
|
_taxCodeController.clear();
|
||||||
|
_idCardFile = null;
|
||||||
|
_certificateFile = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) {
|
||||||
|
return 'Vui lòng chọn vai trò';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const SizedBox(
|
||||||
|
height: 48,
|
||||||
|
child: Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
|
error: (error, stack) => Container(
|
||||||
|
height: 48,
|
||||||
|
padding: const EdgeInsets.all(AppSpacing.sm),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.danger.withValues(alpha: 0.1),
|
||||||
|
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
|
||||||
|
border: Border.all(color: AppColors.danger),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.error_outline, color: AppColors.danger, size: 20),
|
||||||
|
const SizedBox(width: AppSpacing.xs),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Lỗi tải vai trò',
|
||||||
|
style: const TextStyle(color: AppColors.danger, fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: _initializeData,
|
||||||
|
child: const Text('Thử lại', style: TextStyle(fontSize: 12)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build city dropdown
|
||||||
|
Widget _buildCityDropdown() {
|
||||||
|
final citiesAsync = ref.watch(citiesProvider);
|
||||||
|
|
||||||
|
return citiesAsync.when(
|
||||||
|
data: (cities) {
|
||||||
|
return DropdownButtonFormField<City>(
|
||||||
|
value: _selectedCity,
|
||||||
|
decoration: _buildInputDecoration(
|
||||||
|
hintText: 'Chọn tỉnh/thành phố',
|
||||||
|
prefixIcon: Icons.location_city,
|
||||||
|
),
|
||||||
|
items: cities
|
||||||
|
.map(
|
||||||
|
(city) => DropdownMenuItem(
|
||||||
|
value: city,
|
||||||
|
child: Text(city.cityName),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_selectedCity = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) {
|
||||||
|
return 'Vui lòng chọn tỉnh/thành phố';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const SizedBox(
|
||||||
|
height: 48,
|
||||||
|
child: Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
|
error: (error, stack) => Container(
|
||||||
|
height: 48,
|
||||||
|
padding: const EdgeInsets.all(AppSpacing.sm),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.danger.withValues(alpha: 0.1),
|
||||||
|
borderRadius: BorderRadius.circular(InputFieldSpecs.borderRadius),
|
||||||
|
border: Border.all(color: AppColors.danger),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.error_outline, color: AppColors.danger, size: 20),
|
||||||
|
const SizedBox(width: AppSpacing.xs),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Lỗi tải danh sách tỉnh/thành phố',
|
||||||
|
style: const TextStyle(color: AppColors.danger, fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: _initializeData,
|
||||||
|
child: const Text('Thử lại', style: TextStyle(fontSize: 12)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Build verification section
|
/// Build verification section
|
||||||
Widget _buildVerificationSection() {
|
Widget _buildVerificationSection() {
|
||||||
return Container(
|
return Container(
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/// Cities Provider
|
||||||
|
///
|
||||||
|
/// Manages the list of cities/provinces for address selection
|
||||||
|
library;
|
||||||
|
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:worker/features/auth/data/datasources/auth_remote_datasource.dart';
|
||||||
|
import 'package:worker/features/auth/domain/entities/city.dart';
|
||||||
|
import 'package:worker/features/auth/presentation/providers/session_provider.dart';
|
||||||
|
|
||||||
|
part 'cities_provider.g.dart';
|
||||||
|
|
||||||
|
/// Cities Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of cities from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the cities list persists and doesn't auto-dispose.
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class Cities extends _$Cities {
|
||||||
|
@override
|
||||||
|
Future<List<City>> build() async {
|
||||||
|
// Don't auto-fetch on build, wait for manual call
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch cities from API
|
||||||
|
Future<void> fetchCities() async {
|
||||||
|
state = const AsyncValue.loading();
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(() async {
|
||||||
|
final sessionState = ref.read(sessionProvider);
|
||||||
|
|
||||||
|
if (!sessionState.hasSession) {
|
||||||
|
throw Exception('No active session. Please get session first.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final dataSource = ref.read(authRemoteDataSourceProvider);
|
||||||
|
return await dataSource.getCities(
|
||||||
|
csrfToken: sessionState.csrfToken!,
|
||||||
|
sid: sessionState.sid!,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Refresh cities list
|
||||||
|
Future<void> refresh() async {
|
||||||
|
await fetchCities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provider to get a specific city by code
|
||||||
|
@riverpod
|
||||||
|
City? cityByCode(Ref ref, String code) {
|
||||||
|
final citiesAsync = ref.watch(citiesProvider);
|
||||||
|
|
||||||
|
return citiesAsync.whenOrNull(
|
||||||
|
data: (List<City> cities) => cities.firstWhere(
|
||||||
|
(City city) => city.code == code,
|
||||||
|
orElse: () => cities.first,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
160
lib/features/auth/presentation/providers/cities_provider.g.dart
Normal file
160
lib/features/auth/presentation/providers/cities_provider.g.dart
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'cities_provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
/// Cities Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of cities from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the cities list persists and doesn't auto-dispose.
|
||||||
|
|
||||||
|
@ProviderFor(Cities)
|
||||||
|
const citiesProvider = CitiesProvider._();
|
||||||
|
|
||||||
|
/// Cities Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of cities from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the cities list persists and doesn't auto-dispose.
|
||||||
|
final class CitiesProvider extends $AsyncNotifierProvider<Cities, List<City>> {
|
||||||
|
/// Cities Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of cities from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the cities list persists and doesn't auto-dispose.
|
||||||
|
const CitiesProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'citiesProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$citiesHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
Cities create() => Cities();
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$citiesHash() => r'0de4a7d44e576d74ecd875ddad46d6cb52a38bf8';
|
||||||
|
|
||||||
|
/// Cities Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of cities from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the cities list persists and doesn't auto-dispose.
|
||||||
|
|
||||||
|
abstract class _$Cities extends $AsyncNotifier<List<City>> {
|
||||||
|
FutureOr<List<City>> build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final created = build();
|
||||||
|
final ref = this.ref as $Ref<AsyncValue<List<City>>, List<City>>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<AsyncValue<List<City>>, List<City>>,
|
||||||
|
AsyncValue<List<City>>,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provider to get a specific city by code
|
||||||
|
|
||||||
|
@ProviderFor(cityByCode)
|
||||||
|
const cityByCodeProvider = CityByCodeFamily._();
|
||||||
|
|
||||||
|
/// Provider to get a specific city by code
|
||||||
|
|
||||||
|
final class CityByCodeProvider extends $FunctionalProvider<City?, City?, City?>
|
||||||
|
with $Provider<City?> {
|
||||||
|
/// Provider to get a specific city by code
|
||||||
|
const CityByCodeProvider._({
|
||||||
|
required CityByCodeFamily super.from,
|
||||||
|
required String super.argument,
|
||||||
|
}) : super(
|
||||||
|
retry: null,
|
||||||
|
name: r'cityByCodeProvider',
|
||||||
|
isAutoDispose: true,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$cityByCodeHash();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return r'cityByCodeProvider'
|
||||||
|
''
|
||||||
|
'($argument)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$ProviderElement<City?> $createElement($ProviderPointer pointer) =>
|
||||||
|
$ProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
City? create(Ref ref) {
|
||||||
|
final argument = this.argument as String;
|
||||||
|
return cityByCode(ref, argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(City? value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<City?>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is CityByCodeProvider && other.argument == argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return argument.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$cityByCodeHash() => r'4e4a9a72526b0a366b8697244f2e7e2aedf7cabe';
|
||||||
|
|
||||||
|
/// Provider to get a specific city by code
|
||||||
|
|
||||||
|
final class CityByCodeFamily extends $Family
|
||||||
|
with $FunctionalFamilyOverride<City?, String> {
|
||||||
|
const CityByCodeFamily._()
|
||||||
|
: super(
|
||||||
|
retry: null,
|
||||||
|
name: r'cityByCodeProvider',
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
isAutoDispose: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Provider to get a specific city by code
|
||||||
|
|
||||||
|
CityByCodeProvider call(String code) =>
|
||||||
|
CityByCodeProvider._(argument: code, from: this);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => r'cityByCodeProvider';
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/// Customer Groups Provider
|
||||||
|
///
|
||||||
|
/// Manages the list of customer groups (roles) for user registration
|
||||||
|
library;
|
||||||
|
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:worker/features/auth/data/datasources/auth_remote_datasource.dart';
|
||||||
|
import 'package:worker/features/auth/domain/entities/customer_group.dart';
|
||||||
|
import 'package:worker/features/auth/presentation/providers/session_provider.dart';
|
||||||
|
|
||||||
|
part 'customer_groups_provider.g.dart';
|
||||||
|
|
||||||
|
/// Customer Groups Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of customer groups (roles) from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the customer groups list persists and doesn't auto-dispose.
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class CustomerGroups extends _$CustomerGroups {
|
||||||
|
@override
|
||||||
|
Future<List<CustomerGroup>> build() async {
|
||||||
|
// Don't auto-fetch on build, wait for manual call
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch customer groups from API
|
||||||
|
Future<void> fetchCustomerGroups() async {
|
||||||
|
state = const AsyncValue.loading();
|
||||||
|
|
||||||
|
state = await AsyncValue.guard(() async {
|
||||||
|
final sessionState = ref.read(sessionProvider);
|
||||||
|
|
||||||
|
if (!sessionState.hasSession) {
|
||||||
|
throw Exception('No active session. Please get session first.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final dataSource = ref.read(authRemoteDataSourceProvider);
|
||||||
|
return await dataSource.getCustomerGroups(
|
||||||
|
csrfToken: sessionState.csrfToken!,
|
||||||
|
sid: sessionState.sid!,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Refresh customer groups list
|
||||||
|
Future<void> refresh() async {
|
||||||
|
await fetchCustomerGroups();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provider to get a specific customer group by code/value
|
||||||
|
@riverpod
|
||||||
|
CustomerGroup? customerGroupByCode(
|
||||||
|
Ref ref,
|
||||||
|
String code,
|
||||||
|
) {
|
||||||
|
final groupsAsync = ref.watch(customerGroupsProvider);
|
||||||
|
|
||||||
|
return groupsAsync.whenOrNull(
|
||||||
|
data: (List<CustomerGroup> groups) => groups.firstWhere(
|
||||||
|
(CustomerGroup group) => group.value == code || group.name == code,
|
||||||
|
orElse: () => groups.first,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'customer_groups_provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
/// Customer Groups Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of customer groups (roles) from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the customer groups list persists and doesn't auto-dispose.
|
||||||
|
|
||||||
|
@ProviderFor(CustomerGroups)
|
||||||
|
const customerGroupsProvider = CustomerGroupsProvider._();
|
||||||
|
|
||||||
|
/// Customer Groups Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of customer groups (roles) from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the customer groups list persists and doesn't auto-dispose.
|
||||||
|
final class CustomerGroupsProvider
|
||||||
|
extends $AsyncNotifierProvider<CustomerGroups, List<CustomerGroup>> {
|
||||||
|
/// Customer Groups Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of customer groups (roles) from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the customer groups list persists and doesn't auto-dispose.
|
||||||
|
const CustomerGroupsProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'customerGroupsProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$customerGroupsHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
CustomerGroups create() => CustomerGroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$customerGroupsHash() => r'df9107ef844e3cd320804af8d5dcf2fee2462208';
|
||||||
|
|
||||||
|
/// Customer Groups Provider
|
||||||
|
///
|
||||||
|
/// Fetches list of customer groups (roles) from API for registration form.
|
||||||
|
/// Requires active session (CSRF token and SID).
|
||||||
|
/// keepAlive: true ensures the customer groups list persists and doesn't auto-dispose.
|
||||||
|
|
||||||
|
abstract class _$CustomerGroups extends $AsyncNotifier<List<CustomerGroup>> {
|
||||||
|
FutureOr<List<CustomerGroup>> build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final created = build();
|
||||||
|
final ref =
|
||||||
|
this.ref as $Ref<AsyncValue<List<CustomerGroup>>, List<CustomerGroup>>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<AsyncValue<List<CustomerGroup>>, List<CustomerGroup>>,
|
||||||
|
AsyncValue<List<CustomerGroup>>,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provider to get a specific customer group by code/value
|
||||||
|
|
||||||
|
@ProviderFor(customerGroupByCode)
|
||||||
|
const customerGroupByCodeProvider = CustomerGroupByCodeFamily._();
|
||||||
|
|
||||||
|
/// Provider to get a specific customer group by code/value
|
||||||
|
|
||||||
|
final class CustomerGroupByCodeProvider
|
||||||
|
extends $FunctionalProvider<CustomerGroup?, CustomerGroup?, CustomerGroup?>
|
||||||
|
with $Provider<CustomerGroup?> {
|
||||||
|
/// Provider to get a specific customer group by code/value
|
||||||
|
const CustomerGroupByCodeProvider._({
|
||||||
|
required CustomerGroupByCodeFamily super.from,
|
||||||
|
required String super.argument,
|
||||||
|
}) : super(
|
||||||
|
retry: null,
|
||||||
|
name: r'customerGroupByCodeProvider',
|
||||||
|
isAutoDispose: true,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$customerGroupByCodeHash();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return r'customerGroupByCodeProvider'
|
||||||
|
''
|
||||||
|
'($argument)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$ProviderElement<CustomerGroup?> $createElement($ProviderPointer pointer) =>
|
||||||
|
$ProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
CustomerGroup? create(Ref ref) {
|
||||||
|
final argument = this.argument as String;
|
||||||
|
return customerGroupByCode(ref, argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(CustomerGroup? value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<CustomerGroup?>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is CustomerGroupByCodeProvider && other.argument == argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return argument.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$customerGroupByCodeHash() =>
|
||||||
|
r'0ddf96a19d7c20c9fe3ddfd2af80ac49bfe76512';
|
||||||
|
|
||||||
|
/// Provider to get a specific customer group by code/value
|
||||||
|
|
||||||
|
final class CustomerGroupByCodeFamily extends $Family
|
||||||
|
with $FunctionalFamilyOverride<CustomerGroup?, String> {
|
||||||
|
const CustomerGroupByCodeFamily._()
|
||||||
|
: super(
|
||||||
|
retry: null,
|
||||||
|
name: r'customerGroupByCodeProvider',
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
isAutoDispose: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Provider to get a specific customer group by code/value
|
||||||
|
|
||||||
|
CustomerGroupByCodeProvider call(String code) =>
|
||||||
|
CustomerGroupByCodeProvider._(argument: code, from: this);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => r'customerGroupByCodeProvider';
|
||||||
|
}
|
||||||
107
lib/features/auth/presentation/providers/session_provider.dart
Normal file
107
lib/features/auth/presentation/providers/session_provider.dart
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/// Session Provider
|
||||||
|
///
|
||||||
|
/// Manages authentication session (SID and CSRF token)
|
||||||
|
library;
|
||||||
|
|
||||||
|
import 'package:curl_logger_dio_interceptor/curl_logger_dio_interceptor.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:worker/features/auth/data/datasources/auth_remote_datasource.dart';
|
||||||
|
import 'package:worker/features/auth/data/models/auth_session_model.dart';
|
||||||
|
|
||||||
|
part 'session_provider.g.dart';
|
||||||
|
|
||||||
|
/// Provider for Dio instance
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
Dio dio(Ref ref) {
|
||||||
|
final dio = Dio(
|
||||||
|
BaseOptions(
|
||||||
|
baseUrl: 'https://land.dbiz.com',
|
||||||
|
connectTimeout: const Duration(seconds: 30),
|
||||||
|
receiveTimeout: const Duration(seconds: 30),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add curl logger interceptor for debugging
|
||||||
|
dio.interceptors.add(CurlLoggerDioInterceptor(printOnSuccess: true));
|
||||||
|
|
||||||
|
return dio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provider for AuthRemoteDataSource
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
AuthRemoteDataSource authRemoteDataSource(Ref ref) {
|
||||||
|
final dio = ref.watch(dioProvider);
|
||||||
|
return AuthRemoteDataSource(dio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Session State
|
||||||
|
class SessionState {
|
||||||
|
final String? sid;
|
||||||
|
final String? csrfToken;
|
||||||
|
final bool isLoading;
|
||||||
|
final String? error;
|
||||||
|
|
||||||
|
const SessionState({
|
||||||
|
this.sid,
|
||||||
|
this.csrfToken,
|
||||||
|
this.isLoading = false,
|
||||||
|
this.error,
|
||||||
|
});
|
||||||
|
|
||||||
|
SessionState copyWith({
|
||||||
|
String? sid,
|
||||||
|
String? csrfToken,
|
||||||
|
bool? isLoading,
|
||||||
|
String? error,
|
||||||
|
}) {
|
||||||
|
return SessionState(
|
||||||
|
sid: sid ?? this.sid,
|
||||||
|
csrfToken: csrfToken ?? this.csrfToken,
|
||||||
|
isLoading: isLoading ?? this.isLoading,
|
||||||
|
error: error ?? this.error,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasSession => sid != null && csrfToken != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Session Provider
|
||||||
|
///
|
||||||
|
/// Manages the authentication session including SID and CSRF token.
|
||||||
|
/// This should be called before making any authenticated requests.
|
||||||
|
/// keepAlive: true ensures the session persists across the app lifecycle.
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class Session extends _$Session {
|
||||||
|
@override
|
||||||
|
SessionState build() {
|
||||||
|
return const SessionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get session from API
|
||||||
|
Future<void> getSession() async {
|
||||||
|
state = state.copyWith(isLoading: true, error: null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final dataSource = ref.read(authRemoteDataSourceProvider);
|
||||||
|
final response = await dataSource.getSession();
|
||||||
|
|
||||||
|
state = SessionState(
|
||||||
|
sid: response.message.data.sid,
|
||||||
|
csrfToken: response.message.data.csrfToken,
|
||||||
|
isLoading: false,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
state = SessionState(
|
||||||
|
isLoading: false,
|
||||||
|
error: e.toString(),
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear session
|
||||||
|
void clearSession() {
|
||||||
|
state = const SessionState();
|
||||||
|
}
|
||||||
|
}
|
||||||
181
lib/features/auth/presentation/providers/session_provider.g.dart
Normal file
181
lib/features/auth/presentation/providers/session_provider.g.dart
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'session_provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
/// Provider for Dio instance
|
||||||
|
|
||||||
|
@ProviderFor(dio)
|
||||||
|
const dioProvider = DioProvider._();
|
||||||
|
|
||||||
|
/// Provider for Dio instance
|
||||||
|
|
||||||
|
final class DioProvider extends $FunctionalProvider<Dio, Dio, Dio>
|
||||||
|
with $Provider<Dio> {
|
||||||
|
/// Provider for Dio instance
|
||||||
|
const DioProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'dioProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$dioHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$ProviderElement<Dio> $createElement($ProviderPointer pointer) =>
|
||||||
|
$ProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Dio create(Ref ref) {
|
||||||
|
return dio(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(Dio value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<Dio>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$dioHash() => r'2bc10725a1b646cfaabd88c722e5101c06837c75';
|
||||||
|
|
||||||
|
/// Provider for AuthRemoteDataSource
|
||||||
|
|
||||||
|
@ProviderFor(authRemoteDataSource)
|
||||||
|
const authRemoteDataSourceProvider = AuthRemoteDataSourceProvider._();
|
||||||
|
|
||||||
|
/// Provider for AuthRemoteDataSource
|
||||||
|
|
||||||
|
final class AuthRemoteDataSourceProvider
|
||||||
|
extends
|
||||||
|
$FunctionalProvider<
|
||||||
|
AuthRemoteDataSource,
|
||||||
|
AuthRemoteDataSource,
|
||||||
|
AuthRemoteDataSource
|
||||||
|
>
|
||||||
|
with $Provider<AuthRemoteDataSource> {
|
||||||
|
/// Provider for AuthRemoteDataSource
|
||||||
|
const AuthRemoteDataSourceProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'authRemoteDataSourceProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$authRemoteDataSourceHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$ProviderElement<AuthRemoteDataSource> $createElement(
|
||||||
|
$ProviderPointer pointer,
|
||||||
|
) => $ProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
AuthRemoteDataSource create(Ref ref) {
|
||||||
|
return authRemoteDataSource(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(AuthRemoteDataSource value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<AuthRemoteDataSource>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$authRemoteDataSourceHash() =>
|
||||||
|
r'6a18a0d3fee86c512b6eec01b8e8fda53a307a4c';
|
||||||
|
|
||||||
|
/// Session Provider
|
||||||
|
///
|
||||||
|
/// Manages the authentication session including SID and CSRF token.
|
||||||
|
/// This should be called before making any authenticated requests.
|
||||||
|
/// keepAlive: true ensures the session persists across the app lifecycle.
|
||||||
|
|
||||||
|
@ProviderFor(Session)
|
||||||
|
const sessionProvider = SessionProvider._();
|
||||||
|
|
||||||
|
/// Session Provider
|
||||||
|
///
|
||||||
|
/// Manages the authentication session including SID and CSRF token.
|
||||||
|
/// This should be called before making any authenticated requests.
|
||||||
|
/// keepAlive: true ensures the session persists across the app lifecycle.
|
||||||
|
final class SessionProvider extends $NotifierProvider<Session, SessionState> {
|
||||||
|
/// Session Provider
|
||||||
|
///
|
||||||
|
/// Manages the authentication session including SID and CSRF token.
|
||||||
|
/// This should be called before making any authenticated requests.
|
||||||
|
/// keepAlive: true ensures the session persists across the app lifecycle.
|
||||||
|
const SessionProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'sessionProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$sessionHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
Session create() => Session();
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(SessionState value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<SessionState>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$sessionHash() => r'9c755f010681d87ab3898c4daaa920501104df46';
|
||||||
|
|
||||||
|
/// Session Provider
|
||||||
|
///
|
||||||
|
/// Manages the authentication session including SID and CSRF token.
|
||||||
|
/// This should be called before making any authenticated requests.
|
||||||
|
/// keepAlive: true ensures the session persists across the app lifecycle.
|
||||||
|
|
||||||
|
abstract class _$Session extends $Notifier<SessionState> {
|
||||||
|
SessionState build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final created = build();
|
||||||
|
final ref = this.ref as $Ref<SessionState, SessionState>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<SessionState, SessionState>,
|
||||||
|
SessionState,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, created);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -273,6 +273,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.8"
|
||||||
|
curl_logger_dio_interceptor:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: curl_logger_dio_interceptor
|
||||||
|
sha256: f20d89187a321d2150e1412bca30ebf4d89130bafc648ce21bd4f1ef4062b214
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
custom_lint:
|
custom_lint:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ dependencies:
|
|||||||
dio: ^5.4.3+1
|
dio: ^5.4.3+1
|
||||||
connectivity_plus: ^6.0.3
|
connectivity_plus: ^6.0.3
|
||||||
pretty_dio_logger: ^1.3.1
|
pretty_dio_logger: ^1.3.1
|
||||||
|
curl_logger_dio_interceptor: ^1.0.0
|
||||||
dio_cache_interceptor: ^3.5.0
|
dio_cache_interceptor: ^3.5.0
|
||||||
dio_cache_interceptor_hive_store: ^3.2.2
|
dio_cache_interceptor_hive_store: ^3.2.2
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user