feature - 6 - port react frontend to laravel blade + livewire

This commit is contained in:
myrmidex 2025-12-26 13:37:23 +01:00
parent afa4cf27b7
commit 71ed93fda0
453 changed files with 5145 additions and 184 deletions

23
.gitignore vendored
View file

@ -1 +1,24 @@
/composer.lock
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
/auth.json
/.fleet
/.idea
/.nova
/.vscode
/.zed

View file

@ -10,7 +10,10 @@ class ForceJsonResponse
{
public function handle(Request $request, Closure $next): Response
{
$request->headers->set('Accept', 'application/json');
// Only force JSON for API routes
if ($request->is('api/*')) {
$request->headers->set('Accept', 'application/json');
}
return $next($request);
}

View file

@ -0,0 +1,36 @@
<?php
namespace App\Livewire\Auth;
use Livewire\Component;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Rule;
class Login extends Component
{
#[Rule('required|email')]
public $email = '';
#[Rule('required')]
public $password = '';
public $remember = false;
public function login()
{
$this->validate();
if (Auth::attempt(['email' => $this->email, 'password' => $this->password], $this->remember)) {
session()->regenerate();
return redirect()->intended(route('dashboard'));
}
$this->addError('email', 'These credentials do not match our records.');
}
public function render()
{
return view('livewire.auth.login')
->layout('layouts.guest');
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Livewire\Auth;
use App\Models\User;
use Livewire\Component;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Livewire\Attributes\Rule;
class Register extends Component
{
#[Rule('required|string|max:255')]
public $name = '';
#[Rule('required|email|unique:users,email')]
public $email = '';
#[Rule('required|min:8|confirmed')]
public $password = '';
public $password_confirmation = '';
#[Rule('required|exists:planners,id')]
public $planner_id = '';
public function mount()
{
// Set default planner_id if only one exists
$planners = \App\Models\Planner::all();
if ($planners->count() === 1) {
$this->planner_id = $planners->first()->id;
}
}
public function register()
{
$this->validate();
$user = User::create([
'name' => $this->name,
'email' => $this->email,
'password' => Hash::make($this->password),
'planner_id' => $this->planner_id,
]);
Auth::login($user);
session()->regenerate();
return redirect()->route('dashboard');
}
public function render()
{
return view('livewire.auth.register', [
'planners' => \App\Models\Planner::all()
])->layout('layouts.guest');
}
}

View file

@ -0,0 +1,122 @@
<?php
namespace App\Livewire\Dishes;
use App\Models\Dish;
use App\Models\User;
use Livewire\Component;
use Livewire\WithPagination;
class DishesList extends Component
{
use WithPagination;
public $showCreateModal = false;
public $showEditModal = false;
public $showDeleteModal = false;
public $editingDish = null;
public $deletingDish = null;
// Form fields
public $name = '';
public $selectedUsers = [];
protected $rules = [
'name' => 'required|string|max:255',
'selectedUsers' => 'array',
];
public function render()
{
$dishes = Dish::with('users')
->orderBy('name')
->paginate(10);
$users = User::where('planner_id', auth()->user()->planner_id)
->orderBy('name')
->get();
return view('livewire.dishes.dishes-list', [
'dishes' => $dishes,
'users' => $users
]);
}
public function create()
{
$this->reset(['name', 'selectedUsers']);
$this->resetValidation();
$this->showCreateModal = true;
}
public function store()
{
$this->validate();
$dish = Dish::create([
'name' => $this->name,
'planner_id' => auth()->user()->planner_id,
]);
// Attach selected users
if (!empty($this->selectedUsers)) {
$dish->users()->attach($this->selectedUsers);
}
$this->showCreateModal = false;
$this->reset(['name', 'selectedUsers']);
session()->flash('success', 'Dish created successfully.');
}
public function edit(Dish $dish)
{
$this->editingDish = $dish;
$this->name = $dish->name;
$this->selectedUsers = $dish->users->pluck('id')->toArray();
$this->resetValidation();
$this->showEditModal = true;
}
public function update()
{
$this->validate();
$this->editingDish->update([
'name' => $this->name,
]);
// Sync users
$this->editingDish->users()->sync($this->selectedUsers);
$this->showEditModal = false;
$this->reset(['name', 'selectedUsers', 'editingDish']);
session()->flash('success', 'Dish updated successfully.');
}
public function confirmDelete(Dish $dish)
{
$this->deletingDish = $dish;
$this->showDeleteModal = true;
}
public function delete()
{
$this->deletingDish->users()->detach();
$this->deletingDish->delete();
$this->showDeleteModal = false;
$this->deletingDish = null;
session()->flash('success', 'Dish deleted successfully.');
}
public function cancel()
{
$this->showCreateModal = false;
$this->showEditModal = false;
$this->showDeleteModal = false;
$this->reset(['name', 'selectedUsers', 'editingDish', 'deletingDish']);
}
}

View file

@ -0,0 +1,152 @@
<?php
namespace App\Livewire\Schedule;
use App\Models\ScheduledUserDish;
use Carbon\Carbon;
use Livewire\Component;
class ScheduleCalendar extends Component
{
public $currentMonth;
public $currentYear;
public $calendarDays = [];
public $showRegenerateModal = false;
public $regenerateDate = null;
public $regenerateUserId = null;
public function mount()
{
$this->currentMonth = now()->month;
$this->currentYear = now()->year;
$this->generateCalendar();
}
protected $listeners = ['schedule-generated' => 'refreshCalendar'];
public function render()
{
return view('livewire.schedule.schedule-calendar');
}
public function refreshCalendar()
{
$this->generateCalendar();
}
public function generateCalendar()
{
$this->calendarDays = [];
// Get first day of the month and total days
$firstDay = Carbon::createFromDate($this->currentYear, $this->currentMonth, 1);
$daysInMonth = $firstDay->daysInMonth;
// Generate 31 days for consistency with React version
for ($day = 1; $day <= 31; $day++) {
if ($day <= $daysInMonth) {
$date = Carbon::createFromDate($this->currentYear, $this->currentMonth, $day);
// Get scheduled dishes for this date
$scheduledDishes = ScheduledUserDish::with(['user', 'dish'])
->whereDate('date', $date->format('Y-m-d'))
->get();
$this->calendarDays[] = [
'day' => $day,
'date' => $date,
'isToday' => $date->isToday(),
'scheduledDishes' => $scheduledDishes,
'isEmpty' => $scheduledDishes->isEmpty()
];
} else {
// Empty slot for days that don't exist in this month
$this->calendarDays[] = [
'day' => null,
'date' => null,
'isToday' => false,
'scheduledDishes' => collect(),
'isEmpty' => true
];
}
}
}
public function previousMonth()
{
if ($this->currentMonth === 1) {
$this->currentMonth = 12;
$this->currentYear--;
} else {
$this->currentMonth--;
}
$this->generateCalendar();
}
public function nextMonth()
{
if ($this->currentMonth === 12) {
$this->currentMonth = 1;
$this->currentYear++;
} else {
$this->currentMonth++;
}
$this->generateCalendar();
}
public function regenerateForUserDate($date, $userId)
{
$this->regenerateDate = $date;
$this->regenerateUserId = $userId;
$this->showRegenerateModal = true;
}
public function confirmRegenerate()
{
try {
// Delete existing scheduled dish for this user on this date
ScheduledUserDish::whereDate('date', $this->regenerateDate)
->where('user_id', $this->regenerateUserId)
->delete();
// You could call a specific regeneration method here
// For now, we'll just delete and let the user generate again
$this->showRegenerateModal = false;
$this->generateCalendar(); // Refresh calendar
session()->flash('success', 'Schedule regenerated for the selected date!');
} catch (\Exception $e) {
session()->flash('error', 'Error regenerating schedule: ' . $e->getMessage());
}
}
public function skipDay($date, $userId)
{
try {
// Mark this day as skipped or delete the assignment
ScheduledUserDish::whereDate('date', $date)
->where('user_id', $userId)
->delete();
$this->generateCalendar(); // Refresh calendar
session()->flash('success', 'Day skipped successfully!');
} catch (\Exception $e) {
session()->flash('error', 'Error skipping day: ' . $e->getMessage());
}
}
public function cancel()
{
$this->showRegenerateModal = false;
$this->regenerateDate = null;
$this->regenerateUserId = null;
}
public function getMonthNameProperty()
{
return Carbon::createFromDate($this->currentYear, $this->currentMonth, 1)->format('F Y');
}
}

View file

@ -0,0 +1,202 @@
<?php
namespace App\Livewire\Schedule;
use App\Models\User;
use App\Models\Dish;
use App\Models\Schedule;
use App\Models\ScheduledUserDish;
use Carbon\Carbon;
use Livewire\Component;
class ScheduleGenerator extends Component
{
public $selectedMonth;
public $selectedYear;
public $selectedUsers = [];
public $clearExisting = true;
public $showAdvancedOptions = false;
public $isGenerating = false;
public function mount()
{
$this->selectedMonth = now()->month;
$this->selectedYear = now()->year;
// Select all users by default
$this->selectedUsers = User::where('planner_id', auth()->user()->planner_id)
->pluck('id')
->toArray();
}
public function render()
{
$users = User::where('planner_id', auth()->user()->planner_id)
->orderBy('name')
->get();
$months = [
1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April',
5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August',
9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December'
];
$years = range(now()->year - 1, now()->year + 2);
return view('livewire.schedule.schedule-generator', [
'users' => $users,
'months' => $months,
'years' => $years
]);
}
public function generate()
{
$this->validate([
'selectedUsers' => 'required|array|min:1',
'selectedMonth' => 'required|integer|min:1|max:12',
'selectedYear' => 'required|integer|min:2020|max:2030',
]);
$this->isGenerating = true;
try {
$startDate = Carbon::createFromDate($this->selectedYear, $this->selectedMonth, 1);
$endDate = $startDate->copy()->endOfMonth();
// Clear existing schedule if requested
if ($this->clearExisting) {
ScheduledUserDish::whereBetween('date', [$startDate, $endDate])
->whereIn('user_id', $this->selectedUsers)
->delete();
}
// Get all dishes assigned to selected users
$userDishes = [];
foreach ($this->selectedUsers as $userId) {
$user = User::find($userId);
$dishes = $user->dishes()->get();
if ($dishes->isNotEmpty()) {
$userDishes[$userId] = $dishes->toArray();
}
}
// Generate schedule for each day
$currentDate = $startDate->copy();
while ($currentDate <= $endDate) {
foreach ($this->selectedUsers as $userId) {
// Skip if user already has a dish for this day
if (ScheduledUserDish::where('date', $currentDate->format('Y-m-d'))
->where('user_id', $userId)
->exists()) {
continue;
}
// Get available dishes for this user
if (!isset($userDishes[$userId]) || empty($userDishes[$userId])) {
continue;
}
$availableDishes = $userDishes[$userId];
// Simple random assignment (you can implement more complex logic here)
if (!empty($availableDishes)) {
$randomDish = $availableDishes[array_rand($availableDishes)];
ScheduledUserDish::create([
'user_id' => $userId,
'dish_id' => $randomDish['id'],
'date' => $currentDate->format('Y-m-d'),
'planner_id' => auth()->user()->planner_id,
]);
}
}
$currentDate->addDay();
}
$this->isGenerating = false;
// Emit event to refresh calendar
$this->dispatch('schedule-generated');
session()->flash('success', 'Schedule generated successfully for ' .
$this->getSelectedMonthName() . ' ' . $this->selectedYear);
} catch (\Exception $e) {
$this->isGenerating = false;
session()->flash('error', 'Error generating schedule: ' . $e->getMessage());
}
}
public function regenerateForDate($date)
{
try {
// Clear existing assignments for this date
ScheduledUserDish::whereDate('date', $date)
->whereIn('user_id', $this->selectedUsers)
->delete();
// Regenerate for this specific date
$currentDate = Carbon::parse($date);
foreach ($this->selectedUsers as $userId) {
$user = User::find($userId);
$dishes = $user->dishes()->get();
if ($dishes->isNotEmpty()) {
$randomDish = $dishes->random();
ScheduledUserDish::create([
'user_id' => $userId,
'dish_id' => $randomDish->id,
'date' => $currentDate->format('Y-m-d'),
'planner_id' => auth()->user()->planner_id,
]);
}
}
$this->dispatch('schedule-generated');
session()->flash('success', 'Schedule regenerated for ' . $currentDate->format('M d, Y'));
} catch (\Exception $e) {
session()->flash('error', 'Error regenerating schedule: ' . $e->getMessage());
}
}
public function clearMonth()
{
try {
$startDate = Carbon::createFromDate($this->selectedYear, $this->selectedMonth, 1);
$endDate = $startDate->copy()->endOfMonth();
ScheduledUserDish::whereBetween('date', [$startDate, $endDate])
->whereIn('user_id', $this->selectedUsers)
->delete();
$this->dispatch('schedule-generated');
session()->flash('success', 'Schedule cleared for ' .
$this->getSelectedMonthName() . ' ' . $this->selectedYear);
} catch (\Exception $e) {
session()->flash('error', 'Error clearing schedule: ' . $e->getMessage());
}
}
public function toggleAdvancedOptions()
{
$this->showAdvancedOptions = !$this->showAdvancedOptions;
}
private function getSelectedMonthName()
{
$months = [
1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April',
5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August',
9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December'
];
return $months[$this->selectedMonth];
}
}

View file

@ -0,0 +1,136 @@
<?php
namespace App\Livewire\Users;
use App\Models\User;
use Livewire\Component;
use Livewire\WithPagination;
class UsersList extends Component
{
use WithPagination;
public $showCreateModal = false;
public $showEditModal = false;
public $showDeleteModal = false;
public $editingUser = null;
public $deletingUser = null;
// Form fields
public $name = '';
public $email = '';
public $password = '';
public $password_confirmation = '';
protected $rules = [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|min:8|confirmed',
];
public function render()
{
$users = User::where('planner_id', auth()->user()->planner_id)
->orderBy('name')
->paginate(10);
return view('livewire.users.users-list', [
'users' => $users
]);
}
public function create()
{
$this->reset(['name', 'email', 'password', 'password_confirmation']);
$this->resetValidation();
$this->showCreateModal = true;
}
public function store()
{
$this->validate();
User::create([
'name' => $this->name,
'email' => $this->email,
'password' => bcrypt($this->password),
'planner_id' => auth()->user()->planner_id,
]);
$this->showCreateModal = false;
$this->reset(['name', 'email', 'password', 'password_confirmation']);
session()->flash('success', 'User created successfully.');
}
public function edit(User $user)
{
$this->editingUser = $user;
$this->name = $user->name;
$this->email = $user->email;
$this->password = '';
$this->password_confirmation = '';
$this->resetValidation();
$this->showEditModal = true;
}
public function update()
{
$rules = [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,' . $this->editingUser->id,
];
if ($this->password) {
$rules['password'] = 'min:8|confirmed';
}
$this->validate($rules);
$this->editingUser->update([
'name' => $this->name,
'email' => $this->email,
]);
if ($this->password) {
$this->editingUser->update([
'password' => bcrypt($this->password)
]);
}
$this->showEditModal = false;
$this->reset(['name', 'email', 'password', 'password_confirmation', 'editingUser']);
session()->flash('success', 'User updated successfully.');
}
public function confirmDelete(User $user)
{
$this->deletingUser = $user;
$this->showDeleteModal = true;
}
public function delete()
{
if ($this->deletingUser->id === auth()->id()) {
session()->flash('error', 'You cannot delete your own account.');
$this->showDeleteModal = false;
return;
}
$this->deletingUser->delete();
$this->showDeleteModal = false;
$this->deletingUser = null;
session()->flash('success', 'User deleted successfully.');
}
public function cancel()
{
$this->showCreateModal = false;
$this->showEditModal = false;
$this->showDeleteModal = false;
$this->reset(['name', 'email', 'password', 'password_confirmation', 'editingUser', 'deletingUser']);
}
}

25
backend/.gitignore vendored
View file

@ -1,25 +0,0 @@
/composer.lock
/.composer
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
/auth.json
/.fleet
/.idea
/.nova
/.vscode
/.zed

View file

@ -1,54 +0,0 @@
services:
backend:
build:
context: './vendor/laravel/sail/runtimes/8.4'
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: 'sail-8.4/app'
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
IGNITION_LOCAL_SITES_PATH: '${PWD}'
volumes:
- '.:/var/www/html:Z'
networks:
- sail
depends_on:
- mysql
mysql:
image: 'docker.io/mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: '%'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql:Z'
networks:
- sail
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-p${DB_PASSWORD}'
retries: 3
timeout: 5s
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local

View file

@ -1,17 +0,0 @@
{
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"axios": "^1.7.4",
"concurrently": "^9.0.1",
"laravel-vite-plugin": "^1.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.13",
"vite": "^6.0"
}
}

View file

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View file

@ -1 +0,0 @@
import './bootstrap';

View file

@ -1,7 +0,0 @@
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});

View file

@ -1,20 +0,0 @@
import defaultTheme from 'tailwindcss/defaultTheme';
/** @type {import('tailwindcss').Config} */
export default {
content: [
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
'./storage/framework/views/*.php',
'./resources/**/*.blade.php',
'./resources/**/*.js',
'./resources/**/*.vue',
],
theme: {
extend: {
fontFamily: {
sans: ['Figtree', ...defaultTheme.fontFamily.sans],
},
},
},
plugins: [],
};

View file

@ -12,7 +12,8 @@
"php": "^8.2",
"laravel/framework": "^12.9.2",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.9"
"laravel/tinker": "^2.9",
"livewire/livewire": "^3.7"
},
"require-dev": {
"fakerphp/faker": "^1.23",

186
config/livewire.php Normal file
View file

@ -0,0 +1,186 @@
<?php
return [
/*
|---------------------------------------------------------------------------
| Class Namespace
|---------------------------------------------------------------------------
|
| This value sets the root class namespace for Livewire component classes in
| your application. This value will change where component auto-discovery
| finds components. It's also referenced by the file creation commands.
|
*/
'class_namespace' => 'App\\Livewire',
/*
|---------------------------------------------------------------------------
| View Path
|---------------------------------------------------------------------------
|
| This value is used to specify where Livewire component Blade templates are
| stored when running file creation commands like `artisan make:livewire`.
| It is also used if you choose to omit a component's render() method.
|
*/
'view_path' => resource_path('views/livewire'),
/*
|---------------------------------------------------------------------------
| Layout
|---------------------------------------------------------------------------
| The view that will be used as the layout when rendering a single component
| as an entire page via `Route::get('/post/create', CreatePost::class);`.
| In this case, the view returned by CreatePost will render into $slot.
|
*/
'layout' => 'components.layouts.app',
/*
|---------------------------------------------------------------------------
| Lazy Loading Placeholder
|---------------------------------------------------------------------------
| Livewire allows you to lazy load components that would otherwise slow down
| the initial page load. Every component can have a custom placeholder or
| you can define the default placeholder view for all components below.
|
*/
'lazy_placeholder' => null,
/*
|---------------------------------------------------------------------------
| Temporary File Uploads
|---------------------------------------------------------------------------
|
| Livewire handles file uploads by storing uploads in a temporary directory
| before the file is stored permanently. All file uploads are directed to
| a global endpoint for temporary storage. You may configure this below:
|
*/
'temporary_file_upload' => [
'disk' => null, // Example: 'local', 's3' | Default: 'default'
'rules' => null, // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB)
'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp'
'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1'
'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs...
'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
'mov', 'avi', 'wmv', 'mp3', 'm4a',
'jpg', 'jpeg', 'mpga', 'webp', 'wma',
],
'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs...
],
/*
|---------------------------------------------------------------------------
| Render On Redirect
|---------------------------------------------------------------------------
|
| This value determines if Livewire will run a component's `render()` method
| after a redirect has been triggered using something like `redirect(...)`
| Setting this to true will render the view once more before redirecting
|
*/
'render_on_redirect' => false,
/*
|---------------------------------------------------------------------------
| Eloquent Model Binding
|---------------------------------------------------------------------------
|
| Previous versions of Livewire supported binding directly to eloquent model
| properties using wire:model by default. However, this behavior has been
| deemed too "magical" and has therefore been put under a feature flag.
|
*/
'legacy_model_binding' => false,
/*
|---------------------------------------------------------------------------
| Auto-inject Frontend Assets
|---------------------------------------------------------------------------
|
| By default, Livewire automatically injects its JavaScript and CSS into the
| <head> and <body> of pages containing Livewire components. By disabling
| this behavior, you need to use @livewireStyles and @livewireScripts.
|
*/
'inject_assets' => true,
/*
|---------------------------------------------------------------------------
| Navigate (SPA mode)
|---------------------------------------------------------------------------
|
| By adding `wire:navigate` to links in your Livewire application, Livewire
| will prevent the default link handling and instead request those pages
| via AJAX, creating an SPA-like effect. Configure this behavior here.
|
*/
'navigate' => [
'show_progress_bar' => true,
'progress_bar_color' => '#2299dd',
],
/*
|---------------------------------------------------------------------------
| HTML Morph Markers
|---------------------------------------------------------------------------
|
| Livewire intelligently "morphs" existing HTML into the newly rendered HTML
| after each update. To make this process more reliable, Livewire injects
| "markers" into the rendered Blade surrounding @if, @class & @foreach.
|
*/
'inject_morph_markers' => true,
/*
|---------------------------------------------------------------------------
| Smart Wire Keys
|---------------------------------------------------------------------------
|
| Livewire uses loops and keys used within loops to generate smart keys that
| are applied to nested components that don't have them. This makes using
| nested components more reliable by ensuring that they all have keys.
|
*/
'smart_wire_keys' => false,
/*
|---------------------------------------------------------------------------
| Pagination Theme
|---------------------------------------------------------------------------
|
| When enabling Livewire's pagination feature by using the `WithPagination`
| trait, Livewire will use Tailwind templates to render pagination views
| on the page. If you want Bootstrap CSS, you can specify: "bootstrap"
|
*/
'pagination_theme' => 'tailwind',
/*
|---------------------------------------------------------------------------
| Release Token
|---------------------------------------------------------------------------
|
| This token is stored client-side and sent along with each request to check
| a users session to see if a new release has invalidated it. If there is
| a mismatch it will throw an error and prompt for a browser refresh.
|
*/
'release_token' => 'a',
];

View file

@ -1,55 +1,52 @@
services:
web:
image: nginx:alpine
container_name: dishplanner-nginx
restart: unless-stopped
depends_on:
- backend
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
command: /bin/sh -c "until nslookup backend. ; do sleep 2; done && nginx -g 'daemon off;'"
ports:
- "3000:80"
backend:
image: jochent/dishplanner-backend:v0.2
container_name: dishplanner-backend
restart: unless-stopped
environment:
DB_CONNECTION: mysql
DB_HOST: db
DB_PORT: 3306
DB_DATABASE: dishplanner
DB_USERNAME: dishuser
DB_PASSWORD: dishpass
depends_on:
- db
ports:
- "8080:80"
frontend:
image: jochent/dishplanner-frontend:v0.2
container_name: dishplanner-frontend
restart: unless-stopped
depends_on:
- backend
# ports:
# - "3000:3000"
db:
image: mysql:8.0
container_name: dishplanner-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: dishplanner
MYSQL_USER: dishuser
MYSQL_PASSWORD: dishpass
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
laravel.test:
build:
context: './vendor/laravel/sail/runtimes/8.4'
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: 'sail-8.4/app'
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
IGNITION_LOCAL_SITES_PATH: '${PWD}'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: '%'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
networks:
- sail
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-p${DB_PASSWORD}'
retries: 3
timeout: 5s
networks:
default:
name: dishplanner-net
sail:
driver: bridge
volumes:
sail-mysql:
driver: local

Some files were not shown because too many files have changed in this diff Show more