Commit e92ea8bf authored by DatHV's avatar DatHV
Browse files

update logic

parent 5413611e
......@@ -10,4 +10,7 @@ class APIPaths {
static const String otpCreateNew = "/otpCreateNew/1.0.0";
static const String websitePageGetDetail = "/websitePageGetDetail/1.0.0";
static const String websitePage = "/user/api/v2.0/websitePage";
static const String websiteFolderGetPageList = "/websiteFolderGetPageList/1.0.0";
static const String otpVerifyForDoingNextEvent = "/otpVerifyForDoingNextEvent/1.0.0";
static const String accountPasswordReset = "/accountPasswordReset/1.0.0";
}
......@@ -7,20 +7,22 @@ part 'directional_screen.g.dart';
@JsonSerializable()
class DirectionalScreen {
@JsonKey(name: "click_action_type")
final String clickActionType;
final String? clickActionType;
@JsonKey(name: "click_action_param")
final String? clickActionParam;
final ClickActionType? actionType;
DirectionalScreen({
required this.clickActionType,
this.clickActionType,
this.clickActionParam,
this.actionType,
});
factory DirectionalScreen.fromJson(Map<String, dynamic> json) => _$DirectionalScreenFromJson(json);
Map<String, dynamic> toJson() => _$DirectionalScreenToJson(this);
void begin() {
final type = ClickActionTypeExtension.fromString(clickActionType);
final type = ClickActionTypeExtension.fromString(clickActionType ?? actionType?.key ?? "");
if (type == null) {
print("Không nhận diện được action type: $clickActionType");
return;
......
......@@ -8,12 +8,21 @@ part of 'directional_screen.dart';
DirectionalScreen _$DirectionalScreenFromJson(Map<String, dynamic> json) =>
DirectionalScreen(
clickActionType: json['click_action_type'] as String,
clickActionType: json['click_action_type'] as String?,
clickActionParam: json['click_action_param'] as String?,
actionType: $enumDecodeNullable(
_$ClickActionTypeEnumMap,
json['actionType'],
),
);
Map<String, dynamic> _$DirectionalScreenToJson(DirectionalScreen instance) =>
<String, dynamic>{
'click_action_type': instance.clickActionType,
'click_action_param': instance.clickActionParam,
'actionType': _$ClickActionTypeEnumMap[instance.actionType],
};
const _$ClickActionTypeEnumMap = {
ClickActionType.campaignDetail: 'campaignDetail',
};
......@@ -6,8 +6,10 @@ import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/networking/restful_api.dart';
import '../configs/device_info.dart';
import '../model/update_response_object.dart';
import '../screen/faqs/faqs_model.dart';
import '../screen/onboarding/model/check_phone_response_model.dart';
import '../screen/onboarding/model/onboarding_info_model.dart';
import '../screen/otp/model/create_otp_response_model.dart';
import '../screen/otp/model/otp_verify_response_model.dart';
import '../screen/pageDetail/model/campaign_detail_model.dart';
import '../screen/pageDetail/model/detail_page_rule_type.dart';
......@@ -48,7 +50,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
}
Future<BaseResponseModel<OTPVerifyResponseModel>> verifyOTP(String otp, String mfaToken) async {
final body = {"otp": otp, "mfaToken": mfaToken,};
final body = {"otp": otp, "mfaToken": mfaToken};
return requestNormal(
APIPaths.verifyOtpWithAction,
Method.POST,
......@@ -58,7 +60,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
}
Future<BaseResponseModel<OTPResendResponseModel>> resendOTP(String mfaToken) async {
final body = {"mfaToken": mfaToken,};
final body = {"mfaToken": mfaToken};
return requestNormal(
APIPaths.retryOtpWithAction,
Method.POST,
......@@ -70,27 +72,42 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
Future<BaseResponseModel<EmptyCodable>> signup(String phone, String password) async {
var deviceKey = await DeviceInfo.getDeviceId();
final body = {"username": phone, "password": password.toSha256(), "device_key": deviceKey};
return requestNormal(APIPaths.signup, Method.POST, body, (data) => EmptyCodable.fromJson(data as Json));
}
Future<BaseResponseModel<CreateOTPResponseModel>> otpCreateNew(String ownerId) async {
var deviceKey = await DeviceInfo.getDeviceId();
final body = {"owner_id": ownerId, "ttl": Constants.otpTtl, "resend_after_second": Constants.otpTtl};
return requestNormal(
APIPaths.signup,
APIPaths.otpCreateNew,
Method.POST,
body,
(data) => EmptyCodable.fromJson(data as Json),
(data) => CreateOTPResponseModel.fromJson(data as Json),
);
}
Future<BaseResponseModel<EmptyCodable>> otpCreateNew(String ownerId,) async {
var deviceKey = await DeviceInfo.getDeviceId();
final body = {"owner_id": ownerId, "ttl": Constants.otpTtl, "resend_after_second": Constants.otpTtl};
Future<BaseResponseModel<CreateOTPResponseModel>> otpVerifyForDoingNextEvent(
String ownerId,
String otp,
String nextEventName,
) async {
final body = {
"owner_id": ownerId,
"otp": otp,
"next_event_name": nextEventName,
"ttdne": 180, // TODO
"ttl": Constants.otpTtl, "resend_after_second": Constants.otpTtl,
};
return requestNormal(
APIPaths.otpCreateNew,
APIPaths.otpVerifyForDoingNextEvent,
Method.POST,
body,
(data) => EmptyCodable.fromJson(data as Json),
(data) => CreateOTPResponseModel.fromJson(data as Json),
);
}
Future<BaseResponseModel<CampaignDetailResponseModel>> websitePageGetDetail(String id) async {
final body = {"website_page_id": "18756", "access_token": "",};
final body = {"website_page_id": id};
return requestNormal(
APIPaths.websitePageGetDetail,
Method.POST,
......@@ -100,7 +117,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
}
Future<BaseResponseModel<CampaignDetailResponseModel>> websitePage(DetailPageRuleType rule) async {
final body = {"code": rule.key,};
final body = {"code": rule.key};
return requestNormal(
APIPaths.websitePage,
Method.GET,
......@@ -108,4 +125,24 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
(data) => CampaignDetailResponseModel.fromJson(data as Json),
);
}
Future<BaseResponseModel<FAQItemModelResponse>> websiteFolderGetPageList() async {
final body = {"folder_uri": "FAQ"};
return requestNormal(
APIPaths.websiteFolderGetPageList,
Method.POST,
body,
(data) => FAQItemModelResponse.fromJson(data as Json),
);
}
Future<BaseResponseModel<EmptyCodable>> accountPasswordReset(String phone, String password) async {
final body = {"login_name": phone, "password": password.toSha256()};
return requestNormal(
APIPaths.accountPasswordReset,
Method.POST,
body,
(data) => EmptyCodable.fromJson(data as Json),
);
}
}
......@@ -38,13 +38,11 @@ class CreatePasswordViewModel extends GetxController {
Future<void> onSubmit() async {
if (!isButtonEnabled.value) return;
try {
final response = await repository.signup(newPassword.value);
final response = await repository.setPassword(newPassword.value);
if (response.isSuccess) {
errorMessage.value = "";
// TODO: Điều hướng sang màn hình tiếp theo
// e.g. Get.offAllNamed("/home");
} else {
errorMessage.value = "Tạo mật khẩu thất bại. Thử lại sau.";
errorMessage.value = response.errorMessage ?? "Tạo mật khẩu thất bại. Thử lại sau.";
}
} catch (e) {
errorMessage.value = "Có lỗi xảy ra: $e";
......
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import 'package:mypoint_flutter_app/screen/create_pass/signup_create_password_repository.dart';
import '../../base/base_response_model.dart';
import '../../base/restful_api_viewmodel.dart';
import '../login/login_screen.dart';
import '../splash/splash_screen_viewmodel.dart';
class ResetCreatePasswordRepository extends RestfulApiViewModel implements ICreatePasswordRepository {
@override
late String phoneNumber;
ResetCreatePasswordRepository(this.phoneNumber);
@override
Future<BaseResponseModel<EmptyCodable>> setPassword(String password) async {
showLoading();
return client.accountPasswordReset(phoneNumber, password).then((value) {
hideLoading();
if (value.status == "success" || value.code == 200) {
print("Reset password success");
Get.off(() => LoginScreen(phoneNumber: phoneNumber));
}
return value;
});
}
}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import 'package:mypoint_flutter_app/screen/login/login_screen.dart';
import '../../base/base_response_model.dart';
......@@ -10,8 +9,7 @@ import '../splash/splash_screen_viewmodel.dart';
abstract class ICreatePasswordRepository {
late String phoneNumber;
Future<bool?> createPassword(String newPassword);
Future<BaseResponseModel<EmptyCodable>> signup(String password);
Future<BaseResponseModel<EmptyCodable>> setPassword(String password);
}
class SignUpCreatePasswordRepository extends RestfulApiViewModel implements ICreatePasswordRepository {
......@@ -21,7 +19,7 @@ class SignUpCreatePasswordRepository extends RestfulApiViewModel implements ICre
SignUpCreatePasswordRepository(this.phoneNumber);
@override
Future<BaseResponseModel<EmptyCodable>> signup(String password) async {
Future<BaseResponseModel<EmptyCodable>> setPassword(String password) async {
showLoading();
return client.signup(phoneNumber, password).then((value) {
hideLoading();
......@@ -32,10 +30,4 @@ class SignUpCreatePasswordRepository extends RestfulApiViewModel implements ICre
return value;
});
}
@override
Future<bool?> createPassword(String newPassword) {
// TODO: implement createPassword
throw UnimplementedError();
}
}
import 'package:flutter/material.dart';
import 'faqs_model.dart';
class FAQDetailScreen extends StatelessWidget {
final FAQItemModel faqItem;
const FAQDetailScreen({super.key, required this.faqItem});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(faqItem.title ?? "", style: const TextStyle(fontWeight: FontWeight.bold)),
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 0,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
faqItem.chapeau ?? "",
style: const TextStyle(fontSize: 16, color: Colors.black87),
),
),
);
}
}
import 'package:json_annotation/json_annotation.dart';
part 'faqs_model.g.dart';
@JsonSerializable()
class FAQItemModel {
final String? thumbnail;
@JsonKey(name: "page_id")
final String? pageId;
final String? title;
@JsonKey(name: "publish_at_date")
final String? publishAtDate;
final String? chapeau;
FAQItemModel({
this.thumbnail,
this.pageId,
this.title,
this.publishAtDate,
this.chapeau,
});
factory FAQItemModel.fromJson(Map<String, dynamic> json) => _$FAQItemModelFromJson(json);
Map<String, dynamic> toJson() => _$FAQItemModelToJson(this);
}
@JsonSerializable()
class FAQItemModelResponse {
final List<FAQItemModel>? items;
FAQItemModelResponse({
this.items,
});
factory FAQItemModelResponse.fromJson(Map<String, dynamic> json) => _$FAQItemModelResponseFromJson(json);
Map<String, dynamic> toJson() => _$FAQItemModelResponseToJson(this);
}
\ No newline at end of file
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'faqs_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
FAQItemModel _$FAQItemModelFromJson(Map<String, dynamic> json) => FAQItemModel(
thumbnail: json['thumbnail'] as String?,
pageId: json['page_id'] as String?,
title: json['title'] as String?,
publishAtDate: json['publish_at_date'] as String?,
chapeau: json['chapeau'] as String?,
);
Map<String, dynamic> _$FAQItemModelToJson(FAQItemModel instance) =>
<String, dynamic>{
'thumbnail': instance.thumbnail,
'page_id': instance.pageId,
'title': instance.title,
'publish_at_date': instance.publishAtDate,
'chapeau': instance.chapeau,
};
FAQItemModelResponse _$FAQItemModelResponseFromJson(
Map<String, dynamic> json,
) => FAQItemModelResponse(
items:
(json['items'] as List<dynamic>?)
?.map((e) => FAQItemModel.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$FAQItemModelResponseToJson(
FAQItemModelResponse instance,
) => <String, dynamic>{'items': instance.items};
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/screen/pageDetail/campaign_detail_screen.dart';
import 'package:mypoint_flutter_app/widgets/back_button.dart';
import '../../base/base_screen.dart';
import '../../base/basic_state.dart';
import '../../resouce/base_color.dart';
import 'faqs_viewmodel.dart';
class FAQScreen extends BaseScreen {
const FAQScreen({super.key});
@override
State<FAQScreen> createState() => _FAQScreenState();
}
class _FAQScreenState extends BaseState<FAQScreen> with BasicState {
final FAQViewModel _controller = Get.put(FAQViewModel());
@override
Widget createBody() {
return Scaffold(
appBar: AppBar(
leading: CustomBackButton(),
title: const Text("Câu hỏi thường gặp", style: TextStyle(fontWeight: FontWeight.bold)),
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 0,
),
body: Column(
children: [
Obx(() {
if (_controller.isLoading.value) {
return const Expanded(child: Center(child: CircularProgressIndicator()));
}
if (_controller.faqItems.isEmpty) {
return const Expanded(child: Center(child: Text("Không có dữ liệu.")));
}
return Expanded(child: _buildFAQList());
}),
],
),
);
}
Widget _buildFAQList() {
return ListView.builder(
itemCount: _controller.faqItems.length,
itemBuilder: (context, index) {
final item = _controller.faqItems[index];
return GestureDetector(
onTap: () {
if (item.pageId != null && item.pageId!.isNotEmpty) {
Get.to(() => CampaignDetailScreen(pageId: item.pageId));
} else {
Get.snackbar(
"Thông báo",
"Không thể mở chi tiết vì thiếu ID!",
backgroundColor: Colors.redAccent,
colorText: Colors.white,
);
}
},
child: Column(
children: [
Container(
color: BaseColor.second200,
child: ListTile(
leading: const Icon(Icons.help_outline, color: BaseColor.second500),
title: Text(
item.title ?? "",
style: const TextStyle(fontWeight: FontWeight.bold, color: BaseColor.second700),
),
trailing: Icon(Icons.arrow_forward_ios, size: 16, color: BaseColor.second500),
),
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.only(left: 56, right: 16, bottom: 10), // 👈 56 = icon width + padding mặc định
child: Align(
alignment: Alignment.centerLeft,
child: Text(item.chapeau ?? "", style: const TextStyle(fontSize: 16, color: BaseColor.second500)),
),
),
const SizedBox(height: 8),
],
),
);
},
);
}
}
import 'dart:convert';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import '../../base/restful_api_viewmodel.dart';
import 'faqs_model.dart';
class FAQViewModel extends RestfulApiViewModel {
var faqItems = <FAQItemModel>[].obs;
var isLoading = true.obs;
@override
void onInit() {
super.onInit();
fetchFAQItems();
}
Future<void> fetchFAQItems() async {
showLoading();
isLoading(true);
client.websiteFolderGetPageList().then((value) {
hideLoading();
isLoading(false);
faqItems.value = value.data?.items ?? [];
});
}
}
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:mypoint_flutter_app/configs/constants.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import 'package:mypoint_flutter_app/screen/onboarding/onboarding_screen.dart';
import 'package:mypoint_flutter_app/screen/otp/forgot_pass_otp_repository.dart';
import 'package:mypoint_flutter_app/screen/otp/otp_screen.dart';
import '../../base/restful_api_viewmodel.dart';
import '../../permission/biometric_manager.dart';
// login_state_enum.dart
enum LoginState {
idle,
typing,
done,
error,
}
enum LoginState { idle, typing, done, error }
class LoginViewModel extends RestfulApiViewModel {
final BiometricManager _biometricManager = BiometricManager();
......@@ -70,7 +68,14 @@ class LoginViewModel extends RestfulApiViewModel {
showLoading();
client.otpCreateNew(phoneNumber).then((value) {
hideLoading();
print(value);
// TODO: handle error later
if (value.isSuccess) {
Get.to(
OtpScreen(
repository: ForgotPassOTPRepository(phoneNumber, value.data?.resendAfterSecond ?? Constants.otpTtl),
),
);
}
});
}
......@@ -79,8 +84,7 @@ class LoginViewModel extends RestfulApiViewModel {
// Kiểm tra thiết bị hỗ trợ
final canUse = await canUseBiometrics();
if (!canUse || biometricType.value == BiometricTypeEnum.none) {
Get.snackbar("Thông báo", "Thiết bị không hỗ trợ sinh trắc học",
snackPosition: SnackPosition.BOTTOM);
Get.snackbar("Thông báo", "Thiết bị không hỗ trợ sinh trắc học", snackPosition: SnackPosition.BOTTOM);
return;
}
......@@ -88,7 +92,8 @@ class LoginViewModel extends RestfulApiViewModel {
final success = await _biometricManager.showCustomBiometricDialog(
context,
title: "Xác thực sinh trắc học",
content: (biometricType.value == BiometricTypeEnum.faceId)
content:
(biometricType.value == BiometricTypeEnum.faceId)
? "Bạn có muốn đăng nhập bằng Face ID không?"
: "Bạn có muốn đăng nhập bằng vân tay không?",
confirmText: "Đồng ý",
......
......@@ -7,6 +7,7 @@ import '../../base/base_screen.dart';
import '../../base/basic_state.dart';
import '../../configs/constants.dart';
import '../../resouce/base_color.dart';
import '../faqs/faqs_screen.dart';
import '../login/login_screen.dart';
import '../otp/otp_screen.dart';
import '../otp/verify_otp_repository.dart';
......@@ -64,8 +65,8 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
() => OtpScreen(
repository: VerifyOtpRepository(
_viewModel.phoneNumber.value,
response!.otpTtl ?? 0,
response!.mfaToken ?? "",
response?.otpTtl ?? 0,
response?.mfaToken ?? "",
),
),
);
......@@ -203,7 +204,7 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
const TextSpan(text: " và "),
WidgetSpan(
child: GestureDetector(
onTap: () => Get.to(CampaignDetailScreen(type: DetailPageRuleType.privacyPolicy)),
onTap: () => Get.to(FAQScreen()),// Get.to(CampaignDetailScreen(type: DetailPageRuleType.privacyPolicy)),
child: const Text(
"Chính sách bảo mật",
style: TextStyle(
......
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:mypoint_flutter_app/base/base_response_model.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import 'package:mypoint_flutter_app/screen/create_pass/create_pass_screen.dart';
import 'package:mypoint_flutter_app/screen/create_pass/reset_create_password_repository.dart';
import '../../base/restful_api_viewmodel.dart';
import '../splash/splash_screen_viewmodel.dart';
import 'otp_viewmodel.dart';
class ForgotPassOTPRepository extends RestfulApiViewModel implements IOtpRepository {
ForgotPassOTPRepository(this.phoneNumber, this.otpTtl);
@override
int otpTtl;
@override
String phoneNumber;
@override
Future<int?> resendOtp() {
throw UnimplementedError();
}
@override
Future<void> sendOtp() {
throw UnimplementedError();
}
@override
Future<BaseResponseModel<EmptyCodable>> verifyOtp(String otpCode) {
showLoading();
return client.otpVerifyForDoingNextEvent(phoneNumber, otpCode, "RESET_PASSWORD").then((value) {
hideLoading();
if (value.status == "success" || value.code == 200) {
Get.off(() => CreatePasswordScreen(repository: ResetCreatePasswordRepository(phoneNumber)));
}
return value;
});
}
}
\ No newline at end of file
import 'package:json_annotation/json_annotation.dart';
import '../../splash/splash_screen_viewmodel.dart';
part 'create_otp_response_model.g.dart';
@JsonSerializable()
class CreateOTPResponseModel {
class CreateOTPResponseModel extends EmptyCodable {
@JsonKey(name: 'resend_after_second')
int? resendAfterSecond;
CreateOTPResponseModel({
this.resendAfterSecond,
});
}) : super.fromJson(null);
factory CreateOTPResponseModel.fromJson(Map<String, dynamic> json) => _$CreateOTPResponseModelFromJson(json);
Map<String, dynamic> toJson() => _$CreateOTPResponseModelToJson(this);
......
import 'package:json_annotation/json_annotation.dart';
import '../../splash/splash_screen_viewmodel.dart';
import 'otp_claim_verify_response_model.dart';
part 'otp_verify_response_model.g.dart';
@JsonSerializable()
class OTPVerifyResponseModel {
class OTPVerifyResponseModel extends EmptyCodable {
OTPClaimVerifyResponseModel? claim;
OTPVerifyResponseModel({
this.claim,
});
}) : super.fromJson(null);
factory OTPVerifyResponseModel.fromJson(Map<String, dynamic> json) => _$OTPVerifyResponseModelFromJson(json);
Map<String, dynamic> toJson() => _$OTPVerifyResponseModelToJson(this);
......
......@@ -4,12 +4,13 @@ import 'package:mypoint_flutter_app/base/base_response_model.dart';
import 'package:mypoint_flutter_app/configs/constants.dart';
import 'package:mypoint_flutter_app/screen/create_pass/create_pass_screen.dart';
import 'package:mypoint_flutter_app/screen/login/login_screen.dart';
import 'package:mypoint_flutter_app/screen/splash/splash_screen_viewmodel.dart';
import '../create_pass/signup_create_password_repository.dart';
import 'model/otp_verify_response_model.dart';
abstract class IOtpRepository {
Future<void> sendOtp();
Future<BaseResponseModel<OTPVerifyResponseModel>> verifyOtp(String otpCode);
Future<BaseResponseModel<EmptyCodable>> verifyOtp(String otpCode);
Future<int?> resendOtp();
late String phoneNumber;
late int otpTtl;
......@@ -40,12 +41,6 @@ class OtpViewModel extends GetxController {
}
Future<void> sendOtp() async {
try {
await repository.sendOtp();
startCountdown();
} catch (e) {
errorMessage.value = "Gửi OTP thất bại. Vui lòng thử lại.";
}
}
void startCountdown() {
......@@ -81,14 +76,6 @@ class OtpViewModel extends GetxController {
final response = await repository.verifyOtp(otpCode.value);
if (response.isSuccess) {
errorMessage.value = "";
if (response.data?.claim?.action == "signup") {
Get.off(() => CreatePasswordScreen(repository: SignUpCreatePasswordRepository(repository.phoneNumber)));
return;
}
if (response.data?.claim?.action == "login") {
Get.off(() => LoginScreen(phoneNumber: repository.phoneNumber));
return;
}
} else {
errorMessage.value = response.errorMessage ?? "";
}
......
......@@ -4,6 +4,9 @@ import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import '../../base/base_response_model.dart';
import '../../base/restful_api_viewmodel.dart';
import '../create_pass/create_pass_screen.dart';
import '../create_pass/signup_create_password_repository.dart';
import '../login/login_screen.dart';
import 'model/otp_verify_response_model.dart';
import 'otp_viewmodel.dart';
......@@ -24,6 +27,11 @@ class VerifyOtpRepository extends RestfulApiViewModel implements IOtpRepository
showLoading();
return client.verifyOTP(otpCode, mfaToken).then((value) {
hideLoading();
if (value.data?.claim?.action == "signup") {
Get.off(() => CreatePasswordScreen(repository: SignUpCreatePasswordRepository(phoneNumber)));
} else if (value.data?.claim?.action == "login") {
Get.off(() => LoginScreen(phoneNumber: phoneNumber));
}
return value;
});
}
......
......@@ -3,6 +3,8 @@ import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:get/get.dart';
import '../../base/base_screen.dart';
import '../../base/basic_state.dart';
import '../../directional/directional_action_type.dart';
import '../../directional/directional_screen.dart';
import '../../extensions/string_extension.dart'; // tuỳ dự án
import '../../resouce/base_color.dart';
import '../../widgets/back_button.dart';
......@@ -128,7 +130,9 @@ class _CampaignDetailScreenState extends BaseState<CampaignDetailScreen> with Ba
SizedBox(height: 12,),
ElevatedButton(
onPressed: () {
// Xử lý khi bấm nút
DirectionalScreen(
clickActionType: pageDetail?.buttonClickActionType,
clickActionParam: pageDetail?.buttonClickActionParam).begin();
},
style: ElevatedButton.styleFrom(
backgroundColor: parseHexColor(buttonColor),
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment