👽 Update the API request path due to the sepration of the wallet service
This commit is contained in:
@@ -30,7 +30,7 @@ part 'wallet.g.dart';
|
|||||||
Future<SnWallet?> walletCurrent(Ref ref) async {
|
Future<SnWallet?> walletCurrent(Ref ref) async {
|
||||||
try {
|
try {
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
final resp = await apiClient.get('/pass/wallets');
|
final resp = await apiClient.get('/wallet/wallets');
|
||||||
return SnWallet.fromJson(resp.data);
|
return SnWallet.fromJson(resp.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err is DioException && err.response?.statusCode == 404) {
|
if (err is DioException && err.response?.statusCode == 404) {
|
||||||
@@ -43,7 +43,7 @@ Future<SnWallet?> walletCurrent(Ref ref) async {
|
|||||||
@riverpod
|
@riverpod
|
||||||
Future<SnWalletStats> walletStats(Ref ref) async {
|
Future<SnWalletStats> walletStats(Ref ref) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/pass/wallets/stats');
|
final resp = await client.get('/wallet/wallets/stats');
|
||||||
return SnWalletStats.fromJson(resp.data);
|
return SnWalletStats.fromJson(resp.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -976,7 +976,7 @@ class TransactionListNotifier
|
|||||||
final queryParams = {'offset': offset, 'take': pageSize};
|
final queryParams = {'offset': offset, 'take': pageSize};
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
'/pass/wallets/transactions',
|
'/wallet/wallets/transactions',
|
||||||
queryParameters: queryParams,
|
queryParameters: queryParams,
|
||||||
);
|
);
|
||||||
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||||
@@ -1003,7 +1003,7 @@ class WalletFundsNotifier extends AsyncNotifier<PaginationState<SnWalletFund>>
|
|||||||
final offset = fetchedCount;
|
final offset = fetchedCount;
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
'/pass/wallets/funds?offset=$offset&take=$pageSize',
|
'/wallet/wallets/funds?offset=$offset&take=$pageSize',
|
||||||
);
|
);
|
||||||
// Assuming total count header is present or we just check if list is empty
|
// Assuming total count header is present or we just check if list is empty
|
||||||
final list = (response.data as List)
|
final list = (response.data as List)
|
||||||
@@ -1031,7 +1031,7 @@ class WalletFundRecipientsNotifier
|
|||||||
final offset = fetchedCount;
|
final offset = fetchedCount;
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
'/pass/wallets/funds/recipients?offset=$offset&take=$_pageSize',
|
'/wallet/wallets/funds/recipients?offset=$offset&take=$_pageSize',
|
||||||
);
|
);
|
||||||
final list = (response.data as List)
|
final list = (response.data as List)
|
||||||
.map((e) => SnWalletFundRecipient.fromJson(e))
|
.map((e) => SnWalletFundRecipient.fromJson(e))
|
||||||
@@ -1047,7 +1047,7 @@ class WalletFundRecipientsNotifier
|
|||||||
@riverpod
|
@riverpod
|
||||||
Future<SnWalletFund> walletFund(Ref ref, String fundId) async {
|
Future<SnWalletFund> walletFund(Ref ref, String fundId) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/pass/wallets/funds/$fundId');
|
final resp = await client.get('/wallet/wallets/funds/$fundId');
|
||||||
return SnWalletFund.fromJson(resp.data);
|
return SnWalletFund.fromJson(resp.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1239,7 +1239,7 @@ class WalletScreen extends HookConsumerWidget {
|
|||||||
Future<void> createWallet() async {
|
Future<void> createWallet() async {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
try {
|
try {
|
||||||
await client.post('/pass/wallets');
|
await client.post('/wallet/wallets');
|
||||||
ref.invalidate(walletCurrentProvider);
|
ref.invalidate(walletCurrentProvider);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
@@ -1715,7 +1715,7 @@ class WalletScreen extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final resp = await client.post(
|
final resp = await client.post(
|
||||||
'/pass/wallets/funds',
|
'/wallet/wallets/funds',
|
||||||
data: fundData,
|
data: fundData,
|
||||||
options: Options(headers: {'X-Noop': true}),
|
options: Options(headers: {'X-Noop': true}),
|
||||||
);
|
);
|
||||||
@@ -1723,7 +1723,7 @@ class WalletScreen extends HookConsumerWidget {
|
|||||||
if (fund.status == 0) return; // Already created
|
if (fund.status == 0) return; // Already created
|
||||||
|
|
||||||
final orderResp = await client.post(
|
final orderResp = await client.post(
|
||||||
'/pass/wallets/funds/${fund.id}/order',
|
'/wallet/wallets/funds/${fund.id}/order',
|
||||||
);
|
);
|
||||||
final order = SnWalletOrder.fromJson(orderResp.data);
|
final order = SnWalletOrder.fromJson(orderResp.data);
|
||||||
|
|
||||||
@@ -1763,7 +1763,7 @@ class WalletScreen extends HookConsumerWidget {
|
|||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
await client.post('/pass/wallets/transfer', data: transferData);
|
await client.post('/wallet/wallets/transfer', data: transferData);
|
||||||
|
|
||||||
if (context.mounted) hideLoadingModal(context);
|
if (context.mounted) hideLoadingModal(context);
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class RestorePurchaseSheet extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
await client.post(
|
await client.post(
|
||||||
'/pass/subscriptions/order/restore/${selectedProvider.value!}',
|
'/wallet/subscriptions/order/restore/${selectedProvider.value!}',
|
||||||
data: {'order_id': orderIdController.text.trim()},
|
data: {'order_id': orderIdController.text.trim()},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -79,23 +79,22 @@ class RestorePurchaseSheet extends HookConsumerWidget {
|
|||||||
hint: Text('selectProvider'.tr()),
|
hint: Text('selectProvider'.tr()),
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
items:
|
items: providers.map((provider) {
|
||||||
providers.map((provider) {
|
return DropdownMenuItem<String>(
|
||||||
return DropdownMenuItem<String>(
|
value: provider,
|
||||||
value: provider,
|
child: Row(
|
||||||
child: Row(
|
children: [
|
||||||
children: [
|
getProviderIcon(
|
||||||
getProviderIcon(
|
provider,
|
||||||
provider,
|
size: 20,
|
||||||
size: 20,
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
const Gap(12),
|
|
||||||
Text(getLocalizedProviderName(provider)),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
const Gap(12),
|
||||||
}).toList(),
|
Text(getLocalizedProviderName(provider)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
selectedProvider.value = value;
|
selectedProvider.value = value;
|
||||||
},
|
},
|
||||||
@@ -122,14 +121,13 @@ class RestorePurchaseSheet extends HookConsumerWidget {
|
|||||||
// Restore Button
|
// Restore Button
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: isLoading.value ? null : restorePurchase,
|
onPressed: isLoading.value ? null : restorePurchase,
|
||||||
child:
|
child: isLoading.value
|
||||||
isLoading.value
|
? const SizedBox(
|
||||||
? const SizedBox(
|
height: 20,
|
||||||
height: 20,
|
width: 20,
|
||||||
width: 20,
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
)
|
||||||
)
|
: Text('restore'.tr()),
|
||||||
: Text('restore'.tr()),
|
|
||||||
),
|
),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ part 'stellar_program_tab.g.dart';
|
|||||||
Future<SnWalletSubscription?> accountStellarSubscription(Ref ref) async {
|
Future<SnWalletSubscription?> accountStellarSubscription(Ref ref) async {
|
||||||
try {
|
try {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/pass/subscriptions/fuzzy/solian.stellar');
|
final resp = await client.get('/wallet/subscriptions/fuzzy/solian.stellar');
|
||||||
return SnWalletSubscription.fromJson(resp.data);
|
return SnWalletSubscription.fromJson(resp.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err is DioException && err.response?.statusCode == 404) return null;
|
if (err is DioException && err.response?.statusCode == 404) return null;
|
||||||
@@ -46,7 +46,7 @@ Future<List<SnWalletGift>> accountSentGifts(
|
|||||||
}) async {
|
}) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get(
|
final resp = await client.get(
|
||||||
'/pass/subscriptions/gifts/sent?offset=$offset&take=$take',
|
'/wallet/subscriptions/gifts/sent?offset=$offset&take=$take',
|
||||||
);
|
);
|
||||||
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ Future<List<SnWalletGift>> accountReceivedGifts(
|
|||||||
}) async {
|
}) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get(
|
final resp = await client.get(
|
||||||
'/pass/subscriptions/gifts/received?offset=$offset&take=$take',
|
'/wallet/subscriptions/gifts/received?offset=$offset&take=$take',
|
||||||
);
|
);
|
||||||
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ Future<List<SnWalletGift>> accountReceivedGifts(
|
|||||||
@riverpod
|
@riverpod
|
||||||
Future<SnWalletGift> accountGift(Ref ref, String giftId) async {
|
Future<SnWalletGift> accountGift(Ref ref, String giftId) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/pass/subscriptions/gifts/$giftId');
|
final resp = await client.get('/wallet/subscriptions/gifts/$giftId');
|
||||||
return SnWalletGift.fromJson(resp.data);
|
return SnWalletGift.fromJson(resp.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +379,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
await client.post(
|
await client.post(
|
||||||
'/pass/subscriptions/${membership.identifier}/cancel',
|
'/wallet/subscriptions/${membership.identifier}/cancel',
|
||||||
);
|
);
|
||||||
ref.invalidate(accountStellarSubscriptionProvider);
|
ref.invalidate(accountStellarSubscriptionProvider);
|
||||||
ref.read(userInfoProvider.notifier).fetchUser();
|
ref.read(userInfoProvider.notifier).fetchUser();
|
||||||
@@ -680,7 +680,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final resp = await client.post(
|
final resp = await client.post(
|
||||||
'/pass/subscriptions',
|
'/wallet/subscriptions',
|
||||||
data: {
|
data: {
|
||||||
'identifier': tierId,
|
'identifier': tierId,
|
||||||
'payment_method': 'solian.wallet',
|
'payment_method': 'solian.wallet',
|
||||||
@@ -692,7 +692,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
final subscription = SnWalletSubscription.fromJson(resp.data);
|
final subscription = SnWalletSubscription.fromJson(resp.data);
|
||||||
if (subscription.status == 1) return;
|
if (subscription.status == 1) return;
|
||||||
final orderResp = await client.post(
|
final orderResp = await client.post(
|
||||||
'/pass/subscriptions/${subscription.identifier}/order',
|
'/wallet/subscriptions/${subscription.identifier}/order',
|
||||||
);
|
);
|
||||||
final order = SnWalletOrder.fromJson(orderResp.data);
|
final order = SnWalletOrder.fromJson(orderResp.data);
|
||||||
|
|
||||||
@@ -1188,7 +1188,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final resp = await client.post(
|
final resp = await client.post(
|
||||||
'/pass/subscriptions/gifts/purchase',
|
'/wallet/subscriptions/gifts/purchase',
|
||||||
data: {
|
data: {
|
||||||
'subscription_identifier': subscriptionId,
|
'subscription_identifier': subscriptionId,
|
||||||
'recipient_id': ?recipientId,
|
'recipient_id': ?recipientId,
|
||||||
@@ -1204,7 +1204,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
if (gift.status == 1) return; // Already paid
|
if (gift.status == 1) return; // Already paid
|
||||||
|
|
||||||
final orderResp = await client.post(
|
final orderResp = await client.post(
|
||||||
'/pass/subscriptions/gifts/${gift.id}/order',
|
'/wallet/subscriptions/gifts/${gift.id}/order',
|
||||||
);
|
);
|
||||||
final order = SnWalletOrder.fromJson(orderResp.data);
|
final order = SnWalletOrder.fromJson(orderResp.data);
|
||||||
|
|
||||||
@@ -1226,7 +1226,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Get the updated gift
|
// Get the updated gift
|
||||||
final giftResp = await client.get(
|
final giftResp = await client.get(
|
||||||
'/pass/subscriptions/gifts/${gift.id}',
|
'/wallet/subscriptions/gifts/${gift.id}',
|
||||||
);
|
);
|
||||||
final updatedGift = SnWalletGift.fromJson(giftResp.data);
|
final updatedGift = SnWalletGift.fromJson(giftResp.data);
|
||||||
|
|
||||||
@@ -1328,7 +1328,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
|
|
||||||
// First check if gift can be redeemed
|
// First check if gift can be redeemed
|
||||||
final checkResp = await client.get(
|
final checkResp = await client.get(
|
||||||
'/pass/subscriptions/gifts/check/$giftCode',
|
'/wallet/subscriptions/gifts/check/$giftCode',
|
||||||
);
|
);
|
||||||
final checkData = checkResp.data as Map<String, dynamic>;
|
final checkData = checkResp.data as Map<String, dynamic>;
|
||||||
|
|
||||||
@@ -1340,7 +1340,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Redeem the gift
|
// Redeem the gift
|
||||||
await client.post(
|
await client.post(
|
||||||
'/pass/subscriptions/gifts/redeem',
|
'/wallet/subscriptions/gifts/redeem',
|
||||||
data: {'gift_code': giftCode},
|
data: {'gift_code': giftCode},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1384,7 +1384,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
await client.post('/pass/subscriptions/gifts/${gift.id}/cancel');
|
await client.post('/wallet/subscriptions/gifts/${gift.id}/cancel');
|
||||||
ref.invalidate(accountSentGiftsProvider);
|
ref.invalidate(accountSentGiftsProvider);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
hideLoadingModal(context);
|
hideLoadingModal(context);
|
||||||
|
|||||||
@@ -66,21 +66,20 @@ class PaymentOverlay extends HookConsumerWidget {
|
|||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
useSafeArea: true,
|
useSafeArea: true,
|
||||||
builder:
|
builder: (context) => PaymentOverlay(
|
||||||
(context) => PaymentOverlay(
|
order: order,
|
||||||
order: order,
|
enableBiometric: enableBiometric,
|
||||||
enableBiometric: enableBiometric,
|
onPaymentSuccess: (completedOrder) {
|
||||||
onPaymentSuccess: (completedOrder) {
|
Navigator.of(context).pop(completedOrder);
|
||||||
Navigator.of(context).pop(completedOrder);
|
},
|
||||||
},
|
onPaymentError: (err) {
|
||||||
onPaymentError: (err) {
|
Navigator.of(context).pop();
|
||||||
Navigator.of(context).pop();
|
showErrorAlert(err);
|
||||||
showErrorAlert(err);
|
},
|
||||||
},
|
onCancel: () {
|
||||||
onCancel: () {
|
Navigator.of(context).pop();
|
||||||
Navigator.of(context).pop();
|
},
|
||||||
},
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,7 +240,7 @@ class _PaymentContentState extends ConsumerState<_PaymentContent> {
|
|||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final response = await client.post(
|
final response = await client.post(
|
||||||
'/pass/orders/${widget.order.id}/pay',
|
'/wallet/orders/${widget.order.id}/pay',
|
||||||
data: {'pin_code': pin},
|
data: {'pin_code': pin},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -415,46 +414,42 @@ class _PaymentContentState extends ConsumerState<_PaymentContent> {
|
|||||||
|
|
||||||
Widget _buildBiometricAuth() {
|
Widget _buildBiometricAuth() {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child:
|
child: Column(
|
||||||
Column(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
children: [
|
||||||
children: [
|
Icon(Symbols.fingerprint, size: 48),
|
||||||
Icon(Symbols.fingerprint, size: 48),
|
const Gap(16),
|
||||||
const Gap(16),
|
Text(
|
||||||
Text(
|
'useBiometricToConfirm'.tr(),
|
||||||
'useBiometricToConfirm'.tr(),
|
style: Theme.of(
|
||||||
style: Theme.of(
|
context,
|
||||||
context,
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500),
|
||||||
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500),
|
textAlign: TextAlign.center,
|
||||||
textAlign: TextAlign.center,
|
),
|
||||||
),
|
Text(
|
||||||
Text(
|
'The biometric data will only be processed on your device',
|
||||||
'The biometric data will only be processed on your device',
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
fontSize: 11,
|
||||||
fontSize: 11,
|
),
|
||||||
),
|
textAlign: TextAlign.center,
|
||||||
textAlign: TextAlign.center,
|
).opacity(0.75),
|
||||||
).opacity(0.75),
|
const Gap(28),
|
||||||
const Gap(28),
|
ElevatedButton.icon(
|
||||||
ElevatedButton.icon(
|
onPressed: _authenticateWithBiometric,
|
||||||
onPressed: _authenticateWithBiometric,
|
icon: const Icon(Symbols.fingerprint),
|
||||||
icon: const Icon(Symbols.fingerprint),
|
label: Text('authenticateNow'.tr()),
|
||||||
label: Text('authenticateNow'.tr()),
|
style: ElevatedButton.styleFrom(
|
||||||
style: ElevatedButton.styleFrom(
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
padding: const EdgeInsets.symmetric(
|
),
|
||||||
horizontal: 24,
|
),
|
||||||
vertical: 12,
|
TextButton(
|
||||||
),
|
onPressed: () => _fallbackToPinMode(null),
|
||||||
),
|
child: Text('usePinInstead'.tr()),
|
||||||
),
|
),
|
||||||
TextButton(
|
],
|
||||||
onPressed: () => _fallbackToPinMode(null),
|
).center(),
|
||||||
child: Text('usePinInstead'.tr()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).center(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ class ComposeFundSheet extends HookConsumerWidget {
|
|||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
|
|
||||||
final resp = await client.post(
|
final resp = await client.post(
|
||||||
'/pass/wallets/funds',
|
'/wallet/wallets/funds',
|
||||||
data: result,
|
data: result,
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: {'X-Noop': true},
|
headers: {'X-Noop': true},
|
||||||
@@ -253,7 +253,7 @@ class ComposeFundSheet extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final orderResp = await client.post(
|
final orderResp = await client.post(
|
||||||
'/pass/wallets/funds/${fund.id}/order',
|
'/wallet/wallets/funds/${fund.id}/order',
|
||||||
);
|
);
|
||||||
final order = SnWalletOrder.fromJson(
|
final order = SnWalletOrder.fromJson(
|
||||||
orderResp.data,
|
orderResp.data,
|
||||||
@@ -284,7 +284,7 @@ class ComposeFundSheet extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Return the created fund
|
// Return the created fund
|
||||||
final updatedResp = await client.get(
|
final updatedResp = await client.get(
|
||||||
'/pass/wallets/funds/${fund.id}',
|
'/wallet/wallets/funds/${fund.id}',
|
||||||
);
|
);
|
||||||
final updatedFund =
|
final updatedFund =
|
||||||
SnWalletFund.fromJson(
|
SnWalletFund.fromJson(
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ class PostAwardSheet extends HookConsumerWidget {
|
|||||||
final orderId = awardResponse.data['order_id'] as String;
|
final orderId = awardResponse.data['order_id'] as String;
|
||||||
|
|
||||||
// Fetch order details
|
// Fetch order details
|
||||||
final orderResponse = await client.get('/pass/orders/$orderId');
|
final orderResponse = await client.get('/wallet/orders/$orderId');
|
||||||
final order = SnWalletOrder.fromJson(orderResponse.data);
|
final order = SnWalletOrder.fromJson(orderResponse.data);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ part 'fund_envelope.g.dart';
|
|||||||
@riverpod
|
@riverpod
|
||||||
Future<SnWalletFund> walletFund(Ref ref, String fundId) async {
|
Future<SnWalletFund> walletFund(Ref ref, String fundId) async {
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
final resp = await apiClient.get('/pass/wallets/funds/$fundId');
|
final resp = await apiClient.get('/wallet/wallets/funds/$fundId');
|
||||||
return SnWalletFund.fromJson(resp.data);
|
return SnWalletFund.fromJson(resp.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,202 +36,181 @@ class FundEnvelopeWidget extends HookConsumerWidget {
|
|||||||
width: maxWidth,
|
width: maxWidth,
|
||||||
margin: margin ?? const EdgeInsets.symmetric(vertical: 8),
|
margin: margin ?? const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: fundAsync.when(
|
child: fundAsync.when(
|
||||||
loading:
|
loading: () => Card(
|
||||||
() => Card(
|
margin: EdgeInsets.zero,
|
||||||
margin: EdgeInsets.zero,
|
child: const Padding(
|
||||||
child: const Padding(
|
padding: EdgeInsets.all(16),
|
||||||
padding: EdgeInsets.all(16),
|
child: Center(child: CircularProgressIndicator()),
|
||||||
child: Center(child: CircularProgressIndicator()),
|
),
|
||||||
),
|
),
|
||||||
),
|
error: (error, stack) => Card(
|
||||||
error:
|
margin: EdgeInsets.zero,
|
||||||
(error, stack) => Card(
|
child: Padding(
|
||||||
margin: EdgeInsets.zero,
|
padding: const EdgeInsets.all(16),
|
||||||
child: Padding(
|
child: Column(
|
||||||
padding: const EdgeInsets.all(16),
|
children: [
|
||||||
child: Column(
|
Icon(
|
||||||
children: [
|
Icons.error_outline,
|
||||||
Icon(
|
color: Theme.of(context).colorScheme.error,
|
||||||
Icons.error_outline,
|
|
||||||
color: Theme.of(context).colorScheme.error,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
'fundEnvelopeLoadFailed'.tr(),
|
|
||||||
style: TextStyle(
|
|
||||||
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,
|
data: (fund) => Card(
|
||||||
clipBehavior: Clip.antiAlias,
|
margin: EdgeInsets.zero,
|
||||||
child: InkWell(
|
clipBehavior: Clip.antiAlias,
|
||||||
onTap: () => _showClaimDialog(context, ref, fund),
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(8),
|
onTap: () => _showClaimDialog(context, ref, fund),
|
||||||
child: Padding(
|
borderRadius: BorderRadius.circular(8),
|
||||||
padding: const EdgeInsets.all(16),
|
child: Padding(
|
||||||
child: Column(
|
padding: const EdgeInsets.all(16),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Fund title and status
|
||||||
|
Row(
|
||||||
children: [
|
children: [
|
||||||
// Fund title and status
|
Icon(
|
||||||
Row(
|
Icons.account_balance_wallet,
|
||||||
children: [
|
color: Theme.of(context).colorScheme.primary,
|
||||||
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),
|
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
|
// Amount information
|
||||||
Row(
|
Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Text(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
'${fund.totalAmount.toStringAsFixed(2)} ${fund.currency}',
|
||||||
children: [
|
style: Theme.of(context).textTheme.headlineSmall
|
||||||
Text(
|
?.copyWith(
|
||||||
'${fund.totalAmount.toStringAsFixed(2)} ${fund.currency}',
|
|
||||||
style: Theme.of(
|
|
||||||
context,
|
|
||||||
).textTheme.headlineSmall?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
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,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
style: Theme.of(context).textTheme.bodySmall
|
||||||
if (fund.remainingAmount != fund.totalAmount)
|
?.copyWith(
|
||||||
Text(
|
color: Theme.of(
|
||||||
'fundEnvelopeRemaining'.tr(
|
context,
|
||||||
args: [
|
).colorScheme.secondary,
|
||||||
fund.remainingAmount.toStringAsFixed(2),
|
|
||||||
fund.currency,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
style: Theme.of(
|
|
||||||
context,
|
|
||||||
).textTheme.bodySmall?.copyWith(
|
|
||||||
color:
|
|
||||||
Theme.of(context).colorScheme.secondary,
|
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'fundEnvelopeSplit'.tr(
|
'fundEnvelopeSplit'.tr(
|
||||||
args: [
|
args: [
|
||||||
fund.splitType == 0
|
fund.splitType == 0
|
||||||
? 'fundEnvelopeSplitEvenly'.tr()
|
? 'fundEnvelopeSplitEvenly'.tr()
|
||||||
: 'fundEnvelopeSplitRandomly'.tr(),
|
: 'fundEnvelopeSplitRandomly'.tr(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.bodySmall
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.bodySmall?.copyWith(
|
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall
|
.bodySmall
|
||||||
?.color
|
?.color
|
||||||
?.withOpacity(0.7),
|
?.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,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
// 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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -243,26 +222,25 @@ class FundEnvelopeWidget extends HookConsumerWidget {
|
|||||||
) {
|
) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (dialogContext) => FundClaimDialog(
|
||||||
(dialogContext) => FundClaimDialog(
|
fund: fund,
|
||||||
fund: fund,
|
onClaim: () async {
|
||||||
onClaim: () async {
|
try {
|
||||||
try {
|
final apiClient = ref.read(apiClientProvider);
|
||||||
final apiClient = ref.read(apiClientProvider);
|
await apiClient.post('/wallet/wallets/funds/${fund.id}/receive');
|
||||||
await apiClient.post('/pass/wallets/funds/${fund.id}/receive');
|
|
||||||
|
|
||||||
// Refresh the fund data after claiming
|
// Refresh the fund data after claiming
|
||||||
ref.invalidate(walletFundProvider(fund.id));
|
ref.invalidate(walletFundProvider(fund.id));
|
||||||
|
|
||||||
if (dialogContext.mounted) {
|
if (dialogContext.mounted) {
|
||||||
Navigator.of(dialogContext).pop();
|
Navigator.of(dialogContext).pop();
|
||||||
showSnackBar('fundEnvelopeClaimSuccess'.tr());
|
showSnackBar('fundEnvelopeClaimSuccess'.tr());
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showErrorAlert(e);
|
showErrorAlert(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,8 +321,9 @@ class FundEnvelopeWidget extends HookConsumerWidget {
|
|||||||
|
|
||||||
Widget _buildRecipientsOverview(BuildContext context, SnWalletFund fund) {
|
Widget _buildRecipientsOverview(BuildContext context, SnWalletFund fund) {
|
||||||
final claimedCount = fund.recipients.where((r) => r.isReceived).length;
|
final claimedCount = fund.recipients.where((r) => r.isReceived).length;
|
||||||
final totalCount =
|
final totalCount = fund.isOpen
|
||||||
fund.isOpen ? fund.amountOfSplits : fund.recipients.length;
|
? fund.amountOfSplits
|
||||||
|
: fund.recipients.length;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -362,8 +341,9 @@ class FundEnvelopeWidget extends HookConsumerWidget {
|
|||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
value: totalCount > 0 ? claimedCount / totalCount : 0,
|
value: totalCount > 0 ? claimedCount / totalCount : 0,
|
||||||
backgroundColor:
|
backgroundColor: Theme.of(
|
||||||
Theme.of(context).colorScheme.surfaceContainerHighest,
|
context,
|
||||||
|
).colorScheme.surfaceContainerHighest,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -436,15 +416,16 @@ class FundClaimDialog extends HookConsumerWidget {
|
|||||||
!isExpired && hasRemainingAmount && !hasUserClaimed && userAbleToClaim;
|
!isExpired && hasRemainingAmount && !hasUserClaimed && userAbleToClaim;
|
||||||
|
|
||||||
// Get claimed recipients for display
|
// Get claimed recipients for display
|
||||||
final claimedRecipients =
|
final claimedRecipients = fund.recipients
|
||||||
fund.recipients.where((r) => r.isReceived).toList();
|
.where((r) => r.isReceived)
|
||||||
final unclaimedRecipients =
|
.toList();
|
||||||
fund.recipients.where((r) => !r.isReceived).toList();
|
final unclaimedRecipients = fund.recipients
|
||||||
|
.where((r) => !r.isReceived)
|
||||||
|
.toList();
|
||||||
|
|
||||||
final remainingSplits =
|
final remainingSplits = fund.isOpen
|
||||||
fund.isOpen
|
? fund.amountOfSplits - claimedRecipients.length
|
||||||
? fund.amountOfSplits - claimedRecipients.length
|
: unclaimedRecipients.length;
|
||||||
: unclaimedRecipients.length;
|
|
||||||
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Row(
|
title: Row(
|
||||||
@@ -491,16 +472,14 @@ class FundClaimDialog extends HookConsumerWidget {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color:
|
color: fund.isOpen
|
||||||
fund.isOpen
|
? Colors.green.withOpacity(0.1)
|
||||||
? Colors.green.withOpacity(0.1)
|
: Colors.blue.withOpacity(0.1),
|
||||||
: Colors.blue.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color:
|
color: fund.isOpen
|
||||||
fund.isOpen
|
? Colors.green.withOpacity(0.3)
|
||||||
? Colors.green.withOpacity(0.3)
|
: Colors.blue.withOpacity(0.3),
|
||||||
: Colors.blue.withOpacity(0.3),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -535,13 +514,13 @@ class FundClaimDialog extends HookConsumerWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
recipient.recipientAccount?.nick ??
|
recipient.recipientAccount?.nick ??
|
||||||
'fundEnvelopeUnknownUser'.tr(),
|
'fundEnvelopeUnknownUser'.tr(),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.bodySmall
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.bodySmall?.copyWith(
|
decoration: TextDecoration.lineThrough,
|
||||||
decoration: TextDecoration.lineThrough,
|
color: Theme.of(
|
||||||
color:
|
context,
|
||||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
Reference in New Issue
Block a user