Merge pull request 'PostHog last fixes hopefully' (#109) from SEND006 into main
All checks were successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
All checks were successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #109
This commit was merged in pull request #109.
This commit is contained in:
@@ -11,6 +11,8 @@ class CommonConstants {
|
||||
static String apiEndpoint = '/api/v1';
|
||||
static String amplitudeSecret = 'c3d75b3e2520d708440acbb16b923e79';
|
||||
static String amplitudeServerZone = 'EU';
|
||||
static String posthogApiKey = 'phc_lVhbruaZpxiQxppHBJpL36ARnPlkqbCewv6cauoceTN';
|
||||
static String posthogHost = 'https://eu.i.posthog.com';
|
||||
static Locale defaultLocale = const Locale('en');
|
||||
static String defaultCurrency = 'EUR';
|
||||
static int defaultDimensionLength = 500;
|
||||
@@ -36,6 +38,8 @@ class CommonConstants {
|
||||
apiEndpoint = configJson['apiEndpoint'] ?? apiEndpoint;
|
||||
amplitudeSecret = configJson['amplitudeSecret'] ?? amplitudeSecret;
|
||||
amplitudeServerZone = configJson['amplitudeServerZone'] ?? amplitudeServerZone;
|
||||
posthogApiKey = configJson['posthogApiKey'] ?? posthogApiKey;
|
||||
posthogHost = configJson['posthogHost'] ?? posthogHost;
|
||||
defaultLocale = Locale(configJson['defaultLocale'] ?? defaultLocale.languageCode);
|
||||
defaultCurrency = configJson['defaultCurrency'] ?? defaultCurrency;
|
||||
wsProto = configJson['wsProto'] ?? wsProto;
|
||||
|
||||
@@ -15,6 +15,8 @@ class Constants extends CommonConstants {
|
||||
static String get currentOrgKey => CommonConstants.currentOrgKey;
|
||||
static String get apiUrl => CommonConstants.apiUrl;
|
||||
static String get serviceUrl => CommonConstants.serviceUrl;
|
||||
static String get posthogApiKey => CommonConstants.posthogApiKey;
|
||||
static String get posthogHost => CommonConstants.posthogHost;
|
||||
static int get defaultDimensionLength => CommonConstants.defaultDimensionLength;
|
||||
static String get deviceIdStorageKey => CommonConstants.deviceIdStorageKey;
|
||||
static String get nilObjectRef => CommonConstants.nilObjectRef;
|
||||
|
||||
@@ -21,6 +21,8 @@ extension AppConfigExtension on AppConfig {
|
||||
external String? get apiEndpoint;
|
||||
external String? get amplitudeSecret;
|
||||
external String? get amplitudeServerZone;
|
||||
external String? get posthogApiKey;
|
||||
external String? get posthogHost;
|
||||
external String? get defaultLocale;
|
||||
external String? get wsProto;
|
||||
external String? get wsEndpoint;
|
||||
@@ -40,6 +42,8 @@ class Constants extends CommonConstants {
|
||||
static String get currentOrgKey => CommonConstants.currentOrgKey;
|
||||
static String get apiUrl => CommonConstants.apiUrl;
|
||||
static String get serviceUrl => CommonConstants.serviceUrl;
|
||||
static String get posthogApiKey => CommonConstants.posthogApiKey;
|
||||
static String get posthogHost => CommonConstants.posthogHost;
|
||||
static int get defaultDimensionLength => CommonConstants.defaultDimensionLength;
|
||||
static String get deviceIdStorageKey => CommonConstants.deviceIdStorageKey;
|
||||
static String get nilObjectRef => CommonConstants.nilObjectRef;
|
||||
@@ -57,6 +61,8 @@ class Constants extends CommonConstants {
|
||||
'apiEndpoint': config.apiEndpoint,
|
||||
'amplitudeSecret': config.amplitudeSecret,
|
||||
'amplitudeServerZone': config.amplitudeServerZone,
|
||||
'posthogApiKey': config.posthogApiKey,
|
||||
'posthogHost': config.posthogHost,
|
||||
'defaultLocale': config.defaultLocale,
|
||||
'wsProto': config.wsProto,
|
||||
'wsEndpoint': config.wsEndpoint,
|
||||
|
||||
7
frontend/pshared/lib/models/auth/state.dart
Normal file
7
frontend/pshared/lib/models/auth/state.dart
Normal file
@@ -0,0 +1,7 @@
|
||||
enum AuthState {
|
||||
idle,
|
||||
checking,
|
||||
ready,
|
||||
empty,
|
||||
error,
|
||||
}
|
||||
@@ -79,12 +79,13 @@ enum ResourceType {
|
||||
@JsonValue('payments')
|
||||
payments,
|
||||
|
||||
@JsonValue('payment_methods')
|
||||
paymentMethods,
|
||||
|
||||
/// Represents payment orchestration service
|
||||
@JsonValue('payment_orchestrator')
|
||||
paymentOrchestrator,
|
||||
|
||||
@JsonValue('payment_methods')
|
||||
paymentMethods,
|
||||
|
||||
/// Represents permissions service
|
||||
@JsonValue('permissions')
|
||||
permissions,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pshared/models/auth/state.dart';
|
||||
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
@@ -20,8 +23,14 @@ import 'package:pshared/utils/exception.dart';
|
||||
|
||||
|
||||
class AccountProvider extends ChangeNotifier {
|
||||
AccountProvider();
|
||||
|
||||
static String get currentUserRef => Constants.nilObjectRef;
|
||||
|
||||
/// Auth lifecycle state to avoid multiple ad-hoc flags.
|
||||
AuthState _authState = AuthState.idle;
|
||||
AuthState get authState => _authState;
|
||||
|
||||
// The resource now wraps our Account? state along with its loading/error state.
|
||||
Resource<Account?> _resource = Resource(data: null);
|
||||
Resource<Account?> get resource => _resource;
|
||||
@@ -52,9 +61,18 @@ class AccountProvider extends ChangeNotifier {
|
||||
);
|
||||
}
|
||||
|
||||
// Private helper to update the resource and notify listeners.
|
||||
@protected
|
||||
Future<void> onAccountChanged(Account? previous, Account? current) => Future<void>.value();
|
||||
|
||||
void _setResource(Resource<Account?> newResource) {
|
||||
final previousAccount = _resource.data;
|
||||
_resource = newResource;
|
||||
final currentAccount = newResource.data;
|
||||
|
||||
if (previousAccount != currentAccount) {
|
||||
unawaited(onAccountChanged(previousAccount, currentAccount));
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -75,6 +93,7 @@ class AccountProvider extends ChangeNotifier {
|
||||
locale: locale,
|
||||
));
|
||||
if (outcome.account != null) {
|
||||
_authState = AuthState.ready;
|
||||
_setResource(Resource(data: outcome.account, isLoading: false));
|
||||
_pickupLocale(outcome.account!.locale);
|
||||
} else {
|
||||
@@ -84,10 +103,12 @@ class AccountProvider extends ChangeNotifier {
|
||||
}
|
||||
await VerificationService.requestLoginCode(pending);
|
||||
_pendingLogin = pending;
|
||||
_authState = AuthState.idle;
|
||||
_setResource(_resource.copyWith(isLoading: false));
|
||||
}
|
||||
return outcome;
|
||||
} catch (e) {
|
||||
_authState = AuthState.error;
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
@@ -95,6 +116,7 @@ class AccountProvider extends ChangeNotifier {
|
||||
|
||||
void completePendingLogin(Account account) {
|
||||
_pendingLogin = null;
|
||||
_authState = AuthState.ready;
|
||||
_setResource(Resource(data: account, isLoading: false, error: null));
|
||||
_pickupLocale(account.locale);
|
||||
}
|
||||
@@ -102,13 +124,17 @@ class AccountProvider extends ChangeNotifier {
|
||||
Future<bool> isAuthorizationStored() async => AuthorizationService.isAuthorizationStored();
|
||||
|
||||
Future<Account?> restore() async {
|
||||
_authState = AuthState.checking;
|
||||
notifyListeners();
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
final acc = await AccountService.restore();
|
||||
_authState = AuthState.ready;
|
||||
_setResource(Resource(data: acc, isLoading: false));
|
||||
_pickupLocale(acc.locale);
|
||||
return acc;
|
||||
} catch (e) {
|
||||
_authState = AuthState.error;
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
@@ -140,11 +166,14 @@ class AccountProvider extends ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
_authState = AuthState.empty;
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
_pendingLogin = null;
|
||||
try {
|
||||
await AccountService.logout();
|
||||
_setResource(Resource(data: null, isLoading: false));
|
||||
} catch (e) {
|
||||
_authState = AuthState.error;
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
@@ -220,4 +249,15 @@ class AccountProvider extends ChangeNotifier {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> restoreIfPossible() async {
|
||||
if (_authState == AuthState.checking || _authState == AuthState.ready) return;
|
||||
final hasAuth = await AuthorizationService.isAuthorizationStored();
|
||||
if (!hasAuth) {
|
||||
_authState = AuthState.empty;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
await restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,4 +80,12 @@ class OrganizationsProvider extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> reset() async {
|
||||
_resource = Resource(data: []);
|
||||
_currentOrg = null;
|
||||
notifyListeners();
|
||||
// Best-effort cleanup of stored selection to avoid using stale org on next login.
|
||||
await SecureStorageService.delete(Constants.currentOrgKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
@@ -21,9 +23,17 @@ class PermissionsProvider extends ChangeNotifier {
|
||||
Resource<UserAccess> _userAccess = Resource(data: null, isLoading: false, error: null);
|
||||
late OrganizationsProvider _organizations;
|
||||
bool _isLoaded = false;
|
||||
String? _loadedOrgRef;
|
||||
//For permissions to auto-load when an organization is set, so the dashboard no longer hangs waiting for permissions to become ready.
|
||||
|
||||
void update(OrganizationsProvider venue) {
|
||||
_organizations = venue;
|
||||
// Trigger a reload when organization changes or when permissions were never loaded.
|
||||
if (_organizations.isOrganizationSet &&
|
||||
_loadedOrgRef != _organizations.current.id &&
|
||||
!_userAccess.isLoading) {
|
||||
unawaited(load());
|
||||
}
|
||||
}
|
||||
|
||||
// Generic wrapper to perform service calls and reload state
|
||||
@@ -42,7 +52,11 @@ class PermissionsProvider extends ChangeNotifier {
|
||||
}
|
||||
|
||||
/// Load the [UserAccess] for the current venue.
|
||||
Future<UserAccess?> load() async {
|
||||
Future<UserAccess?> load() async {
|
||||
if (!_organizations.isOrganizationSet) {
|
||||
// Organization is not ready yet; skip loading until it becomes available.
|
||||
return _userAccess.data;
|
||||
}
|
||||
_userAccess = _userAccess.copyWith(isLoading: true, error: null);
|
||||
notifyListeners();
|
||||
|
||||
@@ -56,6 +70,7 @@ class PermissionsProvider extends ChangeNotifier {
|
||||
_userAccess = _userAccess.copyWith(data: allAccess, isLoading: false);
|
||||
}
|
||||
_isLoaded = true;
|
||||
_loadedOrgRef = orgRef;
|
||||
} catch (e) {
|
||||
_userAccess = _userAccess.copyWith(
|
||||
error: e is Exception ? e : Exception(e.toString()),
|
||||
@@ -164,9 +179,14 @@ class PermissionsProvider extends ChangeNotifier {
|
||||
void reset() {
|
||||
_userAccess = Resource(data: null, isLoading: false, error: null);
|
||||
_isLoaded = false;
|
||||
_loadedOrgRef = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> resetAsync() async {
|
||||
reset();
|
||||
}
|
||||
|
||||
bool canRead(ResourceType r, {Object? objectRef}) => canAccessResource(r, action: perm.Action.read, objectRef: objectRef);
|
||||
bool canUpdate(ResourceType r, {Object? objectRef}) => canAccessResource(r, action: perm.Action.update, objectRef: objectRef);
|
||||
bool canDelete(ResourceType r, {Object? objectRef}) => canAccessResource(r, action: perm.Action.delete, objectRef: objectRef);
|
||||
|
||||
Reference in New Issue
Block a user