🎨 Use feature based folder structure
This commit is contained in:
1817
lib/wallet/wallet.dart
Normal file
1817
lib/wallet/wallet.dart
Normal file
File diff suppressed because it is too large
Load Diff
162
lib/wallet/wallet.g.dart
Normal file
162
lib/wallet/wallet.g.dart
Normal file
@@ -0,0 +1,162 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'wallet.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(walletCurrent)
|
||||
final walletCurrentProvider = WalletCurrentProvider._();
|
||||
|
||||
final class WalletCurrentProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<SnWallet?>,
|
||||
SnWallet?,
|
||||
FutureOr<SnWallet?>
|
||||
>
|
||||
with $FutureModifier<SnWallet?>, $FutureProvider<SnWallet?> {
|
||||
WalletCurrentProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'walletCurrentProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$walletCurrentHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<SnWallet?> $createElement($ProviderPointer pointer) =>
|
||||
$FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<SnWallet?> create(Ref ref) {
|
||||
return walletCurrent(ref);
|
||||
}
|
||||
}
|
||||
|
||||
String _$walletCurrentHash() => r'6a654d34aa7e3002edf97749e386b0bd3db641bb';
|
||||
|
||||
@ProviderFor(walletStats)
|
||||
final walletStatsProvider = WalletStatsProvider._();
|
||||
|
||||
final class WalletStatsProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<SnWalletStats>,
|
||||
SnWalletStats,
|
||||
FutureOr<SnWalletStats>
|
||||
>
|
||||
with $FutureModifier<SnWalletStats>, $FutureProvider<SnWalletStats> {
|
||||
WalletStatsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'walletStatsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$walletStatsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<SnWalletStats> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<SnWalletStats> create(Ref ref) {
|
||||
return walletStats(ref);
|
||||
}
|
||||
}
|
||||
|
||||
String _$walletStatsHash() => r'fa265e0fa6e59e1687f6e00c2f9579aa619fcefd';
|
||||
|
||||
@ProviderFor(walletFund)
|
||||
final walletFundProvider = WalletFundFamily._();
|
||||
|
||||
final class WalletFundProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<SnWalletFund>,
|
||||
SnWalletFund,
|
||||
FutureOr<SnWalletFund>
|
||||
>
|
||||
with $FutureModifier<SnWalletFund>, $FutureProvider<SnWalletFund> {
|
||||
WalletFundProvider._({
|
||||
required WalletFundFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'walletFundProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$walletFundHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'walletFundProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<SnWalletFund> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<SnWalletFund> create(Ref ref) {
|
||||
final argument = this.argument as String;
|
||||
return walletFund(ref, argument);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is WalletFundProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$walletFundHash() => r'adbbc98e0054ee3687c93b7905dabaa84bfeaf1f';
|
||||
|
||||
final class WalletFundFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnWalletFund>, String> {
|
||||
WalletFundFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'walletFundProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
WalletFundProvider call(String fundId) =>
|
||||
WalletFundProvider._(argument: fundId, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'walletFundProvider';
|
||||
}
|
||||
257
lib/wallet/wallet_models/wallet.dart
Normal file
257
lib/wallet/wallet_models/wallet.dart
Normal file
@@ -0,0 +1,257 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:island/accounts/accounts_models/account.dart';
|
||||
|
||||
part 'wallet.freezed.dart';
|
||||
part 'wallet.g.dart';
|
||||
|
||||
@freezed
|
||||
sealed class SnWallet with _$SnWallet {
|
||||
const factory SnWallet({
|
||||
required String id,
|
||||
required List<SnWalletPocket> pockets,
|
||||
required String accountId,
|
||||
required SnAccount? account,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnWallet;
|
||||
|
||||
factory SnWallet.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnWalletStats with _$SnWalletStats {
|
||||
const factory SnWalletStats({
|
||||
required DateTime periodBegin,
|
||||
required DateTime periodEnd,
|
||||
required int totalTransactions,
|
||||
required int totalOrders,
|
||||
required double totalIncome,
|
||||
required double totalOutgoing,
|
||||
required double sum,
|
||||
@Default({}) Map<String, double> incomeCategories,
|
||||
@Default({}) Map<String, double> outgoingCategories,
|
||||
}) = _SnWalletStats;
|
||||
|
||||
factory SnWalletStats.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletStatsFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnWalletPocket with _$SnWalletPocket {
|
||||
const factory SnWalletPocket({
|
||||
required String id,
|
||||
required String currency,
|
||||
required double amount,
|
||||
required String walletId,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnWalletPocket;
|
||||
|
||||
factory SnWalletPocket.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletPocketFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnTransaction with _$SnTransaction {
|
||||
const factory SnTransaction({
|
||||
required String id,
|
||||
required String currency,
|
||||
required double amount,
|
||||
required String? remarks,
|
||||
required int type,
|
||||
required String? payerWalletId,
|
||||
required SnWallet? payerWallet,
|
||||
required String? payeeWalletId,
|
||||
required SnWallet? payeeWallet,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnTransaction;
|
||||
|
||||
factory SnTransaction.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnTransactionFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnWalletSubscription with _$SnWalletSubscription {
|
||||
const factory SnWalletSubscription({
|
||||
required String id,
|
||||
required DateTime begunAt,
|
||||
required DateTime? endedAt,
|
||||
required String identifier,
|
||||
@Default(true) bool isActive,
|
||||
@Default(false) bool isFreeTrial,
|
||||
@Default(1) int status,
|
||||
required String? paymentMethod,
|
||||
required Map<String, dynamic>? paymentDetails,
|
||||
required double? basePrice,
|
||||
required String? couponId,
|
||||
required dynamic coupon,
|
||||
required DateTime? renewalAt,
|
||||
required String accountId,
|
||||
required SnAccount? account,
|
||||
@Default(true) bool isAvailable,
|
||||
required double? finalPrice,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnWalletSubscription;
|
||||
|
||||
factory SnWalletSubscription.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletSubscriptionFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnWalletSubscriptionRef with _$SnWalletSubscriptionRef {
|
||||
const factory SnWalletSubscriptionRef({
|
||||
required String id,
|
||||
required bool isActive,
|
||||
required String accountId,
|
||||
required DateTime createdAt,
|
||||
required DateTime? deletedAt,
|
||||
required DateTime updatedAt,
|
||||
required String identifier,
|
||||
}) = _SnWalletSubscriptionRef;
|
||||
|
||||
factory SnWalletSubscriptionRef.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletSubscriptionRefFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnWalletOrder with _$SnWalletOrder {
|
||||
const factory SnWalletOrder({
|
||||
required String id,
|
||||
required int status,
|
||||
required String currency,
|
||||
required String? remarks,
|
||||
required String appIdentifier,
|
||||
@Default({}) Map<String, dynamic> meta,
|
||||
required int amount,
|
||||
required DateTime expiredAt,
|
||||
required String? payeeWalletId,
|
||||
required String? transactionId,
|
||||
required String? issuerAppId,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnWalletOrder;
|
||||
|
||||
factory SnWalletOrder.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletOrderFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnWalletGift with _$SnWalletGift {
|
||||
const factory SnWalletGift({
|
||||
required String id,
|
||||
required String giftCode,
|
||||
required String subscriptionIdentifier,
|
||||
required String? recipientId,
|
||||
required SnAccount? recipient,
|
||||
required String gifterId,
|
||||
required SnAccount? gifter,
|
||||
required String? redeemerId,
|
||||
required SnAccount? redeemer,
|
||||
required String? message,
|
||||
required int status,
|
||||
required DateTime? redeemedAt,
|
||||
required DateTime? expiredAt,
|
||||
required String? subscriptionId,
|
||||
required SnWalletSubscription? subscription,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnWalletGift;
|
||||
|
||||
factory SnWalletGift.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletGiftFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnWalletFund with _$SnWalletFund {
|
||||
const factory SnWalletFund({
|
||||
required String id,
|
||||
required String currency,
|
||||
required double totalAmount,
|
||||
required double remainingAmount,
|
||||
required int amountOfSplits,
|
||||
required int splitType, // 0: even, 1: random
|
||||
required int
|
||||
status, // 0: created, 1: partially claimed, 2: fully claimed, 3: expired
|
||||
required String? message,
|
||||
required String creatorAccountId,
|
||||
required SnAccount? creatorAccount,
|
||||
required DateTime expiredAt,
|
||||
required List<SnWalletFundRecipient> recipients,
|
||||
required bool isOpen,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnWalletFund;
|
||||
|
||||
factory SnWalletFund.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletFundFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnWalletFundRecipient with _$SnWalletFundRecipient {
|
||||
const factory SnWalletFundRecipient({
|
||||
required String id,
|
||||
required String fundId,
|
||||
required String recipientAccountId,
|
||||
required SnAccount? recipientAccount,
|
||||
required double amount,
|
||||
required bool isReceived,
|
||||
required DateTime? receivedAt,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnWalletFundRecipient;
|
||||
|
||||
factory SnWalletFundRecipient.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnWalletFundRecipientFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnLotteryTicket with _$SnLotteryTicket {
|
||||
const factory SnLotteryTicket({
|
||||
required String id,
|
||||
required String accountId,
|
||||
required SnAccount? account,
|
||||
required List<int> regionOneNumbers,
|
||||
required int regionTwoNumber,
|
||||
required int multiplier,
|
||||
required int drawStatus,
|
||||
required DateTime? drawDate,
|
||||
required List<int>? matchedRegionOneNumbers,
|
||||
required int? matchedRegionTwoNumber,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnLotteryTicket;
|
||||
|
||||
factory SnLotteryTicket.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnLotteryTicketFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnLotteryRecord with _$SnLotteryRecord {
|
||||
const factory SnLotteryRecord({
|
||||
required String id,
|
||||
required DateTime drawDate,
|
||||
required List<int> winningRegionOneNumbers,
|
||||
required int winningRegionTwoNumber,
|
||||
required int totalTickets,
|
||||
required int totalPrizesAwarded,
|
||||
required double totalPrizeAmount,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
}) = _SnLotteryRecord;
|
||||
|
||||
factory SnLotteryRecord.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnLotteryRecordFromJson(json);
|
||||
}
|
||||
3817
lib/wallet/wallet_models/wallet.freezed.dart
Normal file
3817
lib/wallet/wallet_models/wallet.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
472
lib/wallet/wallet_models/wallet.g.dart
Normal file
472
lib/wallet/wallet_models/wallet.g.dart
Normal file
@@ -0,0 +1,472 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'wallet.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_SnWallet _$SnWalletFromJson(Map<String, dynamic> json) => _SnWallet(
|
||||
id: json['id'] as String,
|
||||
pockets: (json['pockets'] as List<dynamic>)
|
||||
.map((e) => SnWalletPocket.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
accountId: json['account_id'] as String,
|
||||
account: json['account'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletToJson(_SnWallet instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'pockets': instance.pockets.map((e) => e.toJson()).toList(),
|
||||
'account_id': instance.accountId,
|
||||
'account': instance.account?.toJson(),
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnWalletStats _$SnWalletStatsFromJson(Map<String, dynamic> json) =>
|
||||
_SnWalletStats(
|
||||
periodBegin: DateTime.parse(json['period_begin'] as String),
|
||||
periodEnd: DateTime.parse(json['period_end'] as String),
|
||||
totalTransactions: (json['total_transactions'] as num).toInt(),
|
||||
totalOrders: (json['total_orders'] as num).toInt(),
|
||||
totalIncome: (json['total_income'] as num).toDouble(),
|
||||
totalOutgoing: (json['total_outgoing'] as num).toDouble(),
|
||||
sum: (json['sum'] as num).toDouble(),
|
||||
incomeCategories:
|
||||
(json['income_categories'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, (e as num).toDouble()),
|
||||
) ??
|
||||
const {},
|
||||
outgoingCategories:
|
||||
(json['outgoing_categories'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, (e as num).toDouble()),
|
||||
) ??
|
||||
const {},
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletStatsToJson(_SnWalletStats instance) =>
|
||||
<String, dynamic>{
|
||||
'period_begin': instance.periodBegin.toIso8601String(),
|
||||
'period_end': instance.periodEnd.toIso8601String(),
|
||||
'total_transactions': instance.totalTransactions,
|
||||
'total_orders': instance.totalOrders,
|
||||
'total_income': instance.totalIncome,
|
||||
'total_outgoing': instance.totalOutgoing,
|
||||
'sum': instance.sum,
|
||||
'income_categories': instance.incomeCategories,
|
||||
'outgoing_categories': instance.outgoingCategories,
|
||||
};
|
||||
|
||||
_SnWalletPocket _$SnWalletPocketFromJson(Map<String, dynamic> json) =>
|
||||
_SnWalletPocket(
|
||||
id: json['id'] as String,
|
||||
currency: json['currency'] as String,
|
||||
amount: (json['amount'] as num).toDouble(),
|
||||
walletId: json['wallet_id'] as String,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletPocketToJson(_SnWalletPocket instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'currency': instance.currency,
|
||||
'amount': instance.amount,
|
||||
'wallet_id': instance.walletId,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnTransaction _$SnTransactionFromJson(Map<String, dynamic> json) =>
|
||||
_SnTransaction(
|
||||
id: json['id'] as String,
|
||||
currency: json['currency'] as String,
|
||||
amount: (json['amount'] as num).toDouble(),
|
||||
remarks: json['remarks'] as String?,
|
||||
type: (json['type'] as num).toInt(),
|
||||
payerWalletId: json['payer_wallet_id'] as String?,
|
||||
payerWallet: json['payer_wallet'] == null
|
||||
? null
|
||||
: SnWallet.fromJson(json['payer_wallet'] as Map<String, dynamic>),
|
||||
payeeWalletId: json['payee_wallet_id'] as String?,
|
||||
payeeWallet: json['payee_wallet'] == null
|
||||
? null
|
||||
: SnWallet.fromJson(json['payee_wallet'] as Map<String, dynamic>),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnTransactionToJson(_SnTransaction instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'currency': instance.currency,
|
||||
'amount': instance.amount,
|
||||
'remarks': instance.remarks,
|
||||
'type': instance.type,
|
||||
'payer_wallet_id': instance.payerWalletId,
|
||||
'payer_wallet': instance.payerWallet?.toJson(),
|
||||
'payee_wallet_id': instance.payeeWalletId,
|
||||
'payee_wallet': instance.payeeWallet?.toJson(),
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnWalletSubscription _$SnWalletSubscriptionFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnWalletSubscription(
|
||||
id: json['id'] as String,
|
||||
begunAt: DateTime.parse(json['begun_at'] as String),
|
||||
endedAt: json['ended_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['ended_at'] as String),
|
||||
identifier: json['identifier'] as String,
|
||||
isActive: json['is_active'] as bool? ?? true,
|
||||
isFreeTrial: json['is_free_trial'] as bool? ?? false,
|
||||
status: (json['status'] as num?)?.toInt() ?? 1,
|
||||
paymentMethod: json['payment_method'] as String?,
|
||||
paymentDetails: json['payment_details'] as Map<String, dynamic>?,
|
||||
basePrice: (json['base_price'] as num?)?.toDouble(),
|
||||
couponId: json['coupon_id'] as String?,
|
||||
coupon: json['coupon'],
|
||||
renewalAt: json['renewal_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['renewal_at'] as String),
|
||||
accountId: json['account_id'] as String,
|
||||
account: json['account'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||
isAvailable: json['is_available'] as bool? ?? true,
|
||||
finalPrice: (json['final_price'] as num?)?.toDouble(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletSubscriptionToJson(
|
||||
_SnWalletSubscription instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'begun_at': instance.begunAt.toIso8601String(),
|
||||
'ended_at': instance.endedAt?.toIso8601String(),
|
||||
'identifier': instance.identifier,
|
||||
'is_active': instance.isActive,
|
||||
'is_free_trial': instance.isFreeTrial,
|
||||
'status': instance.status,
|
||||
'payment_method': instance.paymentMethod,
|
||||
'payment_details': instance.paymentDetails,
|
||||
'base_price': instance.basePrice,
|
||||
'coupon_id': instance.couponId,
|
||||
'coupon': instance.coupon,
|
||||
'renewal_at': instance.renewalAt?.toIso8601String(),
|
||||
'account_id': instance.accountId,
|
||||
'account': instance.account?.toJson(),
|
||||
'is_available': instance.isAvailable,
|
||||
'final_price': instance.finalPrice,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnWalletSubscriptionRef _$SnWalletSubscriptionRefFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnWalletSubscriptionRef(
|
||||
id: json['id'] as String,
|
||||
isActive: json['is_active'] as bool,
|
||||
accountId: json['account_id'] as String,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
identifier: json['identifier'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletSubscriptionRefToJson(
|
||||
_SnWalletSubscriptionRef instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'is_active': instance.isActive,
|
||||
'account_id': instance.accountId,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'identifier': instance.identifier,
|
||||
};
|
||||
|
||||
_SnWalletOrder _$SnWalletOrderFromJson(Map<String, dynamic> json) =>
|
||||
_SnWalletOrder(
|
||||
id: json['id'] as String,
|
||||
status: (json['status'] as num).toInt(),
|
||||
currency: json['currency'] as String,
|
||||
remarks: json['remarks'] as String?,
|
||||
appIdentifier: json['app_identifier'] as String,
|
||||
meta: json['meta'] as Map<String, dynamic>? ?? const {},
|
||||
amount: (json['amount'] as num).toInt(),
|
||||
expiredAt: DateTime.parse(json['expired_at'] as String),
|
||||
payeeWalletId: json['payee_wallet_id'] as String?,
|
||||
transactionId: json['transaction_id'] as String?,
|
||||
issuerAppId: json['issuer_app_id'] as String?,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletOrderToJson(_SnWalletOrder instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'status': instance.status,
|
||||
'currency': instance.currency,
|
||||
'remarks': instance.remarks,
|
||||
'app_identifier': instance.appIdentifier,
|
||||
'meta': instance.meta,
|
||||
'amount': instance.amount,
|
||||
'expired_at': instance.expiredAt.toIso8601String(),
|
||||
'payee_wallet_id': instance.payeeWalletId,
|
||||
'transaction_id': instance.transactionId,
|
||||
'issuer_app_id': instance.issuerAppId,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnWalletGift _$SnWalletGiftFromJson(Map<String, dynamic> json) =>
|
||||
_SnWalletGift(
|
||||
id: json['id'] as String,
|
||||
giftCode: json['gift_code'] as String,
|
||||
subscriptionIdentifier: json['subscription_identifier'] as String,
|
||||
recipientId: json['recipient_id'] as String?,
|
||||
recipient: json['recipient'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['recipient'] as Map<String, dynamic>),
|
||||
gifterId: json['gifter_id'] as String,
|
||||
gifter: json['gifter'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['gifter'] as Map<String, dynamic>),
|
||||
redeemerId: json['redeemer_id'] as String?,
|
||||
redeemer: json['redeemer'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['redeemer'] as Map<String, dynamic>),
|
||||
message: json['message'] as String?,
|
||||
status: (json['status'] as num).toInt(),
|
||||
redeemedAt: json['redeemed_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['redeemed_at'] as String),
|
||||
expiredAt: json['expired_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['expired_at'] as String),
|
||||
subscriptionId: json['subscription_id'] as String?,
|
||||
subscription: json['subscription'] == null
|
||||
? null
|
||||
: SnWalletSubscription.fromJson(
|
||||
json['subscription'] as Map<String, dynamic>,
|
||||
),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletGiftToJson(_SnWalletGift instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'gift_code': instance.giftCode,
|
||||
'subscription_identifier': instance.subscriptionIdentifier,
|
||||
'recipient_id': instance.recipientId,
|
||||
'recipient': instance.recipient?.toJson(),
|
||||
'gifter_id': instance.gifterId,
|
||||
'gifter': instance.gifter?.toJson(),
|
||||
'redeemer_id': instance.redeemerId,
|
||||
'redeemer': instance.redeemer?.toJson(),
|
||||
'message': instance.message,
|
||||
'status': instance.status,
|
||||
'redeemed_at': instance.redeemedAt?.toIso8601String(),
|
||||
'expired_at': instance.expiredAt?.toIso8601String(),
|
||||
'subscription_id': instance.subscriptionId,
|
||||
'subscription': instance.subscription?.toJson(),
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnWalletFund _$SnWalletFundFromJson(Map<String, dynamic> json) =>
|
||||
_SnWalletFund(
|
||||
id: json['id'] as String,
|
||||
currency: json['currency'] as String,
|
||||
totalAmount: (json['total_amount'] as num).toDouble(),
|
||||
remainingAmount: (json['remaining_amount'] as num).toDouble(),
|
||||
amountOfSplits: (json['amount_of_splits'] as num).toInt(),
|
||||
splitType: (json['split_type'] as num).toInt(),
|
||||
status: (json['status'] as num).toInt(),
|
||||
message: json['message'] as String?,
|
||||
creatorAccountId: json['creator_account_id'] as String,
|
||||
creatorAccount: json['creator_account'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['creator_account'] as Map<String, dynamic>),
|
||||
expiredAt: DateTime.parse(json['expired_at'] as String),
|
||||
recipients: (json['recipients'] as List<dynamic>)
|
||||
.map((e) => SnWalletFundRecipient.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
isOpen: json['is_open'] as bool,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletFundToJson(_SnWalletFund instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'currency': instance.currency,
|
||||
'total_amount': instance.totalAmount,
|
||||
'remaining_amount': instance.remainingAmount,
|
||||
'amount_of_splits': instance.amountOfSplits,
|
||||
'split_type': instance.splitType,
|
||||
'status': instance.status,
|
||||
'message': instance.message,
|
||||
'creator_account_id': instance.creatorAccountId,
|
||||
'creator_account': instance.creatorAccount?.toJson(),
|
||||
'expired_at': instance.expiredAt.toIso8601String(),
|
||||
'recipients': instance.recipients.map((e) => e.toJson()).toList(),
|
||||
'is_open': instance.isOpen,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnWalletFundRecipient _$SnWalletFundRecipientFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnWalletFundRecipient(
|
||||
id: json['id'] as String,
|
||||
fundId: json['fund_id'] as String,
|
||||
recipientAccountId: json['recipient_account_id'] as String,
|
||||
recipientAccount: json['recipient_account'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['recipient_account'] as Map<String, dynamic>),
|
||||
amount: (json['amount'] as num).toDouble(),
|
||||
isReceived: json['is_received'] as bool,
|
||||
receivedAt: json['received_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['received_at'] as String),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnWalletFundRecipientToJson(
|
||||
_SnWalletFundRecipient instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'fund_id': instance.fundId,
|
||||
'recipient_account_id': instance.recipientAccountId,
|
||||
'recipient_account': instance.recipientAccount?.toJson(),
|
||||
'amount': instance.amount,
|
||||
'is_received': instance.isReceived,
|
||||
'received_at': instance.receivedAt?.toIso8601String(),
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnLotteryTicket _$SnLotteryTicketFromJson(Map<String, dynamic> json) =>
|
||||
_SnLotteryTicket(
|
||||
id: json['id'] as String,
|
||||
accountId: json['account_id'] as String,
|
||||
account: json['account'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||
regionOneNumbers: (json['region_one_numbers'] as List<dynamic>)
|
||||
.map((e) => (e as num).toInt())
|
||||
.toList(),
|
||||
regionTwoNumber: (json['region_two_number'] as num).toInt(),
|
||||
multiplier: (json['multiplier'] as num).toInt(),
|
||||
drawStatus: (json['draw_status'] as num).toInt(),
|
||||
drawDate: json['draw_date'] == null
|
||||
? null
|
||||
: DateTime.parse(json['draw_date'] as String),
|
||||
matchedRegionOneNumbers:
|
||||
(json['matched_region_one_numbers'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toInt())
|
||||
.toList(),
|
||||
matchedRegionTwoNumber: (json['matched_region_two_number'] as num?)
|
||||
?.toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnLotteryTicketToJson(_SnLotteryTicket instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'account_id': instance.accountId,
|
||||
'account': instance.account?.toJson(),
|
||||
'region_one_numbers': instance.regionOneNumbers,
|
||||
'region_two_number': instance.regionTwoNumber,
|
||||
'multiplier': instance.multiplier,
|
||||
'draw_status': instance.drawStatus,
|
||||
'draw_date': instance.drawDate?.toIso8601String(),
|
||||
'matched_region_one_numbers': instance.matchedRegionOneNumbers,
|
||||
'matched_region_two_number': instance.matchedRegionTwoNumber,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnLotteryRecord _$SnLotteryRecordFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnLotteryRecord(
|
||||
id: json['id'] as String,
|
||||
drawDate: DateTime.parse(json['draw_date'] as String),
|
||||
winningRegionOneNumbers: (json['winning_region_one_numbers'] as List<dynamic>)
|
||||
.map((e) => (e as num).toInt())
|
||||
.toList(),
|
||||
winningRegionTwoNumber: (json['winning_region_two_number'] as num).toInt(),
|
||||
totalTickets: (json['total_tickets'] as num).toInt(),
|
||||
totalPrizesAwarded: (json['total_prizes_awarded'] as num).toInt(),
|
||||
totalPrizeAmount: (json['total_prize_amount'] as num).toDouble(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnLotteryRecordToJson(_SnLotteryRecord instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'draw_date': instance.drawDate.toIso8601String(),
|
||||
'winning_region_one_numbers': instance.winningRegionOneNumbers,
|
||||
'winning_region_two_number': instance.winningRegionTwoNumber,
|
||||
'total_tickets': instance.totalTickets,
|
||||
'total_prizes_awarded': instance.totalPrizesAwarded,
|
||||
'total_prize_amount': instance.totalPrizeAmount,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
598
lib/wallet/wallet_widgets/wallet/fund_envelope.dart
Normal file
598
lib/wallet/wallet_widgets/wallet/fund_envelope.dart
Normal file
@@ -0,0 +1,598 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/wallet/wallet_models/wallet.dart';
|
||||
import 'package:island/core/network.dart';
|
||||
import 'package:island/accounts/accounts_pod.dart';
|
||||
import 'package:island/shared/widgets/alert.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
part 'fund_envelope.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<SnWalletFund> walletFund(Ref ref, String fundId) async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get('/wallet/wallets/funds/$fundId');
|
||||
return SnWalletFund.fromJson(resp.data);
|
||||
}
|
||||
|
||||
class FundEnvelopeWidget extends HookConsumerWidget {
|
||||
const FundEnvelopeWidget({
|
||||
super.key,
|
||||
required this.fundId,
|
||||
this.maxWidth,
|
||||
this.margin,
|
||||
});
|
||||
|
||||
final String fundId;
|
||||
final double? maxWidth;
|
||||
final EdgeInsetsGeometry? margin;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final fundAsync = ref.watch(walletFundProvider(fundId));
|
||||
|
||||
return Container(
|
||||
width: maxWidth,
|
||||
margin: margin ?? const EdgeInsets.symmetric(vertical: 8),
|
||||
child: fundAsync.when(
|
||||
loading: () => Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
),
|
||||
error: (error, stack) => Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'fundEnvelopeLoadFailed'.tr(),
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.error),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
data: (fund) => Card(
|
||||
margin: EdgeInsets.zero,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
onTap: () => _showClaimDialog(context, ref, fund),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Fund title and status
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.account_balance_wallet,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'fundEnvelope'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium
|
||||
?.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
_buildStatusChips(context, fund),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Amount information
|
||||
Row(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${fund.totalAmount.toStringAsFixed(2)} ${fund.currency}',
|
||||
style: Theme.of(context).textTheme.headlineSmall
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
if (fund.remainingAmount != fund.totalAmount)
|
||||
Text(
|
||||
'fundEnvelopeRemaining'.tr(
|
||||
args: [
|
||||
fund.remainingAmount.toStringAsFixed(2),
|
||||
fund.currency,
|
||||
],
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.secondary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'fundEnvelopeSplit'.tr(
|
||||
args: [
|
||||
fund.splitType == 0
|
||||
? 'fundEnvelopeSplitEvenly'.tr()
|
||||
: 'fundEnvelopeSplitRandomly'.tr(),
|
||||
],
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.color
|
||||
?.withOpacity(0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Recipients overview
|
||||
if (fund.recipients.isNotEmpty) ...[
|
||||
const SizedBox(height: 12),
|
||||
_buildRecipientsOverview(context, fund),
|
||||
],
|
||||
|
||||
// Message
|
||||
if (fund.message != null && fund.message!.isNotEmpty) ...[
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'"${fund.message}"',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontStyle: FontStyle.italic,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
// Creator info
|
||||
if (fund.creatorAccount != null) ...[
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.person,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
fund.creatorAccount!.nick,
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
// Expiry info
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.schedule,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_formatDate(fund.expiredAt),
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showClaimDialog(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
SnWalletFund fund,
|
||||
) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (dialogContext) => FundClaimDialog(
|
||||
fund: fund,
|
||||
onClaim: () async {
|
||||
try {
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
await apiClient.post('/wallet/wallets/funds/${fund.id}/receive');
|
||||
|
||||
// Refresh the fund data after claiming
|
||||
ref.invalidate(walletFundProvider(fund.id));
|
||||
|
||||
if (dialogContext.mounted) {
|
||||
Navigator.of(dialogContext).pop();
|
||||
showSnackBar('fundEnvelopeClaimSuccess'.tr());
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorAlert(e);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusChip(BuildContext context, int status) {
|
||||
String text;
|
||||
Color color;
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
text = 'fundEnvelopeStatusCreated'.tr();
|
||||
color = Colors.blue;
|
||||
break;
|
||||
case 1:
|
||||
text = 'fundEnvelopeStatusPartial'.tr();
|
||||
color = Colors.orange;
|
||||
break;
|
||||
case 2:
|
||||
text = 'fundEnvelopeStatusCompleted'.tr();
|
||||
color = Colors.green;
|
||||
break;
|
||||
case 3:
|
||||
text = 'fundEnvelopeStatusExpired'.tr();
|
||||
color = Colors.red;
|
||||
break;
|
||||
default:
|
||||
text = 'fundEnvelopeStatusUnknown'.tr();
|
||||
color = Colors.grey;
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: color.withOpacity(0.3)),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: color,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusChips(BuildContext context, SnWalletFund fund) {
|
||||
return Row(
|
||||
children: [
|
||||
if (fund.isOpen) ...[
|
||||
_buildOpenFundBadge(context),
|
||||
const SizedBox(width: 6),
|
||||
],
|
||||
_buildStatusChip(context, fund.status),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOpenFundBadge(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.green.withOpacity(0.3)),
|
||||
),
|
||||
child: Text(
|
||||
'Open Fund'.tr(),
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.green,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRecipientsOverview(BuildContext context, SnWalletFund fund) {
|
||||
final claimedCount = fund.recipients.where((r) => r.isReceived).length;
|
||||
final totalCount = fund.isOpen
|
||||
? fund.amountOfSplits
|
||||
: fund.recipients.length;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'fundEnvelopeRecipients'.tr(
|
||||
args: [claimedCount.toString(), totalCount.toString()],
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
LinearProgressIndicator(
|
||||
value: totalCount > 0 ? claimedCount / totalCount : 0,
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainerHighest,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String _formatDate(DateTime date) {
|
||||
try {
|
||||
final now = DateTime.now();
|
||||
final difference = date.difference(now);
|
||||
|
||||
if (difference.isNegative) {
|
||||
final days = difference.inDays.abs();
|
||||
return 'fundEnvelopeExpiredDaysAgo'.plural(
|
||||
days,
|
||||
args: [days.toString()],
|
||||
);
|
||||
} else if (difference.inDays == 0) {
|
||||
final hours = difference.inHours;
|
||||
if (hours == 0) {
|
||||
return 'fundEnvelopeExpiresSoon'.tr();
|
||||
}
|
||||
return 'fundEnvelopeExpiresInHours'.plural(
|
||||
hours,
|
||||
args: [hours.toString()],
|
||||
);
|
||||
} else if (difference.inDays < 7) {
|
||||
final days = difference.inDays;
|
||||
return 'fundEnvelopeExpiresInDays'.plural(
|
||||
days,
|
||||
args: [days.toString()],
|
||||
);
|
||||
} else {
|
||||
return '${date.day}/${date.month}/${date.year}';
|
||||
}
|
||||
} catch (e) {
|
||||
return date.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FundClaimDialog extends HookConsumerWidget {
|
||||
const FundClaimDialog({super.key, required this.fund, required this.onClaim});
|
||||
|
||||
final SnWalletFund fund;
|
||||
final VoidCallback onClaim;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final userInfo = ref.watch(userInfoProvider);
|
||||
|
||||
// Check if user can claim
|
||||
final now = DateTime.now();
|
||||
final isExpired = fund.expiredAt.isBefore(now);
|
||||
final hasRemainingAmount = fund.remainingAmount > 0;
|
||||
final hasUserClaimed =
|
||||
userInfo.value != null &&
|
||||
fund.recipients.any(
|
||||
(recipient) =>
|
||||
recipient.recipientAccountId == userInfo.value!.id &&
|
||||
recipient.isReceived,
|
||||
);
|
||||
final userAbleToClaim =
|
||||
userInfo.value != null &&
|
||||
(fund.isOpen ||
|
||||
fund.recipients.any(
|
||||
(recipient) => recipient.recipientAccountId == userInfo.value!.id,
|
||||
));
|
||||
|
||||
final canClaim =
|
||||
!isExpired && hasRemainingAmount && !hasUserClaimed && userAbleToClaim;
|
||||
|
||||
// Get claimed recipients for display
|
||||
final claimedRecipients = fund.recipients
|
||||
.where((r) => r.isReceived)
|
||||
.toList();
|
||||
final unclaimedRecipients = fund.recipients
|
||||
.where((r) => !r.isReceived)
|
||||
.toList();
|
||||
|
||||
final remainingSplits = fund.isOpen
|
||||
? fund.amountOfSplits - claimedRecipients.length
|
||||
: unclaimedRecipients.length;
|
||||
|
||||
return AlertDialog(
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.account_balance_wallet,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text('Claim Fund'.tr()),
|
||||
],
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Fund info
|
||||
Text(
|
||||
'${fund.totalAmount.toStringAsFixed(2)} ${fund.currency}',
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
|
||||
// Remaining amount
|
||||
Text(
|
||||
'fundEnvelopeRemainingWithSplits'.tr(
|
||||
args: [
|
||||
fund.remainingAmount.toStringAsFixed(2),
|
||||
fund.currency,
|
||||
remainingSplits.toString(),
|
||||
],
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Status indicator
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: fund.isOpen
|
||||
? Colors.green.withOpacity(0.1)
|
||||
: Colors.blue.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: fund.isOpen
|
||||
? Colors.green.withOpacity(0.3)
|
||||
: Colors.blue.withOpacity(0.3),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
fund.isOpen ? 'Open Fund'.tr() : 'Invite Only'.tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: fund.isOpen ? Colors.green : Colors.blue,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Claimed recipients section
|
||||
if (claimedRecipients.isNotEmpty) ...[
|
||||
Text(
|
||||
'Already Claimed'.tr(),
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
...claimedRecipients.map(
|
||||
(recipient) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.check_circle, size: 16, color: Colors.green),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
recipient.recipientAccount?.nick ??
|
||||
'fundEnvelopeUnknownUser'.tr(),
|
||||
style: Theme.of(context).textTheme.bodySmall
|
||||
?.copyWith(
|
||||
decoration: TextDecoration.lineThrough,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${recipient.amount.toStringAsFixed(2)} ${fund.currency}',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
|
||||
// Unclaimed recipients section
|
||||
if (unclaimedRecipients.isNotEmpty) ...[
|
||||
Text(
|
||||
'Available to Claim'.tr(),
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
...unclaimedRecipients.map(
|
||||
(recipient) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.radio_button_unchecked,
|
||||
size: 16,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurfaceVariant.withOpacity(0.5),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
recipient.recipientAccount?.nick ??
|
||||
'fundEnvelopeUnknownUser'.tr(),
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${recipient.amount.toStringAsFixed(2)} ${fund.currency}',
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('Cancel'.tr()),
|
||||
),
|
||||
if (canClaim)
|
||||
FilledButton.icon(
|
||||
icon: const Icon(Icons.account_balance_wallet),
|
||||
label: Text('Claim'.tr()),
|
||||
onPressed: onClaim,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
85
lib/wallet/wallet_widgets/wallet/fund_envelope.g.dart
Normal file
85
lib/wallet/wallet_widgets/wallet/fund_envelope.g.dart
Normal file
@@ -0,0 +1,85 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'fund_envelope.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(walletFund)
|
||||
final walletFundProvider = WalletFundFamily._();
|
||||
|
||||
final class WalletFundProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<SnWalletFund>,
|
||||
SnWalletFund,
|
||||
FutureOr<SnWalletFund>
|
||||
>
|
||||
with $FutureModifier<SnWalletFund>, $FutureProvider<SnWalletFund> {
|
||||
WalletFundProvider._({
|
||||
required WalletFundFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'walletFundProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$walletFundHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'walletFundProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<SnWalletFund> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<SnWalletFund> create(Ref ref) {
|
||||
final argument = this.argument as String;
|
||||
return walletFund(ref, argument);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is WalletFundProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$walletFundHash() => r'566b74f1338de8825c19edbc987f942e05f65f49';
|
||||
|
||||
final class WalletFundFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnWalletFund>, String> {
|
||||
WalletFundFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'walletFundProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
WalletFundProvider call(String fundId) =>
|
||||
WalletFundProvider._(argument: fundId, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'walletFundProvider';
|
||||
}
|
||||
Reference in New Issue
Block a user