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 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 identify(Account account) async => _amp().setUserId(account.id); static Future login(Account account) async => _logEvent( 'login', userProperties: { // 'email': account.email, TODO Add email into account 'locale': account.locale, }, ); static Future logout() async => _logEvent("logout"); static Future 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 registrationStarted(String method, String country) async => // _logEvent("registrationStarted", eventProperties: {"method": method, "country": country}); // static Future registrationCompleted(String method, String country) async => // _logEvent("registrationCompleted", eventProperties: {"method": method, "country": country}); static Future pageNotFound(String url) async => _logEvent("pageNotFound", eventProperties: {"url": url}); static Future localeChanged(Locale locale) async => _logEvent("localeChanged", eventProperties: {"locale": locale.toString()}); static Future localeMatched(String locale, bool haveRequested) async => //DO we need it? _logEvent("localeMatched", eventProperties: { "locale": locale, "have_requested_locale": haveRequested }); static Future recipientAddStarted() async => _logEvent("recipientAddStarted"); static Future recipientAddCompleted( RecipientType type, RecipientStatus status, Set methods, ) async { _logEvent( "recipientAddCompleted", eventProperties: { "methods": methods.map((m) => m.name).toList(), "type": type.name, "status": status.name, }, ); } static Future _paymentEvent( String evt, double amount, double fee, bool payerCoversFee, PaymentType source, PaymentType recpientPaymentMethod, { String? message, String? errorType, Map? 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 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 paymentStarted(double amount, double fee, bool payerCoversFee, PaymentType source, PaymentType recpientPaymentMethod) async => _paymentEvent("paymentStarted", amount, fee, payerCoversFee, source, recpientPaymentMethod); static Future 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 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 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 supportOpened(String fromPage, String trigger) async => // _logEvent("supportOpened", eventProperties: {"from_page": fromPage, "trigger": trigger}); // static Future supportMessageSent(String category, bool resolved) async => // _logEvent("supportMessageSent", eventProperties: {"category": category, "resolved": resolved}); static Future 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 uiElementClicked(String elementName, String page, String uiSource) async => _logEvent("uiElementClicked", eventProperties: { "element_name": elementName, "page": page, "uiSource": uiSource }); static final Map _stepStartTimes = {}; //TODO Consider it as part of payment flow or registration flow or adding recipient and rework accordingly static Future 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 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 _logEvent( String eventType, { Map? eventProperties, Map? userProperties, }) async { final event = BaseEvent( eventType, eventProperties: eventProperties, userProperties: userProperties, ); _amp().track(event); print(event.toString()); //TODO delete when everything is ready } }