Files
ladill-care/app/Services/Care/ConsultationReturnContext.php
T
isaaccladandCursor 94e53d05bf
Deploy Ladill Care / deploy (push) Successful in 1m7s
Keep consultation context on nested clinical pages and add Call again on patient queue cards.
Doctors can return to the active consultation from forms, lab, prescriptions, pathways, and bills; queue cards can re-announce called/serving tickets via the existing Queue recall bridge.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-17 17:48:34 +00:00

147 lines
4.1 KiB
PHP

<?php
namespace App\Services\Care;
use App\Models\Consultation;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
/**
* Preserves "serving from consultation" context when doctors navigate to nested
* forms (prescriptions, assessments, lab requests, pathways, bills).
*
* Preference order: explicit ?from_consultation= query → session remembered on
* consultation show. Direct access without either shows no consultation chrome.
*/
class ConsultationReturnContext
{
public const QUERY_KEY = 'from_consultation';
public const SESSION_KEY = 'care.from_consultation';
public function remember(Consultation $consultation): void
{
if ($consultation->status === Consultation::STATUS_COMPLETED) {
$this->forget();
return;
}
session([self::SESSION_KEY => $consultation->uuid]);
}
public function forget(): void
{
session()->forget(self::SESSION_KEY);
}
public function uuidFrom(Request $request): ?string
{
foreach ([
$request->query(self::QUERY_KEY),
$request->input(self::QUERY_KEY),
session(self::SESSION_KEY),
] as $candidate) {
if (is_string($candidate) && Str::isUuid($candidate)) {
return $candidate;
}
}
return null;
}
/**
* Capture an explicit from_consultation posted/queried value into session
* so subsequent redirects keep the serving flow.
*/
public function capture(Request $request): void
{
$uuid = $request->query(self::QUERY_KEY) ?? $request->input(self::QUERY_KEY);
if (is_string($uuid) && Str::isUuid($uuid)) {
session([self::SESSION_KEY => $uuid]);
}
}
public function resolve(Request $request, ?int $patientId = null): ?Consultation
{
$this->capture($request);
$uuid = $this->uuidFrom($request);
if ($uuid === null) {
return null;
}
$consultation = Consultation::query()
->where('uuid', $uuid)
->with(['patient', 'appointment'])
->first();
if (! $consultation) {
return null;
}
if ($patientId !== null && (int) $consultation->patient_id !== $patientId) {
return null;
}
return $consultation;
}
/**
* Resolve from an explicit linked consultation (e.g. prescription.consultation)
* only when the doctor is already in a serving flow for that consultation.
*/
public function resolveLinked(Request $request, ?Consultation $linked): ?Consultation
{
if (! $linked) {
return null;
}
$active = $this->resolve($request, (int) $linked->patient_id);
if ($active && $active->id === $linked->id) {
return $active;
}
// Nested under consultation route (create prescription) or still in progress
// with an explicit query/session match already handled above. For linked
// records opened mid-flow without query (POST redirect), prefer the linked
// consultation when session matches its uuid.
$uuid = $this->uuidFrom($request);
if ($uuid !== null && $linked->uuid === $uuid) {
$linked->loadMissing(['patient', 'appointment']);
return $linked;
}
return null;
}
/**
* @return array{from_consultation: string}
*/
public function query(Consultation $consultation): array
{
return [self::QUERY_KEY => $consultation->uuid];
}
public function withQuery(string $url, Consultation $consultation): string
{
$separator = str_contains($url, '?') ? '&' : '?';
return $url.$separator.self::QUERY_KEY.'='.urlencode($consultation->uuid);
}
/**
* Route parameters to keep return context on redirects (empty when none).
*
* @return array<string, string>
*/
public function routeQuery(Request $request): array
{
$this->capture($request);
$uuid = $this->uuidFrom($request);
return $uuid ? [self::QUERY_KEY => $uuid] : [];
}
}