Files
front-hokm/lib/feature/shop/presentation/bloc/shop_bloc.dart
T

123 lines
4.5 KiB
Dart

import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../core/payment/payment_gateway.dart';
import '../../../../core/storage/token_storage.dart';
import '../../../../core/resources/data_state.dart';
import '../../../../core/usecase/use_case.dart';
import '../../domain/use_cases/ad_reward_usecase.dart';
import '../../domain/use_cases/buy_card_usecase.dart';
import '../../domain/use_cases/get_shop_usecase.dart';
import '../../domain/use_cases/purchase_usecase.dart';
import '../../domain/use_cases/select_card_usecase.dart';
import 'shop_event.dart';
import 'shop_state.dart';
import 'shop_status.dart';
class ShopBloc extends Bloc<ShopEvent, ShopBlocState> {
final GetShopUseCase getShopUseCase;
final BuyCardUseCase buyCardUseCase;
final SelectCardUseCase selectCardUseCase;
final PurchaseUseCase purchaseUseCase;
final AdRewardUseCase adRewardUseCase;
final PaymentGateway gateway;
final TokenStorage storage;
ShopBloc(
this.getShopUseCase,
this.buyCardUseCase,
this.selectCardUseCase,
this.purchaseUseCase,
this.adRewardUseCase,
this.gateway,
this.storage,
) : super(ShopBlocState.initial()) {
on<LoadShopEvent>((event, emit) => _load(emit));
on<BuyCardEvent>((event, emit) =>
_action(emit, () => buyCardUseCase(event.cardId)));
on<SelectCardEvent>((event, emit) =>
_action(emit, () => selectCardUseCase(event.cardId)));
on<PurchaseEvent>((event, emit) => _action(emit, () => _purchase(event)));
on<AdRewardEvent>((event, emit) => _action(
emit,
() async {
final res = await adRewardUseCase(
'dev-ad-${DateTime.now().millisecondsSinceEpoch}');
if (res is DataSuccess) {
return const DataSuccess('سکه رایگان دریافت شد');
}
return DataError<String>(res.error!);
},
));
}
/// جریانِ خرید: ابتدا پرداختِ فروشگاهی (native) اجرا می‌شود، سپس مدرکِ خرید
/// (token/purchaseData/signature) برای اعتبارسنجی به بک‌اند فرستاده می‌شود و
/// در پایان، خرید در فروشگاه consume می‌شود.
Future<DataState<String>> _purchase(PurchaseEvent event) async {
// برای پرداختِ native به SKUِ فروشگاه نیاز است؛ اگر تنظیم نشده باشد از
// شناسه‌ی کاتالوگ استفاده می‌کنیم (حالتِ توسعه/تک‌فروشگاهی).
final sku = event.sku.isNotEmpty ? event.sku : event.productId;
// شماره‌ی موبایل را به‌عنوان payload می‌فرستیم تا خرید در پنلِ فروشگاه
// قابلِ ردیابی باشد.
final mobile = await storage.readMobile() ?? '';
final PurchaseResult result;
try {
result = await gateway.purchase(sku, payload: mobile);
} catch (e) {
return DataError<String>('خطا در پرداخت: $e');
}
if (!result.success) {
return DataError<String>('خرید انجام نشد یا لغو شد');
}
final verify = await purchaseUseCase(PurchaseParams(
store: gateway.store,
kind: event.kind,
productId: event.productId,
token: result.token,
purchaseData: result.purchaseData,
signature: result.signature,
));
// پس از تأییدِ بک‌اند، خرید را در فروشگاه نهایی/مصرف می‌کنیم.
if (verify is DataSuccess && result.onConfirmed != null) {
try {
await result.onConfirmed!();
} catch (_) {/* consume ناموفق حیاتی نیست */}
}
return verify;
}
Future<void> _load(Emitter<ShopBlocState> emit) async {
emit(state.copyWith(loadStatus: ShopLoading()));
final res = await getShopUseCase(const NoParams());
if (res is DataSuccess) {
emit(state.copyWith(loadStatus: ShopLoaded(res.data!)));
} else {
emit(state.copyWith(loadStatus: ShopLoadError(res.error!)));
}
}
/// اجرای یک عملیات، نمایش وضعیت و سپس بازخوانی کاتالوگ.
Future<void> _action(
Emitter<ShopBlocState> emit,
Future<DataState<String>> Function() action,
) async {
if (state.busy) return;
emit(state.copyWith(actionStatus: ActionLoading()));
final res = await action();
if (res is DataSuccess) {
emit(state.copyWith(actionStatus: ActionSuccess(res.data!)));
await _load(emit);
} else {
emit(state.copyWith(actionStatus: ActionError(res.error!)));
}
}
}