Update
This commit is contained in:
32
app/Helpers/FirstParty/Stripe/StripeHelper.php
Normal file
32
app/Helpers/FirstParty/Stripe/StripeHelper.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers\FirstParty\Stripe;
|
||||
|
||||
use Laravel\Cashier\Events\WebhookReceived;
|
||||
|
||||
class StripeHelper
|
||||
{
|
||||
public static function handleSubscriptionWebhookEvents(WebhookReceived $event)
|
||||
{
|
||||
switch ($event->payload['type']) {
|
||||
case 'customer.subscription.created':
|
||||
case 'customer.subscription.updated':
|
||||
self::handleSubscriptionUpsert($event);
|
||||
break;
|
||||
|
||||
case 'customer.subscription.deleted':
|
||||
self::handleSubscriptionDelete($event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static function handleSubscriptionUpsert(WebhookReceived $event)
|
||||
{
|
||||
///
|
||||
}
|
||||
|
||||
private static function handleSubscriptionDelete(WebhookReceived $event)
|
||||
{
|
||||
///
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public function store(LoginRequest $request): RedirectResponse
|
||||
|
||||
$request->session()->regenerate();
|
||||
|
||||
return redirect()->intended(route('dashboard', absolute: false));
|
||||
return redirect()->intended(route(config('platform.general.authed_route_redirect'), absolute: false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,6 +46,6 @@ public function destroy(Request $request): RedirectResponse
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return redirect('/');
|
||||
return redirect(route('home'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@ public function store(Request $request): RedirectResponse
|
||||
|
||||
$request->session()->put('auth.password_confirmed_at', time());
|
||||
|
||||
return redirect()->intended(route('dashboard', absolute: false));
|
||||
return redirect()->intended(route(config('platform.general.authed_route_redirect'), absolute: false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class EmailVerificationNotificationController extends Controller
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
if ($request->user()->hasVerifiedEmail()) {
|
||||
return redirect()->intended(route('dashboard', absolute: false));
|
||||
return redirect()->intended(route(config('platform.general.authed_route_redirect'), absolute: false));
|
||||
}
|
||||
|
||||
$request->user()->sendEmailVerificationNotification();
|
||||
|
||||
@@ -16,7 +16,7 @@ class EmailVerificationPromptController extends Controller
|
||||
public function __invoke(Request $request): Response|RedirectResponse
|
||||
{
|
||||
return $request->user()->hasVerifiedEmail()
|
||||
? redirect()->intended(route('dashboard', absolute: false))
|
||||
? redirect()->intended(route(config('platform.general.authed_route_redirect'), absolute: false))
|
||||
: Inertia::render('auth/verify-email', ['status' => $request->session()->get('status')]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,6 @@ public function store(Request $request): RedirectResponse
|
||||
|
||||
Auth::login($user);
|
||||
|
||||
return to_route('dashboard');
|
||||
return to_route(config('platform.general.authed_route_redirect'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class VerifyEmailController extends Controller
|
||||
public function __invoke(EmailVerificationRequest $request): RedirectResponse
|
||||
{
|
||||
if ($request->user()->hasVerifiedEmail()) {
|
||||
return redirect()->intended(route('dashboard', absolute: false).'?verified=1');
|
||||
return redirect()->intended(route(config('platform.general.authed_route_redirect'), absolute: false) . '?verified=1');
|
||||
}
|
||||
|
||||
if ($request->user()->markEmailAsVerified()) {
|
||||
@@ -25,6 +25,6 @@ public function __invoke(EmailVerificationRequest $request): RedirectResponse
|
||||
event(new Verified($user));
|
||||
}
|
||||
|
||||
return redirect()->intended(route('dashboard', absolute: false).'?verified=1');
|
||||
return redirect()->intended(route(config('platform.general.authed_route_redirect'), absolute: false) . '?verified=1');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use App;
|
||||
use App\Models\User;
|
||||
use App\Models\UserPlan;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
|
||||
@@ -60,7 +61,7 @@ public function handleGoogleCallback()
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->intended(route('home'));
|
||||
return redirect()->intended(route('home'))->with('success', "You're now logged in!");
|
||||
} catch (\Exception $e) {
|
||||
|
||||
throw $e;
|
||||
@@ -73,7 +74,17 @@ public function handleGoogleCallback()
|
||||
}
|
||||
}
|
||||
|
||||
private function setupUser($user) {}
|
||||
private function setupUser($user)
|
||||
{
|
||||
$user_plan = UserPlan::where('user_id', $user->id)->first();
|
||||
|
||||
if (!$user_plan) {
|
||||
$user_plan = UserPlan::create([
|
||||
'user_id' => $user->id,
|
||||
'plan_id' => 'free',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function getMockGoogleUser()
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@ public function subscribe(Request $request)
|
||||
'cancel_url' => route('subscribe.cancelled') . '?' . 'session_id={CHECKOUT_SESSION_ID}',
|
||||
'line_items' => [[
|
||||
'price' => $price_id,
|
||||
'quantity' => 1,
|
||||
]],
|
||||
];
|
||||
|
||||
@@ -60,10 +61,7 @@ public function subscribeSuccess(Request $request)
|
||||
|
||||
Session::forget('checkout_session_id');
|
||||
|
||||
return redirect()->route('home')->with('success', [
|
||||
'message' => 'Thank you for subscribing! Your subscription should be active momentarily. Please refresh the page if you do not see your plan.',
|
||||
'action' => 'subscription_success',
|
||||
]);
|
||||
return redirect()->route('home')->with('success', 'Thank you for subscribing! Your subscription should be active momentarily. Please refresh the page if you do not see your plan.');
|
||||
}
|
||||
|
||||
public function subscribeCancelled(Request $request)
|
||||
@@ -73,10 +71,7 @@ public function subscribeCancelled(Request $request)
|
||||
Session::forget('checkout_session_id');
|
||||
}
|
||||
|
||||
return redirect()->route('home')->with('error', [
|
||||
'message' => "You've decided not to complete the payment at this time. No charges have been made to your account.",
|
||||
'action' => 'subscription_cancelled',
|
||||
]);
|
||||
return redirect()->route('home')->with('error', "You've decided not to complete the payment at this time. No charges have been made to your account.");
|
||||
}
|
||||
|
||||
// PURCHASE (ONE TIME)
|
||||
@@ -112,10 +107,7 @@ public function purchaseSuccess(Request $request)
|
||||
|
||||
Session::forget('checkout_session_id');
|
||||
|
||||
return redirect()->route('home')->with('success', [
|
||||
'message' => 'Thank you for purchasing! Your purchase should be active momentarily. Please refresh the page if you do not see your plan.',
|
||||
'action' => 'purchase_success',
|
||||
]);
|
||||
return redirect()->route('home')->with('success', "Thank you for purchasing! Your purchase should be active momentarily. Please refresh the page if you do not see your plan.");
|
||||
}
|
||||
|
||||
public function purchaseCancelled(Request $request)
|
||||
@@ -124,9 +116,6 @@ public function purchaseCancelled(Request $request)
|
||||
Session::forget('checkout_session_id');
|
||||
}
|
||||
|
||||
return redirect()->route('home')->with('error', [
|
||||
'message' => "You've decided not to complete the payment at this time. No charges have been made to your account.",
|
||||
'action' => 'purchase_cancelled',
|
||||
]);
|
||||
return redirect()->route('home')->with('error', "You've decided not to complete the payment at this time. No charges have been made to your account.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ public function share(Request $request): array
|
||||
'location' => $request->url(),
|
||||
],
|
||||
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
|
||||
'flash' => [
|
||||
'message' => fn() => $request->session()->get('message'),
|
||||
'error' => fn() => $request->session()->get('error'),
|
||||
'success' => fn() => $request->session()->get('success'),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
28
app/Listeners/StripeEventListener.php
Normal file
28
app/Listeners/StripeEventListener.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Helpers\FirstParty\Stripe\StripeHelper;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
use Laravel\Cashier\Events\WebhookReceived;
|
||||
|
||||
class StripeEventListener
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*/
|
||||
public function handle(WebhookReceived $event): void
|
||||
{
|
||||
StripeHelper::handleSubscriptionWebhookEvents($event);
|
||||
}
|
||||
}
|
||||
31
app/Models/Plan.php
Normal file
31
app/Models/Plan.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Created by Reliese Model.
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Class Plan
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $tier
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
*
|
||||
* @package App\Models
|
||||
*/
|
||||
class Plan extends Model
|
||||
{
|
||||
protected $table = 'plans';
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'tier'
|
||||
];
|
||||
}
|
||||
@@ -24,6 +24,7 @@ class User extends Authenticatable
|
||||
'email',
|
||||
'password',
|
||||
'uuid',
|
||||
'google_id',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
45
app/Models/UserPlan.php
Normal file
45
app/Models/UserPlan.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Created by Reliese Model.
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Class UserPlan
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $user_id
|
||||
* @property int $plan_id
|
||||
* @property Carbon|null $current_period_end
|
||||
* @property Carbon|null $cancel_at
|
||||
* @property Carbon|null $canceled_at
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
*
|
||||
* @package App\Models
|
||||
*/
|
||||
class UserPlan extends Model
|
||||
{
|
||||
protected $table = 'user_plans';
|
||||
|
||||
protected $casts = [
|
||||
'user_id' => 'int',
|
||||
'plan_id' => 'int',
|
||||
'current_period_end' => 'datetime',
|
||||
'cancel_at' => 'datetime',
|
||||
'canceled_at' => 'datetime'
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'plan_id',
|
||||
'current_period_end',
|
||||
'cancel_at',
|
||||
'canceled_at'
|
||||
];
|
||||
}
|
||||
29
database/migrations/2025_07_01_145515_create_plans_table.php
Normal file
29
database/migrations/2025_07_01_145515_create_plans_table.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('plans', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('tier');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('plans');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('user_plans', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id');
|
||||
$table->foreignId('plan_id');
|
||||
$table->dateTime('current_period_end')->nullable();
|
||||
$table->dateTime('cancel_at')->nullable();
|
||||
$table->dateTime('canceled_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_plans');
|
||||
}
|
||||
};
|
||||
43
database/seeders/PlanSeeder.php
Normal file
43
database/seeders/PlanSeeder.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use DB;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class PlanSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$plans = config('platform.purchases.subscriptions');
|
||||
|
||||
foreach ($plans as $plan) {
|
||||
|
||||
if ($plan['type'] !== 'subscription_plans') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if plan with this tier already exists
|
||||
$existingPlan = DB::table('plans')
|
||||
->where('tier', $plan['id'])
|
||||
->first();
|
||||
|
||||
if (! $existingPlan) {
|
||||
DB::table('plans')->insert([
|
||||
'name' => $plan['name'],
|
||||
'tier' => $plan['id'],
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$this->command->info("Inserted plan: {$plan['name']}");
|
||||
} else {
|
||||
$this->command->info("Skipped existing plan tier: {$plan['id']}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import AppLogo from './app-logo';
|
||||
const mainNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
href: route('dashboard'),
|
||||
href: route(config('platform.general.authed_route_redirect')),
|
||||
icon: LayoutGrid,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } f
|
||||
import { useMitt } from '@/plugins/MittContext';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const AuthDialog = ({ onOpenChange }) => {
|
||||
const AuthDialog = ({}) => {
|
||||
const emitter = useMitt();
|
||||
|
||||
const [isLogin, setIsLogin] = useState(false);
|
||||
@@ -21,13 +21,31 @@ const AuthDialog = ({ onOpenChange }) => {
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const handleOpenLogin = () => {
|
||||
setIsLogin(true);
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const handleOpenJoin = () => {
|
||||
setIsLogin(false);
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
emitter.on('401', handleOpenAuth);
|
||||
emitter.on('login', handleOpenLogin);
|
||||
emitter.on('join', handleOpenJoin);
|
||||
|
||||
return () => {
|
||||
emitter.off('401', handleOpenAuth);
|
||||
emitter.off('login', handleOpenLogin);
|
||||
emitter.off('join', handleOpenJoin);
|
||||
};
|
||||
}, [emitter]);
|
||||
|
||||
const onOpenChange = (open) => {
|
||||
setIsOpen(open);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="sm:max-w-[400px]">
|
||||
|
||||
@@ -2,16 +2,28 @@ import { usePage } from '@inertiajs/react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
|
||||
import { useMitt } from '@/plugins/MittContext';
|
||||
import useLocalSettingsStore from '@/stores/localSettingsStore';
|
||||
import { Link } from '@inertiajs/react';
|
||||
|
||||
export default function EditNavSidebar({ isOpen, onClose }) {
|
||||
const { auth } = usePage().props;
|
||||
|
||||
const emitter = useMitt();
|
||||
|
||||
const { getSetting, setSetting } = useLocalSettingsStore();
|
||||
|
||||
const openAuth = (isLogin) => {
|
||||
if (isLogin) {
|
||||
emitter.emit('login');
|
||||
} else {
|
||||
emitter.emit('join');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Sheet open={isOpen} onOpenChange={(open) => !open && onClose()}>
|
||||
<SheetContent side="left" className="w-50 overflow-y-auto">
|
||||
<SheetContent side="left" className="w-[220px] overflow-y-auto">
|
||||
<SheetHeader>
|
||||
<SheetTitle className="flex items-center gap-3">
|
||||
<div className="font-display ml-0 text-lg tracking-wide md:ml-3 md:text-xl">MEMEAIGEN</div>
|
||||
@@ -20,19 +32,42 @@ export default function EditNavSidebar({ isOpen, onClose }) {
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="grid px-2">
|
||||
{/* {!auth.user && <Button variant="outline">Join Now</Button>}
|
||||
{!auth.user && <Button variant="link">Login</Button>} */}
|
||||
</div>
|
||||
|
||||
<div className="grid px-2">
|
||||
{!auth.user && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
window.location.href = route('home');
|
||||
openAuth(false);
|
||||
}}
|
||||
variant="outline"
|
||||
>
|
||||
Sign Up
|
||||
</Button>
|
||||
)}
|
||||
{!auth.user && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
openAuth(true);
|
||||
}}
|
||||
variant="link"
|
||||
>
|
||||
Home
|
||||
Login
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 px-2">
|
||||
<Link className="text-primary block w-full text-sm underline-offset-4 hover:underline" href={route('home')} as="button">
|
||||
Home
|
||||
</Link>
|
||||
{auth.user && (
|
||||
<Link
|
||||
className="text-primary block w-full text-sm underline-offset-4 hover:underline"
|
||||
method="post"
|
||||
href={route('logout')}
|
||||
as="button"
|
||||
>
|
||||
Log out
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</SheetContent>
|
||||
|
||||
23
resources/js/modules/flash/flash-messages.jsx
Normal file
23
resources/js/modules/flash/flash-messages.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { usePage } from '@inertiajs/react';
|
||||
import { useEffect } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
const FlashMessages = () => {
|
||||
const { flash } = usePage().props;
|
||||
|
||||
useEffect(() => {
|
||||
if (flash.message) {
|
||||
toast.success(flash.message);
|
||||
}
|
||||
|
||||
if (flash.error) {
|
||||
toast.error(flash.error);
|
||||
}
|
||||
|
||||
if (flash.success) {
|
||||
toast.success(flash.success);
|
||||
}
|
||||
}, [flash]);
|
||||
};
|
||||
|
||||
export default FlashMessages;
|
||||
@@ -1,9 +1,11 @@
|
||||
import Editor from '@/modules/editor/editor.jsx';
|
||||
import FlashMessages from '@/modules/flash/flash-messages';
|
||||
|
||||
const Home = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-neutral-50 dark:bg-neutral-800">
|
||||
<Editor />
|
||||
<FlashMessages />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function Welcome() {
|
||||
<nav className="flex items-center justify-end gap-4">
|
||||
{auth.user ? (
|
||||
<Link
|
||||
href={route('dashboard')}
|
||||
href={route(config('platform.general.authed_route_redirect'))}
|
||||
className="inline-block rounded-sm border border-[#19140035] px-5 py-1.5 text-sm leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b]"
|
||||
>
|
||||
Dashboard
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
]);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
$response->assertRedirect(route(config('platform.general.authed_route_redirect'), absolute: false));
|
||||
});
|
||||
|
||||
test('users can not authenticate with invalid password', function () {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
Event::assertDispatched(Verified::class);
|
||||
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
|
||||
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
|
||||
$response->assertRedirect(route(config('platform.general.authed_route_redirect'), absolute: false) . '?verified=1');
|
||||
});
|
||||
|
||||
test('email is not verified with invalid hash', function () {
|
||||
|
||||
@@ -17,5 +17,5 @@
|
||||
]);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
$response->assertRedirect(route(config('platform.general.authed_route_redirect'), absolute: false));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user