Files
ladill-care/app/Support/StaffUx.php
T
isaaccladandCursor 3a7bd14b2b
Deploy Ladill Care / deploy (push) Successful in 43s
Add practitioners admin and staff-scoped Care UX.
Hospital admins can manage assignable doctors and invite team members
from Ladill mailboxes; invited staff only see Care tools they need.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 21:59:39 +00:00

120 lines
3.6 KiB
PHP

<?php
namespace App\Support;
use Illuminate\Contracts\Auth\Authenticatable;
/**
* Staff vs account-owner UX: team members are limited to the apps they were
* invited to. Single-app staff skip Home/launcher; all scoped staff hide
* Billing/Wallet (the account owner pays).
*
* In Care/Meet/etc., values are cached at SSO via Identity (StaffUx::remember).
* In the monolith, TeamAccessService resolves them live when available.
*/
class StaffUx
{
public const SESSION_KEY = 'ladill.staff_ux';
public static function showProductHub(?Authenticatable $user = null): bool
{
$user ??= auth()->user();
if (! $user) {
return false;
}
if ($resolved = self::fromTeamAccess($user)) {
return $resolved['show_hub'];
}
$cached = session(self::SESSION_KEY);
if (is_array($cached) && array_key_exists('show_hub', $cached)) {
return (bool) $cached['show_hub'];
}
// Unknown in a silo before SSO cache — assume owner (fail open for hub).
return true;
}
public static function showBilling(?Authenticatable $user = null): bool
{
$user ??= auth()->user();
if (! $user) {
return false;
}
if ($resolved = self::fromTeamAccess($user)) {
return $resolved['show_billing'];
}
$cached = session(self::SESSION_KEY);
if (is_array($cached) && array_key_exists('show_billing', $cached)) {
return (bool) $cached['show_billing'];
}
return true;
}
/** @return list<string>|null Null means unrestricted / unknown. */
public static function allowedAppSlugs(?Authenticatable $user = null): ?array
{
$user ??= auth()->user();
if (! $user) {
return [];
}
if ($resolved = self::fromTeamAccess($user)) {
return $resolved['full_access'] ? null : $resolved['apps'];
}
$cached = session(self::SESSION_KEY);
if (is_array($cached)) {
if (! empty($cached['full_access'])) {
return null;
}
if (array_key_exists('apps', $cached) && is_array($cached['apps'])) {
return array_values(array_map('strval', $cached['apps']));
}
}
return null;
}
/**
* @param array{full_access?: bool, apps?: list<string>, show_hub?: bool, show_billing?: bool} $payload
*/
public static function remember(array $payload): void
{
session([self::SESSION_KEY => [
'full_access' => (bool) ($payload['full_access'] ?? false),
'apps' => array_values(array_map('strval', (array) ($payload['apps'] ?? []))),
'show_hub' => (bool) ($payload['show_hub'] ?? false),
'show_billing' => (bool) ($payload['show_billing'] ?? false),
]]);
}
/** @return array{full_access: bool, apps: list<string>, show_hub: bool, show_billing: bool}|null */
private static function fromTeamAccess(Authenticatable $user): ?array
{
$service = 'App\\Services\\Team\\TeamAccessService';
$userClass = 'App\\Models\\User';
if (! class_exists($service) || ! is_a($user, $userClass)) {
return null;
}
try {
$access = app($service);
return [
'full_access' => $access->hasFullProductAccess($user),
'apps' => $access->accessibleAppSlugs($user),
'show_hub' => $access->showProductHub($user),
'show_billing' => $access->showBilling($user),
];
} catch (\Throwable) {
return null;
}
}
}