resolveUpgradeTarget function
- required Entitlement entitlement,
- required List<
Organization> orgs, - required List<
OrgMember> ? orgMembers, - required String? userId,
- String? scopedOrgId,
Decision helper — pure function, easily unit-testable.
Inputs: the caller's current entitlement + the orgs they belong to + the caller's own user id (to look up their role in those orgs).
scopedOrgId forces the resolver to target a SPECIFIC org rather than
falling back to orgs.first. Used by feature-gated screens that already
know which org they belong to — the user may be in several orgs, so
picking the first one is wrong if the paywall is for a different org.
Implementation
({UpgradeTarget target, String? orgId, String? orgName, String? adminRole})
resolveUpgradeTarget({
required Entitlement entitlement,
required List<Organization> orgs,
required List<OrgMember>? orgMembers,
required String? userId,
String? scopedOrgId,
}) {
if (entitlement.plan == PlanTier.none || userId == null) {
return (
target: UpgradeTarget.none,
orgId: null,
orgName: null,
adminRole: null,
);
}
// Solo user: no org membership. [scopedOrgId] is ignored because the user
// isn't in any org — they need a personal subscription.
if (orgs.isEmpty) {
return (
target: UpgradeTarget.soloSubscription,
orgId: null,
orgName: null,
adminRole: null,
);
}
// Pick the target org: either the one explicitly scoped by the caller, or
// the first one the user belongs to.
final targetOrg = scopedOrgId != null
? orgs.firstWhere((o) => o.id == scopedOrgId, orElse: () => orgs.first)
: orgs.first;
String? myRole;
if (orgMembers != null) {
final me = orgMembers
.where((m) => m.userId == userId && m.orgId == targetOrg.id)
.toList();
if (me.isNotEmpty) {
myRole = me.first.role;
}
}
final isAdmin = myRole == 'owner' || myRole == 'admin';
if (isAdmin) {
return (
target: UpgradeTarget.orgBilling,
orgId: targetOrg.id,
orgName: targetOrg.name,
adminRole: myRole,
);
}
return (
target: UpgradeTarget.contactOrgAdmin,
orgId: targetOrg.id,
orgName: targetOrg.name,
adminRole: myRole,
);
}