Fix redirect loop on session expiry and add missing nav links

- Add redirectGuestsTo in bootstrap/app.php so unauthenticated users
  always redirect to the full account login URL instead of a relative
  /login that would 404 on the admin subdomain or loop
- Create HandleInertiaRequests middleware to share auth.user, flash
  messages, and domain config to all Vue pages (was entirely missing)
- Add Profile nav link in AppLayout, "Customer View" link in AdminLayout
- Point logout to account subdomain where Fortify routes live
- Link AuthLayout logo back to marketing site
- Fix Marketing/Home links to use full account subdomain URLs
- Update RoleBasedAccessTest to match new redirect URL

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Dev
2026-02-09 02:55:48 -05:00
parent 26704f9721
commit 5988c6d064
7 changed files with 75 additions and 9 deletions

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Inertia\Middleware;
class HandleInertiaRequests extends Middleware
{
/** @return array<string, mixed> */
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'auth' => fn () => [
'user' => $request->user() ? $request->user()->only('id', 'name', 'email', 'status') : null,
],
'flash' => fn () => [
'success' => $request->session()->get('success'),
'error' => $request->session()->get('error'),
],
'domains' => fn () => [
'marketing' => config('app.domains.marketing'),
'account' => config('app.domains.account'),
'admin' => config('app.domains.admin'),
],
]);
}
}

View File

@@ -29,9 +29,11 @@ return Application::configure(basePath: dirname(__DIR__))
$middleware->trustProxies(at: '*');
$middleware->web(append: [
\Inertia\Middleware::class,
\App\Http\Middleware\HandleInertiaRequests::class,
]);
$middleware->redirectGuestsTo(fn () => 'https://'.config('app.domains.account').'/login');
$middleware->alias([
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,

View File

@@ -1,8 +1,12 @@
<script setup>
import { Link, usePage } from '@inertiajs/vue3';
import { computed } from 'vue';
import FlashMessages from '@/Components/FlashMessages.vue';
const page = usePage();
const user = page.props.auth?.user;
const user = computed(() => page.props.auth?.user);
const domains = computed(() => page.props.domains);
const accountUrl = computed(() => `https://${domains.value?.account}`);
</script>
<template>
@@ -24,10 +28,17 @@ const user = page.props.auth?.user;
</div>
</div>
<div class="flex items-center space-x-4">
<a
v-if="user"
:href="accountUrl + '/dashboard'"
class="text-sm text-gray-400 hover:text-white"
>
Customer View
</a>
<span v-if="user" class="text-sm text-gray-300">{{ user.name }}</span>
<Link
v-if="user"
href="/logout"
:href="accountUrl + '/logout'"
method="post"
as="button"
class="text-sm text-gray-400 hover:text-white"
@@ -40,6 +51,7 @@ const user = page.props.auth?.user;
</nav>
<main class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<FlashMessages />
<slot />
</main>
</div>

View File

@@ -1,8 +1,11 @@
<script setup>
import { Link, usePage } from '@inertiajs/vue3';
import { computed } from 'vue';
import FlashMessages from '@/Components/FlashMessages.vue';
const page = usePage();
const user = page.props.auth?.user;
const user = computed(() => page.props.auth?.user);
const domains = computed(() => page.props.domains);
</script>
<template>
@@ -21,6 +24,12 @@ const user = page.props.auth?.user;
>
Dashboard
</Link>
<Link
href="/profile"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
>
Profile
</Link>
</div>
</div>
<div class="flex items-center space-x-4">
@@ -40,6 +49,7 @@ const user = page.props.auth?.user;
</nav>
<main class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<FlashMessages />
<slot />
</main>
</div>

View File

@@ -1,11 +1,17 @@
<script setup>
import { usePage } from '@inertiajs/vue3';
import { computed } from 'vue';
const page = usePage();
const domains = computed(() => page.props.domains);
const marketingUrl = computed(() => `https://${domains.value?.marketing}`);
</script>
<template>
<div class="min-h-screen flex flex-col items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div class="w-full max-w-md">
<div class="text-center mb-8">
<h1 class="text-3xl font-bold text-gray-900">EZSCALE</h1>
<a :href="marketingUrl" class="text-3xl font-bold text-gray-900">EZSCALE</a>
<p class="mt-2 text-sm text-gray-600">Cloud Hosting Platform</p>
</div>
<div class="bg-white shadow-sm rounded-lg border border-gray-200 p-8">

View File

@@ -1,4 +1,10 @@
<script setup>
import { usePage } from '@inertiajs/vue3';
import { computed } from 'vue';
const page = usePage();
const domains = computed(() => page.props.domains);
const accountUrl = computed(() => `https://${domains.value?.account}`);
</script>
<template>
@@ -8,8 +14,8 @@
<div class="flex justify-between h-16 items-center">
<span class="text-xl font-bold text-gray-900">EZSCALE</span>
<div class="space-x-4">
<a href="/login" class="text-sm text-gray-600 hover:text-gray-900">Sign in</a>
<a href="/register" class="text-sm px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">Get Started</a>
<a :href="accountUrl + '/login'" class="text-sm text-gray-600 hover:text-gray-900">Sign in</a>
<a :href="accountUrl + '/register'" class="text-sm px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">Get Started</a>
</div>
</div>
</div>
@@ -25,7 +31,7 @@
VPS, Dedicated Servers, Web Hosting, and Game Servers. Powered by EZSCALE.
</p>
<div class="mt-10">
<a href="/register" class="px-8 py-3 bg-blue-600 text-white font-medium rounded-md hover:bg-blue-700 text-lg">
<a :href="accountUrl + '/register'" class="px-8 py-3 bg-blue-600 text-white font-medium rounded-md hover:bg-blue-700 text-lg">
Start Free Trial
</a>
</div>

View File

@@ -12,7 +12,7 @@ beforeEach(function (): void {
it('redirects unauthenticated users to login', function (): void {
$this->get($this->accountUrl.'/dashboard')
->assertRedirect($this->accountUrl.'/login');
->assertRedirect('https://'.config('app.domains.account').'/login');
});
it('identifies admin users correctly', function (): void {