Compare commits

..

No commits in common. "v0.5" and "main" have entirely different histories.
v0.5 ... main

12 changed files with 14 additions and 247 deletions

View file

@ -1,28 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Models\Planner;
use Illuminate\Console\Command;
class PurgeDemoAccountsCommand extends Command
{
protected $signature = 'demo:purge';
protected $description = 'Purge demo accounts older than 24 hours';
public function handle(): int
{
if (! is_mode_demo()) {
$this->error('This command can only run in demo mode.');
return self::FAILURE;
}
$count = Planner::where('created_at', '<', now()->subHours(24))->delete();
$this->info("Purged {$count} demo accounts.");
return self::SUCCESS;
}
}

View file

@ -6,7 +6,6 @@ enum AppModeEnum: string
{
case APP = 'app';
case SAAS = 'saas';
case DEMO = 'demo';
public static function current(): self
{
@ -22,19 +21,4 @@ public function isSaas(): bool
{
return $this === self::SAAS;
}
public function isDemo(): bool
{
return $this === self::DEMO;
}
public function requiresSubscription(): bool
{
return $this === self::SAAS;
}
public function allowsLogout(): bool
{
return $this !== self::DEMO;
}
}

View file

@ -34,10 +34,6 @@ public function login(Request $request)
public function logout(Request $request)
{
if (is_mode_demo()) {
return redirect()->route('dashboard');
}
Auth::logout();
$request->session()->invalidate();

View file

@ -1,43 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Models\Planner;
use Closure;
use DishPlanner\Planner\Actions\SeedDemoPlannerAction;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
class DemoMiddleware
{
public function handle(Request $request, Closure $next): Response
{
if (! is_mode_demo()) {
return $next($request);
}
if (Auth::check()) {
return $next($request);
}
$planner = DB::transaction(function () {
$planner = Planner::create([
'name' => 'Demo User',
'email' => 'demo-' . Str::uuid() . '@demo.local',
'password' => Hash::make(Str::random(32)),
]);
resolve(SeedDemoPlannerAction::class)->execute($planner);
return $planner;
});
Auth::login($planner);
return $next($request);
}
}

View file

@ -2,7 +2,6 @@
namespace App\Http\Middleware;
use App\Enums\AppModeEnum;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
@ -11,7 +10,7 @@ class RequireSubscription
{
public function handle(Request $request, Closure $next): Response
{
if (! AppModeEnum::current()->requiresSubscription()) {
if (is_mode_app()) {
return $next($request);
}

View file

@ -13,7 +13,6 @@
* @property int $id
* @property static PlannerFactory factory($count = null, $state = [])
* @method static first()
* @method static create(array $array)
*/
class Planner extends Authenticatable
{

View file

@ -14,18 +14,4 @@ function is_mode_saas(): bool
{
return AppModeEnum::current()->isSaas();
}
}
if (! function_exists('is_mode_demo')) {
function is_mode_demo(): bool
{
return AppModeEnum::current()->isDemo();
}
}
if (! function_exists('allows_logout')) {
function allows_logout(): bool
{
return AppModeEnum::current()->allowsLogout();
}
}

View file

@ -1,6 +1,5 @@
<?php
use App\Http\Middleware\DemoMiddleware;
use App\Http\Middleware\ForceJsonResponse;
use App\Http\Middleware\RequireSaasMode;
use App\Http\Middleware\RequireSubscription;
@ -28,7 +27,7 @@
->withMiddleware(function (Middleware $middleware) {
// Apply ForceJsonResponse only to API routes
$middleware->api(ForceJsonResponse::class);
$middleware->web(DemoMiddleware::class);
$middleware->alias([
'subscription' => RequireSubscription::class,
'saas' => RequireSaasMode::class,

View file

@ -39,7 +39,6 @@
*/
'mode' => env('APP_MODE', 'app'),
'demo_subscribe_url' => env('APP_DEMO_SUBSCRIBE_URL', 'https://dishplanner.app'),
/*
|--------------------------------------------------------------------------

View file

@ -13,16 +13,6 @@
</head>
<body class="font-sans antialiased bg-gray-600 text-gray-100" x-data="{ mobileMenuOpen: false }">
<div class="min-h-screen">
@if(is_mode_demo())
<!-- Demo Banner -->
<div class="bg-primary text-white text-center py-2 px-4 text-sm sticky top-0 z-[60]">
DEMO MODE.
<a href="{{ config('app.demo_subscribe_url') }}" target="_blank" rel="noopener noreferrer" class="underline font-semibold hover:text-gray-200 ml-1">
Subscribe for only &euro;1 / month &rarr;
</a>
</div>
@endif
<!-- Navigation -->
<nav class="border-b-2 border-secondary shadow-sm z-50 mb-8 bg-gray-700">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@ -80,14 +70,12 @@ class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg bg-gray-
Billing
</a>
@endif
@if(allows_logout())
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="block w-full text-left px-4 py-2 text-sm text-gray-100 hover:bg-gray-600 hover:text-accent-blue">
Logout
</button>
</form>
@endif
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="block w-full text-left px-4 py-2 text-sm text-gray-100 hover:bg-gray-600 hover:text-accent-blue">
Logout
</button>
</form>
</div>
</div>
</div>
@ -162,14 +150,12 @@ class="block text-2xl font-medium {{ request()->routeIs('schedule.*') ? 'text-ac
Billing
</a>
@endif
@if(allows_logout())
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="text-xl text-danger">
Logout
</button>
</form>
@endif
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="text-xl text-danger">
Logout
</button>
</form>
</div>
@else
<div class="space-y-6 text-center">

View file

@ -2,12 +2,7 @@
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote')->hourly();
Schedule::command('demo:purge')
->dailyAt('03:00')
->when(fn () => is_mode_demo());

View file

@ -1,105 +0,0 @@
<?php
namespace DishPlanner\Planner\Actions;
use App\Models\Dish;
use App\Models\Planner;
use App\Models\User;
use DishPlanner\Schedule\Actions\GenerateScheduleForPeriodAction;
class SeedDemoPlannerAction
{
private array $dishNames = [
'Spaghetti Bolognese',
'Chicken Curry',
'Caesar Salad',
'Beef Stir Fry',
'Vegetable Lasagna',
'Fish Tacos',
'Mushroom Risotto',
'BBQ Ribs',
'Greek Salad',
'Pad Thai',
'Margherita Pizza',
'Beef Burger',
'Chicken Fajitas',
'Vegetable Soup',
'Salmon Teriyaki',
'Lamb Chops',
'Shrimp Scampi',
'Pulled Pork Sandwich',
'Caprese Salad',
'Beef Tacos',
'Chicken Alfredo',
'Vegetable Curry',
'Pork Schnitzel',
'Tuna Poke Bowl',
'Beef Stroganoff',
'Chicken Parmesan',
'Ratatouille',
'Fish and Chips',
'Lamb Kebabs',
'Shrimp Fried Rice',
'Pork Tenderloin',
'Nicoise Salad',
'Beef Burritos',
'Chicken Tikka Masala',
'Eggplant Parmesan',
'Grilled Salmon',
'Lamb Tagine',
'Lobster Roll',
'Pork Belly',
'Waldorf Salad',
'Beef Wellington',
'Chicken Satay',
'Stuffed Peppers',
'Miso Glazed Cod',
'Lamb Shanks',
'Crab Cakes',
'Pork Carnitas',
'Cobb Salad',
'Beef Enchiladas',
'Chicken Shawarma',
];
public function execute(Planner $planner): void
{
$users = $this->createUsers($planner);
$this->createDishes($planner, $users);
$this->generateSchedule($planner);
}
private function createUsers(Planner $planner): array
{
$names = ['Alice', 'Bob', 'Charlie'];
return array_map(
fn (string $name) => User::create([
'planner_id' => $planner->id,
'name' => $name,
]),
$names
);
}
private function createDishes(Planner $planner, array $users): void
{
foreach ($this->dishNames as $dishName) {
$dish = Dish::create([
'planner_id' => $planner->id,
'name' => $dishName,
]);
// Randomly assign dish to 1-3 users
$count = rand(1, count($users));
$assignedUsers = collect($users)->random($count);
$userIds = $count === 1 ? [$assignedUsers->id] : $assignedUsers->pluck('id');
$dish->users()->attach($userIds);
}
}
private function generateSchedule(Planner $planner): void
{
resolve(GenerateScheduleForPeriodAction::class)->execute($planner);
}
}