Frontend first draft
This commit is contained in:
210
frontend/pweb/lib/services/amplitude.dart
Normal file
210
frontend/pweb/lib/services/amplitude.dart
Normal file
@@ -0,0 +1,210 @@
|
||||
import 'package:amplitude_flutter/amplitude.dart';
|
||||
import 'package:amplitude_flutter/configuration.dart';
|
||||
import 'package:amplitude_flutter/constants.dart' as amp;
|
||||
import 'package:amplitude_flutter/events/base_event.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:pshared/models/account/account.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
import 'package:pshared/models/recipient/status.dart';
|
||||
import 'package:pshared/models/recipient/type.dart';
|
||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||
|
||||
|
||||
class AmplitudeService {
|
||||
static late Amplitude _analytics;
|
||||
|
||||
static Amplitude _amp() => _analytics;
|
||||
|
||||
static Future<void> initialize() async {
|
||||
_analytics = Amplitude(Configuration(
|
||||
apiKey: '12345', //TODO define through App Contants
|
||||
serverZone: amp.ServerZone.eu, //TODO define through App Contants
|
||||
));
|
||||
await _analytics.isBuilt;
|
||||
}
|
||||
|
||||
static Future<void> identify(Account account) async =>
|
||||
_amp().setUserId(account.id);
|
||||
|
||||
|
||||
static Future<void> login(Account account) async =>
|
||||
_logEvent(
|
||||
'login',
|
||||
userProperties: {
|
||||
// 'email': account.email, TODO Add email into account
|
||||
'locale': account.locale,
|
||||
},
|
||||
);
|
||||
|
||||
static Future<void> logout() async => _logEvent("logout");
|
||||
|
||||
static Future<void> pageOpened(PayoutDestination page, {String? path, String? uiSource}) async {
|
||||
return _logEvent("pageOpened", eventProperties: {
|
||||
"page": page,
|
||||
if (path != null) "path": path,
|
||||
if (uiSource != null) "uiSource": uiSource,
|
||||
});
|
||||
}
|
||||
|
||||
//TODO Add when registration is ready. User properties {user_id, registration_date, has_wallet (true/false), wallet_balance (should concider loggin it as: 0 / <100 / 100–500 / 500+), preferred_method (Wallet/Card/Bank/IBAN), total_transactions, total_amount, last_payout_date, last_login_date , marketing_source}
|
||||
|
||||
// static Future<void> registrationStarted(String method, String country) async =>
|
||||
// _logEvent("registrationStarted", eventProperties: {"method": method, "country": country});
|
||||
|
||||
// static Future<void> registrationCompleted(String method, String country) async =>
|
||||
// _logEvent("registrationCompleted", eventProperties: {"method": method, "country": country});
|
||||
|
||||
static Future<void> pageNotFound(String url) async =>
|
||||
_logEvent("pageNotFound", eventProperties: {"url": url});
|
||||
|
||||
static Future<void> localeChanged(Locale locale) async =>
|
||||
_logEvent("localeChanged", eventProperties: {"locale": locale.toString()});
|
||||
|
||||
static Future<void> localeMatched(String locale, bool haveRequested) async => //DO we need it?
|
||||
_logEvent("localeMatched", eventProperties: {
|
||||
"locale": locale,
|
||||
"have_requested_locale": haveRequested
|
||||
});
|
||||
|
||||
static Future<void> recipientAddStarted() async =>
|
||||
_logEvent("recipientAddStarted");
|
||||
|
||||
static Future<void> recipientAddCompleted(
|
||||
RecipientType type,
|
||||
RecipientStatus status,
|
||||
Set<PaymentType> methods,
|
||||
) async {
|
||||
_logEvent(
|
||||
"recipientAddCompleted",
|
||||
eventProperties: {
|
||||
"methods": methods.map((m) => m.name).toList(),
|
||||
"type": type.name,
|
||||
"status": status.name,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _paymentEvent(
|
||||
String evt,
|
||||
double amount,
|
||||
double fee,
|
||||
bool payerCoversFee,
|
||||
PaymentType source,
|
||||
PaymentType recpientPaymentMethod, {
|
||||
String? message,
|
||||
String? errorType,
|
||||
Map<String, dynamic>? extraProps,
|
||||
}) async {
|
||||
final props = {
|
||||
"amount": amount,
|
||||
"fee": fee,
|
||||
"feeCoveredBy": payerCoversFee ? 'payer' : 'recipient',
|
||||
"source": source,
|
||||
"recipient_method": recpientPaymentMethod,
|
||||
if (message != null) "message": message,
|
||||
if (errorType != null) "error_type": errorType,
|
||||
if (extraProps != null) ...extraProps,
|
||||
};
|
||||
return _logEvent(evt, eventProperties: props);
|
||||
}
|
||||
|
||||
static Future<void> paymentPrepared(double amount, double fee,
|
||||
bool payerCoversFee, PaymentType source, PaymentType recpientPaymentMethod) async =>
|
||||
_paymentEvent("paymentPrepared", amount, fee, payerCoversFee, source, recpientPaymentMethod);
|
||||
//TODO Rework paymentStarted (do i need all those properties or is the event enough? Mb properties should be passed at paymentPrepared)
|
||||
static Future<void> paymentStarted(double amount, double fee,
|
||||
bool payerCoversFee, PaymentType source, PaymentType recpientPaymentMethod) async =>
|
||||
_paymentEvent("paymentStarted", amount, fee, payerCoversFee, source, recpientPaymentMethod);
|
||||
|
||||
static Future<void> paymentFailed(double amount, double fee, bool payerCoversFee,
|
||||
PaymentType source, PaymentType recpientPaymentMethod, String errorType, String message) async =>
|
||||
_paymentEvent("paymentFailed", amount, fee, payerCoversFee, source, recpientPaymentMethod,
|
||||
errorType: errorType, message: message);
|
||||
|
||||
static Future<void> paymentError(double amount, double fee, bool payerCoversFee,
|
||||
PaymentType source,PaymentType recpientPaymentMethod, String message) async =>
|
||||
_paymentEvent("paymentError", amount, fee, payerCoversFee, source, recpientPaymentMethod,
|
||||
message: message);
|
||||
|
||||
static Future<void> paymentSuccess({
|
||||
required double amount,
|
||||
required double fee,
|
||||
required bool payerCoversFee,
|
||||
required PaymentType source,
|
||||
required PaymentType recpientPaymentMethod,
|
||||
required String transactionId,
|
||||
String? comment,
|
||||
required int durationMs,
|
||||
}) async {
|
||||
return _paymentEvent(
|
||||
"paymentSuccess",
|
||||
amount,
|
||||
fee,
|
||||
payerCoversFee,
|
||||
source,
|
||||
recpientPaymentMethod,
|
||||
message: comment,
|
||||
extraProps: {
|
||||
"transaction_id": transactionId,
|
||||
"duration_ms": durationMs, //How do i calculate duration here?
|
||||
"\$revenue": amount, //How do i calculate revenue here?
|
||||
"\$revenueType": "payment", //Do we need to get revenue type?
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
//TODO add when support is ready
|
||||
// static Future<void> supportOpened(String fromPage, String trigger) async =>
|
||||
// _logEvent("supportOpened", eventProperties: {"from_page": fromPage, "trigger": trigger});
|
||||
|
||||
// static Future<void> supportMessageSent(String category, bool resolved) async =>
|
||||
// _logEvent("supportMessageSent", eventProperties: {"category": category, "resolved": resolved});
|
||||
|
||||
|
||||
static Future<void> walletTopUp(double amount, PaymentType method) async =>
|
||||
_logEvent("walletTopUp", eventProperties: {"amount": amount, "method": method});
|
||||
|
||||
|
||||
//TODO Decide do we need uiElementClicked or pageOpened is enough?
|
||||
static Future<void> uiElementClicked(String elementName, String page, String uiSource) async =>
|
||||
_logEvent("uiElementClicked", eventProperties: {
|
||||
"element_name": elementName,
|
||||
"page": page,
|
||||
"uiSource": uiSource
|
||||
});
|
||||
|
||||
static final Map<String, int> _stepStartTimes = {};
|
||||
//TODO Consider it as part of payment flow or registration flow or adding recipient and rework accordingly
|
||||
static Future<void> stepStarted(String stepName, {String? context}) async {
|
||||
_stepStartTimes[stepName] = DateTime.now().millisecondsSinceEpoch;
|
||||
return _logEvent("stepStarted", eventProperties: {
|
||||
"step_name": stepName,
|
||||
if (context != null) "context": context,
|
||||
});
|
||||
}
|
||||
|
||||
static Future<void> stepCompleted(String stepName, bool success) async {
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
final start = _stepStartTimes[stepName] ?? now;
|
||||
final duration = now - start;
|
||||
return _logEvent("stepCompleted", eventProperties: {
|
||||
"step_name": stepName,
|
||||
"duration_ms": duration,
|
||||
"success": success
|
||||
});
|
||||
}
|
||||
|
||||
static Future<void> _logEvent(
|
||||
String eventType, {
|
||||
Map<String, dynamic>? eventProperties,
|
||||
Map<String, dynamic>? userProperties,
|
||||
}) async {
|
||||
final event = BaseEvent(
|
||||
eventType,
|
||||
eventProperties: eventProperties,
|
||||
userProperties: userProperties,
|
||||
);
|
||||
_amp().track(event);
|
||||
print(event.toString()); //TODO delete when everything is ready
|
||||
}
|
||||
}
|
||||
12
frontend/pweb/lib/services/auth.dart
Normal file
12
frontend/pweb/lib/services/auth.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
class AuthenticationService {
|
||||
Future<bool> verifyTwoFactorCode(String code) async {
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
|
||||
if (code == '000000') {
|
||||
return true;
|
||||
} else {
|
||||
throw Exception('Wrong Code'); //TODO Localize
|
||||
}
|
||||
}
|
||||
}
|
||||
22
frontend/pweb/lib/services/balance.dart
Normal file
22
frontend/pweb/lib/services/balance.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
abstract class BalanceService {
|
||||
Future<double> getBalance();
|
||||
Future<String> getWalletName();
|
||||
Future<String> getWalletId();
|
||||
}
|
||||
|
||||
class MockBalanceService implements BalanceService {
|
||||
@override
|
||||
Future<double> getBalance() async {
|
||||
return 3000000.56;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getWalletName() async {
|
||||
return "Wallet";
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getWalletId() async {
|
||||
return "WA-12345667";
|
||||
}
|
||||
}
|
||||
42
frontend/pweb/lib/services/payments/payment_methods.dart
Normal file
42
frontend/pweb/lib/services/payments/payment_methods.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'package:pshared/models/payment/methods/type.dart';
|
||||
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
abstract class PaymentMethodsService {
|
||||
Future<List<PaymentMethod>> fetchMethods();
|
||||
}
|
||||
|
||||
class MockPaymentMethodsService implements PaymentMethodsService {
|
||||
@override
|
||||
Future<List<PaymentMethod>> fetchMethods() async {
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
return [
|
||||
PaymentMethod(
|
||||
id: '1',
|
||||
label: 'My account',
|
||||
details: '•••4567',
|
||||
type: PaymentType.bankAccount,
|
||||
isMain: true,
|
||||
),
|
||||
PaymentMethod(
|
||||
id: '2',
|
||||
label: 'Euro IBAN',
|
||||
details: 'DE•• •••8901',
|
||||
type: PaymentType.iban,
|
||||
),
|
||||
PaymentMethod(
|
||||
id: '3',
|
||||
label: 'Wallet',
|
||||
details: 'WA‑12345667',
|
||||
type: PaymentType.wallet,
|
||||
),
|
||||
PaymentMethod(
|
||||
id: '4',
|
||||
label: 'Credit Card',
|
||||
details: '21•• •••• •••• 8901',
|
||||
type: PaymentType.card,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
20
frontend/pweb/lib/services/payments/upload_history.dart
Normal file
20
frontend/pweb/lib/services/payments/upload_history.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:pshared/models/payment/upload_history_item.dart';
|
||||
|
||||
|
||||
abstract class UploadHistoryService {
|
||||
Future<List<UploadHistoryItem>> fetchHistory();
|
||||
}
|
||||
|
||||
class MockUploadHistoryService implements UploadHistoryService {
|
||||
@override
|
||||
Future<List<UploadHistoryItem>> fetchHistory() async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
return [
|
||||
UploadHistoryItem(name: "cards_payout_single.csv", status: "Valid", time: "5 hours ago"),
|
||||
UploadHistoryItem(name: "rfba_norm.csv", status: "Valid", time: "Yesterday"),
|
||||
UploadHistoryItem(name: "iban (4).csv", status: "Valid", time: "Yesterday"),
|
||||
UploadHistoryItem(name: "rfba_wrong.csv", status: "Error", time: "2 days ago"),
|
||||
];
|
||||
}
|
||||
}
|
||||
88
frontend/pweb/lib/services/recipient/recipient.dart
Normal file
88
frontend/pweb/lib/services/recipient/recipient.dart
Normal file
@@ -0,0 +1,88 @@
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pshared/models/payment/methods/card.dart';
|
||||
import 'package:pshared/models/payment/methods/iban.dart';
|
||||
import 'package:pshared/models/payment/methods/russian_bank.dart';
|
||||
import 'package:pshared/models/payment/methods/wallet.dart';
|
||||
import 'package:pshared/models/recipient/status.dart';
|
||||
import 'package:pshared/models/recipient/type.dart';
|
||||
|
||||
|
||||
class RecipientService {
|
||||
Future<List<Recipient>> fetchRecipients() async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return RecipientMockData.all;
|
||||
}
|
||||
}
|
||||
|
||||
class RecipientMockData {
|
||||
static List<Recipient> get all => [
|
||||
Recipient.mock(
|
||||
name: 'Alice Johnson',
|
||||
email: 'alice@example.com',
|
||||
status: RecipientStatus.ready,
|
||||
type: RecipientType.internal,
|
||||
card: CardPaymentMethod(
|
||||
pan: '1213',
|
||||
firstName: 'Alice',
|
||||
lastName: 'Johnson',
|
||||
),
|
||||
),
|
||||
Recipient.mock(
|
||||
name: 'Bob & Co Ltd.',
|
||||
email: 'payout@bobco.com',
|
||||
status: RecipientStatus.registered,
|
||||
type: RecipientType.external,
|
||||
card: CardPaymentMethod(
|
||||
pan: '4343',
|
||||
firstName: 'Bob',
|
||||
lastName: 'Co',
|
||||
),
|
||||
iban: IbanPaymentMethod(
|
||||
iban: 'FR7630***890189',
|
||||
accountHolder: 'Bob & Co Ltd.',
|
||||
bic: 'AGRIFRPP',
|
||||
bankName: 'Credit Agricole',
|
||||
),
|
||||
wallet: WalletPaymentMethod(walletId: '8932231'),
|
||||
),
|
||||
Recipient.mock(
|
||||
name: 'Carlos Kline',
|
||||
email: 'carlos@acme.org',
|
||||
status: RecipientStatus.notRegistered,
|
||||
type: RecipientType.internal,
|
||||
wallet: WalletPaymentMethod(walletId: '7723490'),
|
||||
),
|
||||
Recipient.mock(
|
||||
name: 'Delta Outsourcing GmbH',
|
||||
email: 'finance@delta-os.de',
|
||||
status: RecipientStatus.registered,
|
||||
type: RecipientType.external,
|
||||
card: CardPaymentMethod(
|
||||
pan: '9988',
|
||||
firstName: 'Delta',
|
||||
lastName: 'GmbH',
|
||||
),
|
||||
iban: IbanPaymentMethod(
|
||||
iban: 'DE4450***324931',
|
||||
accountHolder: 'Delta Outsourcing GmbH',
|
||||
bic: 'INGDDEFFXXX',
|
||||
bankName: 'ING',
|
||||
),
|
||||
),
|
||||
Recipient.mock(
|
||||
name: 'Erin Patel',
|
||||
email: 'erin@labster.io',
|
||||
status: RecipientStatus.ready,
|
||||
type: RecipientType.internal,
|
||||
bank: RussianBankAccountPaymentMethod(
|
||||
accountNumber: '4081***7654',
|
||||
recipientName: 'Erin Patel',
|
||||
inn: '7812012345',
|
||||
kpp: '781201001',
|
||||
bankName: 'Alfa-Bank',
|
||||
bik: '044525593',
|
||||
correspondentAccount: '30101810200000000593',
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
41
frontend/pweb/lib/services/wallets.dart
Normal file
41
frontend/pweb/lib/services/wallets.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:pweb/models/currency.dart';
|
||||
import 'package:pweb/models/wallet.dart';
|
||||
|
||||
|
||||
abstract class WalletsService {
|
||||
Future<List<Wallet>> getWallets();
|
||||
Future<List<Wallet>> updateWallet();
|
||||
Future<List<Wallet>> createWallet();
|
||||
Future<List<Wallet>> deleteWallet();
|
||||
|
||||
Future<Wallet> getWallet(String walletRef);
|
||||
}
|
||||
|
||||
class MockWalletsService implements WalletsService {
|
||||
final List<Wallet> _wallets = [
|
||||
Wallet(id: '1124', walletUserID: 'WA-12345667', name: 'Main Wallet', balance: 10000000.0, currency: Currency.rub),
|
||||
Wallet(id: '2124', walletUserID: 'WA-76654321', name: 'Savings', balance: 2500.5, currency: Currency.usd),
|
||||
];
|
||||
|
||||
@override
|
||||
Future<List<Wallet>> getWallets() async {
|
||||
return _wallets;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Wallet> getWallet(String walletId) async {
|
||||
return _wallets.firstWhere(
|
||||
(wallet) => wallet.id == walletId,
|
||||
orElse: () => throw Exception('Wallet not found'),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Wallet>> updateWallet() async => [];
|
||||
|
||||
@override
|
||||
Future<List<Wallet>> createWallet() async => [];
|
||||
|
||||
@override
|
||||
Future<List<Wallet>> deleteWallet() async => [];
|
||||
}
|
||||
Reference in New Issue
Block a user