import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'payment_draft_provider.g.dart'; /// Session mode the customer is paying for. Mirrors backend `SessionMode` /// (chat | call). Phase 4 introduces `call` as a future option — pricing config /// supplies the call tier list, but no functional voice feature is built yet. enum PaymentMode { chat('chat'), call('call'); final String value; const PaymentMode(this.value); static PaymentMode fromString(String? v) => values.firstWhere((e) => e.value == v, orElse: () => PaymentMode.chat); } /// Draft state shared across the multi-screen payment flow: /// discount-paywall / method-pick / duration-pick / method / waiting / expired. /// /// The state is deliberately minimal — the *source of truth* for amount and /// duration is always the backend (server-validated tier or first-session /// discount). The draft only carries the customer's in-flight intent across /// the screen graph. class PaymentDraft { final PaymentMode mode; final String? durationId; final int? durationMinutes; final int? priceIDR; final String? paymentId; final bool isFirstSessionDiscount; const PaymentDraft({ this.mode = PaymentMode.chat, this.durationId, this.durationMinutes, this.priceIDR, this.paymentId, this.isFirstSessionDiscount = false, }); PaymentDraft copyWith({ PaymentMode? mode, String? durationId, int? durationMinutes, int? priceIDR, String? paymentId, bool? isFirstSessionDiscount, }) { return PaymentDraft( mode: mode ?? this.mode, durationId: durationId ?? this.durationId, durationMinutes: durationMinutes ?? this.durationMinutes, priceIDR: priceIDR ?? this.priceIDR, paymentId: paymentId ?? this.paymentId, isFirstSessionDiscount: isFirstSessionDiscount ?? this.isFirstSessionDiscount, ); } } @Riverpod(keepAlive: true) class PaymentDraftNotifier extends _$PaymentDraftNotifier { @override PaymentDraft build() => const PaymentDraft(); void setMode(PaymentMode mode) { // Switching mode resets the previously-picked tier — chat and call // tier lists are independent. state = state.copyWith( mode: mode, durationId: null, durationMinutes: null, priceIDR: null, ); } void setTier({ required String durationId, required int durationMinutes, required int priceIDR, }) { state = state.copyWith( durationId: durationId, durationMinutes: durationMinutes, priceIDR: priceIDR, ); } void setDiscountPlan({ required int durationMinutes, required int priceIDR, }) { state = state.copyWith( mode: PaymentMode.chat, durationMinutes: durationMinutes, priceIDR: priceIDR, isFirstSessionDiscount: true, ); } void setPaymentId(String paymentId) { state = state.copyWith(paymentId: paymentId); } /// Wipe the draft when entering the flow fresh (e.g. tapping "Mulai Curhat" /// from home). Keeping it across back-nav inside the flow is the default. void reset() { state = const PaymentDraft(); } }