Fixes for PostHog
This commit is contained in:
@@ -27,6 +27,7 @@ import 'package:pweb/providers/wallets.dart';
|
||||
import 'package:pweb/providers/wallet_transactions.dart';
|
||||
import 'package:pweb/services/operations.dart';
|
||||
import 'package:pweb/services/payments/history.dart';
|
||||
import 'package:pweb/services/posthog.dart';
|
||||
import 'package:pweb/services/wallet_transactions.dart';
|
||||
import 'package:pweb/services/wallets.dart';
|
||||
|
||||
@@ -40,11 +41,9 @@ void _setupLogging() {
|
||||
}
|
||||
|
||||
void main() async {
|
||||
await Constants.initialize();
|
||||
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// await AmplitudeService.initialize();
|
||||
await Constants.initialize();
|
||||
await PosthogService.initialize();
|
||||
|
||||
|
||||
_setupLogging();
|
||||
@@ -57,7 +56,12 @@ void main() async {
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => LocaleProvider(null)),
|
||||
ChangeNotifierProxyProvider<LocaleProvider, AccountProvider>(
|
||||
create: (_) => AccountProvider(),
|
||||
create: (_) => AccountProvider(
|
||||
onAccountChanged: (account) {
|
||||
if (account == null) return Future<void>.value();
|
||||
return PosthogService.identify(account);
|
||||
},
|
||||
),
|
||||
update: (context, localeProvider, provider) => provider!..updateProvider(localeProvider),
|
||||
),
|
||||
ChangeNotifierProxyProvider<AccountProvider, TwoFactorProvider>(
|
||||
@@ -70,6 +74,7 @@ void main() async {
|
||||
update: (context, orgnization, provider) => provider!..update(orgnization),
|
||||
),
|
||||
ChangeNotifierProvider(create: (_) => CarouselIndexProvider()),
|
||||
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => UploadHistoryProvider(service: MockUploadHistoryService())..load(),
|
||||
),
|
||||
@@ -91,6 +96,7 @@ void main() async {
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => MockPaymentProvider(),
|
||||
),
|
||||
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => OperationProvider(OperationService())..loadOperations(),
|
||||
),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
@@ -14,6 +16,7 @@ import 'package:pshared/provider/recipient/pmethods.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
|
||||
import 'package:pweb/pages/address_book/form/view.dart';
|
||||
import 'package:pweb/services/posthog.dart';
|
||||
import 'package:pweb/utils/error/snackbar.dart';
|
||||
import 'package:pweb/utils/payment/label.dart';
|
||||
import 'package:pweb/utils/snackbar.dart';
|
||||
@@ -106,11 +109,11 @@ class _AdressBookRecipientFormState extends State<AdressBookRecipientForm> {
|
||||
return;
|
||||
}
|
||||
|
||||
// AmplitudeService.recipientAddCompleted(
|
||||
// _type,
|
||||
// _status,
|
||||
// _methods.keys.toSet(),
|
||||
// );
|
||||
unawaited(PosthogService.recipientAddCompleted(
|
||||
_type,
|
||||
_status,
|
||||
_methods.keys.toSet(),
|
||||
));
|
||||
final recipient = await executeActionWithNotification(
|
||||
context: context,
|
||||
action: _doSave,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
@@ -10,26 +11,50 @@ import 'package:pweb/widgets/error/snackbar.dart';
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class AccountLoader extends StatelessWidget {
|
||||
class AccountLoader extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const AccountLoader({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Consumer<AccountProvider>(builder: (context, provider, _) {
|
||||
if (provider.isLoading) return const Center(child: CircularProgressIndicator());
|
||||
if (provider.error != null) {
|
||||
postNotifyUserOfErrorX(
|
||||
context: context,
|
||||
errorSituation: AppLocalizations.of(context)!.errorLogin,
|
||||
exception: provider.error!,
|
||||
);
|
||||
navigateAndReplace(context, Pages.login);
|
||||
}
|
||||
if (provider.account == null) {
|
||||
State<AccountLoader> createState() => _AccountLoaderState();
|
||||
}
|
||||
|
||||
class _AccountLoaderState extends State<AccountLoader> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final provider = Provider.of<AccountProvider>(context, listen: false);
|
||||
if (provider.account == null) {
|
||||
provider.restoreIfPossible().catchError((error, stack) {
|
||||
Logger('Account restore failed: $error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<AccountProvider>(builder: (context, provider, _) {
|
||||
if (provider.account != null) {
|
||||
return widget.child;
|
||||
}
|
||||
|
||||
if (provider.error != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
postNotifyUserOfErrorX(
|
||||
context: context,
|
||||
errorSituation: AppLocalizations.of(context)!.errorLogin,
|
||||
exception: provider.error!,
|
||||
);
|
||||
navigateAndReplace(context, Pages.login);
|
||||
});
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (provider.isLoading) return const Center(child: CircularProgressIndicator());
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => navigateAndReplace(context, Pages.login));
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return child;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,20 +21,29 @@ class PermissionsLoader extends StatelessWidget {
|
||||
if (provider.isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (provider.error != null) {
|
||||
postNotifyUserOfErrorX(
|
||||
context: context,
|
||||
errorSituation: AppLocalizations.of(context)!.errorLogin,
|
||||
exception: provider.error!,
|
||||
);
|
||||
navigateAndReplace(context, Pages.login);
|
||||
if (provider.hasUnhandledError) {
|
||||
provider.markErrorHandled();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
postNotifyUserOfErrorX(
|
||||
context: context,
|
||||
errorSituation: AppLocalizations.of(context)!.errorLogin,
|
||||
exception: provider.error!,
|
||||
);
|
||||
navigateAndReplace(context, Pages.login);
|
||||
});
|
||||
}
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (provider.error == null && !provider.isReady && accountProvider.account != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
provider.load();
|
||||
});
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
return child;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -14,6 +16,7 @@ import 'package:pweb/widgets/password/password.dart';
|
||||
import 'package:pweb/widgets/username.dart';
|
||||
import 'package:pweb/widgets/vspacer.dart';
|
||||
import 'package:pweb/widgets/error/snackbar.dart';
|
||||
import 'package:pweb/services/posthog.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
@@ -43,6 +46,7 @@ class _LoginFormState extends State<LoginForm> {
|
||||
password: _passwordController.text,
|
||||
locale: context.read<LocaleProvider>().locale.languageCode,
|
||||
);
|
||||
unawaited(PosthogService.login(pending: outcome.isPending));
|
||||
if (outcome.isPending) {
|
||||
// TODO: fix context usage
|
||||
navigateAndReplace(context, Pages.sfactor);
|
||||
|
||||
@@ -16,6 +16,7 @@ import 'package:pweb/providers/payment_flow.dart';
|
||||
import 'package:pweb/pages/payment_methods/payment_page/body.dart';
|
||||
import 'package:pweb/providers/wallets.dart';
|
||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||
import 'package:pweb/services/posthog.dart';
|
||||
|
||||
|
||||
class PaymentPage extends StatefulWidget {
|
||||
@@ -109,7 +110,7 @@ class _PaymentPageState extends State<PaymentPage> {
|
||||
|
||||
void _handleSendPayment() {
|
||||
// TODO: Handle Payment logic
|
||||
// AmplitudeService.paymentInitiated();
|
||||
PosthogService.paymentInitiated(method: _flowProvider.selectedType);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -195,4 +196,4 @@ class _PaymentPageState extends State<PaymentPage> {
|
||||
(method.description?.contains(wallet.walletUserID) ?? false),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/provider/locale.dart';
|
||||
|
||||
// import 'package:pweb/services/amplitude.dart';
|
||||
import 'package:pweb/services/posthog.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
@@ -58,7 +58,7 @@ class LocalePicker extends StatelessWidget {
|
||||
onChanged: (locale) {
|
||||
if (locale != null) {
|
||||
localeProvider.setLocale(locale);
|
||||
// AmplitudeService.localeChanged(locale);
|
||||
PosthogService.localeChanged(locale);
|
||||
}
|
||||
},
|
||||
decoration: const InputDecoration(
|
||||
|
||||
136
frontend/pweb/lib/services/posthog.dart
Normal file
136
frontend/pweb/lib/services/posthog.dart
Normal file
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:posthog_flutter/posthog_flutter.dart';
|
||||
|
||||
import 'package:pshared/config/constants.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 PosthogService {
|
||||
static final _logger = Logger('service.posthog');
|
||||
static String? _identifiedUserId;
|
||||
static bool _initialized = false;
|
||||
|
||||
static bool get isEnabled => _initialized;
|
||||
|
||||
static Future<void> initialize() async {
|
||||
final apiKey = Constants.posthogApiKey;
|
||||
if (apiKey.isEmpty) {
|
||||
_logger.warning('PostHog API key is not configured, analytics disabled.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final config = PostHogConfig(apiKey)
|
||||
..host = Constants.posthogHost
|
||||
..captureApplicationLifecycleEvents = true;
|
||||
await Posthog().setup(config);
|
||||
await Posthog().register('client_id', Constants.clientId);
|
||||
_initialized = true;
|
||||
_logger.info('PostHog initialized with host ${Constants.posthogHost}');
|
||||
} catch (e, st) {
|
||||
_initialized = false;
|
||||
_logger.warning('Failed to initialize PostHog: $e', e, st);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> identify(Account account) async {
|
||||
if (!_initialized) return;
|
||||
if (_identifiedUserId == account.id) return;
|
||||
|
||||
await Posthog().identify(
|
||||
userId: account.id,
|
||||
userProperties: {
|
||||
'email': account.login,
|
||||
'name': account.name,
|
||||
'locale': account.locale,
|
||||
'created_at': account.createdAt.toIso8601String(),
|
||||
},
|
||||
);
|
||||
_identifiedUserId = account.id;
|
||||
}
|
||||
|
||||
static Future<void> reset() async {
|
||||
if (!_initialized) return;
|
||||
_identifiedUserId = null;
|
||||
await Posthog().reset();
|
||||
}
|
||||
|
||||
static Future<void> login({required bool pending}) async {
|
||||
if (!_initialized) return;
|
||||
await _capture(
|
||||
'login',
|
||||
properties: {
|
||||
'result': pending ? 'pending' : 'success',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> pageOpened(PayoutDestination page, {String? path, String? uiSource}) async {
|
||||
if (!_initialized) return;
|
||||
return _capture(
|
||||
'pageOpened',
|
||||
properties: {
|
||||
'page': page.name,
|
||||
if (path != null) 'path': path,
|
||||
if (uiSource != null) 'uiSource': uiSource,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> localeChanged(Locale locale) async {
|
||||
if (!_initialized) return;
|
||||
return _capture(
|
||||
'localeChanged',
|
||||
properties: {'locale': locale.toLanguageTag()},
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> recipientAddCompleted(
|
||||
RecipientType type,
|
||||
RecipientStatus status,
|
||||
Set<PaymentType> methods,
|
||||
) async {
|
||||
if (!_initialized) return;
|
||||
return _capture(
|
||||
'recipientAddCompleted',
|
||||
properties: {
|
||||
'methods': methods.map((m) => m.name).toList(),
|
||||
'type': type.name,
|
||||
'status': status.name,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> paymentInitiated({PaymentType? method}) async {
|
||||
if (!_initialized) return;
|
||||
return _capture(
|
||||
'paymentInitiated',
|
||||
properties: {
|
||||
if (method != null) 'method': method.name,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _capture(
|
||||
String eventName, {
|
||||
Map<String, Object?>? properties,
|
||||
}) async {
|
||||
if (!_initialized) return;
|
||||
final filtered = <String, Object>{};
|
||||
if (properties != null) {
|
||||
for (final entry in properties.entries) {
|
||||
final value = entry.value;
|
||||
if (value != null) filtered[entry.key] = value;
|
||||
}
|
||||
}
|
||||
await Posthog().capture(eventName: eventName, properties: filtered.isEmpty ? null : filtered);
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,12 @@ import 'package:pshared/provider/account.dart';
|
||||
import 'package:pshared/provider/permissions.dart';
|
||||
|
||||
import 'package:pweb/app/router/pages.dart';
|
||||
import 'package:pweb/services/posthog.dart';
|
||||
|
||||
|
||||
void logoutUtil(BuildContext context) {
|
||||
context.read<AccountProvider>().logout();
|
||||
context.read<PermissionsProvider>().reset();
|
||||
PosthogService.reset();
|
||||
navigateAndReplace(context, Pages.login);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// import 'package:pweb/services/amplitude.dart';
|
||||
import 'package:pweb/services/posthog.dart';
|
||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class SideMenuColumn extends StatelessWidget {
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
onSelected(item);
|
||||
// AmplitudeService.pageOpened(item, uiSource: 'sidebar');
|
||||
PosthogService.pageOpened(item, uiSource: 'sidebar');
|
||||
},
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
hoverColor: theme.colorScheme.primaryContainer,
|
||||
@@ -76,4 +76,4 @@ class SideMenuColumn extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import amplitude_flutter
|
||||
import file_selector_macos
|
||||
import flutter_timezone
|
||||
import path_provider_foundation
|
||||
import posthog_flutter
|
||||
import share_plus
|
||||
import shared_preferences_foundation
|
||||
import sqflite_darwin
|
||||
@@ -19,6 +20,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
PosthogFlutterPlugin.register(with: registry.registrar(forPlugin: "PosthogFlutterPlugin"))
|
||||
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
|
||||
@@ -35,6 +35,7 @@ dependencies:
|
||||
sdk: flutter
|
||||
pshared:
|
||||
path: ../pshared
|
||||
posthog_flutter: ^5.9.0
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
|
||||
Reference in New Issue
Block a user