Replace native dialogs with app modals for Events link and unlink.
Deploy Ladill Meet / deploy (push) Successful in 49s

Link opens an in-page modal on conference and webinar show pages; unlink uses the shared confirm-dialog component.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-04 22:39:02 +00:00
co-authored by Cursor
parent d0e68f15c7
commit 14e7ae9557
8 changed files with 222 additions and 72 deletions
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers\Meet\Concerns;
use App\Models\Room;
use App\Services\Integrations\EventsLinkService;
use App\Services\Meet\MeetPermissions;
use App\Support\EventsSourceLink;
use Illuminate\Http\Request;
trait ResolvesEventsLinkContext
{
/** @return array{canManageEvents: bool, linkableEvents: list<array<string, mixed>>} */
protected function eventsLinkContext(Request $request, Room $room): array
{
$canManageEvents = app(MeetPermissions::class)->can($this->member($request), 'meetings.manage');
$linkableEvents = $canManageEvents && ! EventsSourceLink::isLinked($room)
? app(EventsLinkService::class)->linkableEvents($request->user())
: [];
return compact('canManageEvents', 'linkableEvents');
}
}
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Meet;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Meet\Concerns\BuildsMeetIndexPage;
use App\Http\Controllers\Meet\Concerns\ResolvesEventsLinkContext;
use App\Http\Controllers\Meet\Concerns\ScopesToAccount;
use App\Models\Member;
use App\Models\Room;
@@ -20,7 +21,7 @@ use Illuminate\View\View;
class ConferenceController extends Controller
{
use BuildsMeetIndexPage, ScopesToAccount;
use BuildsMeetIndexPage, ResolvesEventsLinkContext, ScopesToAccount;
public function __construct(
protected RoomService $rooms,
@@ -124,7 +125,9 @@ class ConferenceController extends Controller
$room->load(['sessions.participants', 'invitations', 'sessions.recordings', 'sessions.aiSummaries', 'sessionFiles']);
return view('meet.conferences.show', compact('room'));
extract($this->eventsLinkContext($request, $room));
return view('meet.conferences.show', compact('room', 'canManageEvents', 'linkableEvents'));
}
public function updateSpeakers(Request $request, Room $room): RedirectResponse
@@ -7,10 +7,8 @@ use App\Http\Controllers\Meet\Concerns\ScopesToAccount;
use App\Models\Room;
use App\Services\Integrations\EventsClient;
use App\Services\Integrations\EventsLinkService;
use App\Support\EventsSourceLink;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class EventsLinkController extends Controller
{
@@ -21,7 +19,7 @@ class EventsLinkController extends Controller
protected EventsClient $eventsClient,
) {}
public function show(Request $request, Room $room): View|RedirectResponse
public function show(Request $request, Room $room): RedirectResponse
{
$this->authorizeAbility($request, 'meetings.manage');
$this->authorizeOwner($request, $room);
@@ -33,16 +31,9 @@ class EventsLinkController extends Controller
->withErrors(['events' => 'Ladill Events linking is not configured. Set MEET_API_KEY_EVENTS in Meet (and the matching EVENTS_API_KEY_MEET in Events), then try again.']);
}
$events = $this->links->linkableEvents($request->user());
$expectedType = $room->isConference() ? 'town_hall' : 'webinar';
return view('meet.events.link', [
'room' => $room,
'events' => $events,
'expectedType' => $expectedType,
'eventsAppUrl' => EventsSourceLink::baseUrl(),
'isLinked' => EventsSourceLink::isLinked($room),
]);
return redirect()
->route($room->isWebinar() ? 'meet.webinars.show' : 'meet.conferences.show', $room)
->with('open_events_link_modal', true);
}
public function store(Request $request, Room $room): RedirectResponse
@@ -51,11 +42,21 @@ class EventsLinkController extends Controller
$this->authorizeOwner($request, $room);
abort_unless($room->isWebinar() || $room->isConference(), 404);
$validated = $request->validate([
$validator = \Illuminate\Support\Facades\Validator::make($request->all(), [
'event_id' => ['required', 'integer', 'min:1'],
'virtual_session_id' => ['nullable', 'string', 'max:64'],
]);
if ($validator->fails()) {
return redirect()
->route($room->isWebinar() ? 'meet.webinars.show' : 'meet.conferences.show', $room)
->withErrors($validator)
->withInput()
->with('open_events_link_modal', true);
}
$validated = $validator->validated();
try {
$this->links->link(
$room,
@@ -64,7 +65,11 @@ class EventsLinkController extends Controller
$validated['virtual_session_id'] ?? null,
);
} catch (\RuntimeException $e) {
return back()->withErrors(['events' => $e->getMessage()])->withInput();
return redirect()
->route($room->isWebinar() ? 'meet.webinars.show' : 'meet.conferences.show', $room)
->withErrors(['events' => $e->getMessage()])
->withInput()
->with('open_events_link_modal', true);
}
$route = $room->isWebinar() ? 'meet.webinars.show' : 'meet.conferences.show';
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Meet;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Meet\Concerns\BuildsMeetIndexPage;
use App\Http\Controllers\Meet\Concerns\ResolvesEventsLinkContext;
use App\Http\Controllers\Meet\Concerns\ScopesToAccount;
use App\Models\Room;
use App\Services\Meet\CalendarService;
@@ -16,7 +17,7 @@ use Illuminate\View\View;
class WebinarController extends Controller
{
use BuildsMeetIndexPage, ScopesToAccount;
use BuildsMeetIndexPage, ResolvesEventsLinkContext, ScopesToAccount;
public function __construct(
protected RoomService $rooms,
@@ -113,7 +114,9 @@ class WebinarController extends Controller
$room->load(['sessions.participants', 'invitations', 'sessions.recordings', 'sessions.aiSummaries', 'sessionFiles']);
return view('meet.webinars.show', compact('room'));
extract($this->eventsLinkContext($request, $room));
return view('meet.webinars.show', compact('room', 'canManageEvents', 'linkableEvents'));
}
public function start(Request $request, Room $room): RedirectResponse