building a website with laravel,react js and inertia js

 inertiajs

laravel new inerita

https://www.linkedin.com/learning/building-a-website-with-laravel-react-js-and-inertia/creating-an-inertia-navigation

laravel breesze

react with inertia

composer create-project --prefer-dist laravel/laravel my-inertia-app

cd my-inertia-app

for vue 3
composer require inertiajs/inertia-laravel
npm install @inertiajs/inertia @inertiajs/inertia-vue3
npm install @vitejs/plugin-vue

for react

composer require inertiajs/inertia-laravel
npm install @inertiajs/inertia @inertiajs/inertia-react

php artisan make:model Post -a

npm install

some  starterr kits

composer require laravel/breeze --dev

php artisan breeze:install

or php artisan breeze:install --react or --vue or --livewire
reac twith inertia

dark mode 

php unit testing




what is valet link
some will be installed at web.php

<?php

use App\Http\Controllers\ProfileController;
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;

Route::get('/', function () {
return Inertia::render('Welcome', [
'canLogin' => Route::has('login'),
'canRegister' => Route::has('register'),
'laravelVersion' => Application::VERSION,
'phpVersion' => PHP_VERSION,
]);
});

Route::get('/dashboard', function () {
return Inertia::render('Dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');

Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});

require __DIR__.'/auth.php';

=
AFTER THAT 
Route::resource('posts', PostController::class);

now we craete web and home pages 

in web.php 
short hadn routes which dontened controller

Route::inertia('about','About')->name('about');

route::view

in app.jsx already created when install breeze
import './bootstrap';
import '../css/app.css';

import { createRoot } from 'react-dom/client';
import { createInertiaApp } from '@inertiajs/react';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';

const appName = import.meta.env.VITE_APP_NAME || 'Laravel';

createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.jsx`, import.meta.glob('./Pages/**/*.jsx')),
setup({ el, App, props }) {
const root = createRoot(el);

root.render(<App {...props} />);
},
progress: {
color: '#4B5563',
},
});



resources/js/pages/About.jsx

copy below code 
export default function About() {

return (

<div>

<h1>About Page</h1>

<p>Welcome to the about page!</p>

</div>

);


}

error like below when reach about



for that purpise we have to run npm run dev

web.php

Route::get('/', function () {
return Inertia::render('Home', [
'canLogin' => Route::has('login'),
'canRegister' => Route::has('register'),
'laravelVersion' => Application::VERSION,
'phpVersion' => PHP_VERSION,
]);
});

remove the unnecesary routes 
Route::get('/', function () {
return Inertia::render('Home');
});

create home.jsx
resources/js/pages/About.jsx
\


http://127.0.0.1:8000/

Home Page

Welcome to the about page!


create a navigatgion file in components fo;der 

navigation.jsx

resources/js/components/navigation.jsx


write code clike below 

import { Link } from "@inertiajs/react";

export default function Navigation() {
return (
<nav className="pb-5 mb-5 border-b">
<ul className="flex justify-end space-x-5">
<li>
<Link href={route("about")}>About</Link>
</li>
</ul>
</nav>
);
}


we dont have authentication, 
so u can use guestlayout by started kit
resources/js/layouts/guestlayout.jsx

npm install @inertiajs/react

import ApplicationLogo from '@/Components/ApplicationLogo';
import { Link } from '@inertiajs/react';

export default function Guest({ children }) {
return (
<div className="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
<div>
<Link href="/">
<ApplicationLogo className="w-20 h-20 fill-current text-gray-500" />
</Link>
</div>

<div className="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg">
{children}
</div>
</div>
);
}


=
add navigation 

import Navigation from "@/Components/Navigation"
export default function Guest({ children }) {
return (
<div className="w-3/5 mx-auto my-10">
<Navigation />
<div >
{children}
</div>
</div>
);
}


 


lets change the titile

resources/views/app.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title inertia>{{ config('app.name', 'Laravel') }}</title>

<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />

<!-- Scripts -->
@routes
@viteReactRefresh
@vite(['resources/js/app.jsx', "resources/js/Pages/{$page['component']}.jsx"])
@inertiaHead
</head>
<body class="font-sans antialiased">
@inertia
</body>
</html>


resources/js/app.jsx

title: (title) => `${title} - ${appName}`,

change to below 
createInertiaApp({
title: (title) => `inertia and react`,


app.jsx
title: (title) => `${title} - ${appName}`,


guestlayout.jsx

import Navigation from "@/Components/Navigation"; // Ensure the path is correct
import { Head } from '@inertiajs/react';

export default function Guest({ children }) {
return (
<>
<Head title="linkedin learning" />
<div className="w-3/5 mx-auto my-10">
<Navigation />
<div>
{children}
</div>
</div>
</>
);
}


=
title displayas linked-in learning -laravel

in app.blade.php


<title inertia>{{ config('app.name', 'Laravel') }}</title>


=
resoources/js/pages/home.jsx
import GuestLayout from '@/Layouts/GuestLayout';
export default function Home({ posts }) {

return (
<GuestLayout>
<div>

<h1>Home Page</h1>

<p>Welcome to the Home page!</p>
<Posts posts={posts} />
</div>
</GuestLayout>
);


}

=


posts/oindex.jsx

import { Link } from '@inertiajs/react'; // Ensure Link is correctly imported from @inertiajs/react

export default function Index() {
const posts = []; // Replace with your actual posts data
const handleDeletePost = (postId) => {
// Add your delete logic here
};

return (
<div>
<div className='flex'>
<Link to="/posts/create" className="px-4 py-2">
Create New Post
</Link>
</div>
{posts && posts.map((post) => (
<div key={post.id} className="p-5 my-5 border rounded-md shadow-sm text-left">
<h2 className="mb-5 font-bold">{post.title}</h2>
<p>{post.body}</p>
<Link
to={`posts/update/${post.id}`}
state={post}
className="px-4 py-2 text-white bg-purple-500 rounded-md hover:bg-purple-600"
>
Edit Post
</Link>
<button
onClick={() => handleDeletePost(post.id)}
className="px-4 py-2 text-white bg-gray-400 rounded-md hover:bg-gray-500"
>
Delete Post
</button>
</div>
))}
</div>
);
}



=

resources/js/pages/home.jsx
import GuestLayout from '@/Layouts/GuestLayout';
import Posts from '@/Pages/Posts/Index'; // Import the Index component as Posts

export default function Home({ posts }) {
return (
<GuestLayout>
<div>
<h1>Home Page</h1>
<p>Welcome to the Home page!</p>
<Posts posts={posts} /> {/* Pass the posts prop to the Posts component */}
</div>
</GuestLayout>
);
}


===
create.jsx copied from react 
modifield import and 
const {data, setData, post, processing, errors} = useForm({
author: "",
title: "",
body: "",
});
// processing => form submission process
// setdata=>update the form data
// errors => an y errors,


and 
value={data.body}
onChange={(e) => setData("body",e.target.value)}
=
create submit button 
<button
type="submit"
disabled={processing}
className="px-4 py-2 mt-4 ml-4 text-white bg-purple-500 rounded-md hover:bg-purple-600"
>
Create Post
</button>

=
cancel 
<Link
href={route('home')}
className="inline-block px-4 py-2 mt-4 text-black border rounded-md hover:bg-gray-200"
>
Cancel
</Link>

postcopntrller
public function index()
{
return Inertia::render("Home",[
'posts'=>Post::orderByDesc('created_at')->get(),
]);

composer require inertiajs/inertia-laravel
Route::resource('posts', PostController::class);
=
pages/posts/index.jsx
changed route , 
import { Link } from '@inertiajs/react'; // Ensure Link is correctly imported from @inertiajs/react
import { useEffect } from 'react';
export default function Index({ posts }) {
const handleDeletePost = (postId) => {
// Add your delete logic here
};
useEffect(() => {
console.log('s',posts); // Log the data received by the component
}, [posts]);

return (
<div>
<div className='flex'>
<Link href={route("posts.create")} className="px-4 py-2">
Create New Post
</Link>
</div>
{posts && posts.map((post) => (
<div key={post.id} className="p-5 my-5 border rounded-md shadow-sm text-left">
<Link
href={route("posts.show", post.id)}
className="px-4 py-2 bg-purple-500 rounded-md hover:bg-purple-600"
>
<h2 className="mb-5 font-bold">{post.title}</h2>
</Link>
<p>{post.title}</p>
<Link
href={route("posts.edit", post.id)}
className="px-4 py-2 text-white bg-purple-500 rounded-md hover:bg-purple-600"
>
Edit Post
</Link>
<button
onClick={() => handleDeletePost(post.id)}
className="px-4 py-2 text-white bg-gray-400 rounded-md hover:bg-gray-500"
>
Delete Post
</button>
</div>
))}
</div>
);
}


==
directly calling route names

postcontroller 
public function index()
{
return Inertia::render("Home",[
'posts'=>Post::orderByDesc('created_at')->get(),
]);
==
now we modified route
from below which has postcontroller index that only fetch
at home page working
Route::resource('posts', PostController::class)->except('index');
Route::get('/', [PostController::class,'index'])->name('home');


home.jsx

import GuestLayout from '@/Layouts/GuestLayout';
import Posts from '@/Pages/Posts/Index'; // Import the Index component as Posts

export default function Home({ posts }) {
console.log('Home component posts:', posts);
return (
<GuestLayout>
<div>
<h1>Home Page</h1>
<p>Welcome to the Home page!</p>
<Posts posts={posts} /> {/* Pass the posts prop to the Posts component */}
</div>
</GuestLayout>
);
}

=

now all posts showign at home

this api is inside and js files is inside , so no need of axios, we can send directly
NOW CAREATE FORM

public function create()
{
return Inertia::render('Posts/Create');
}

STORE
public function store(StorePostRequest $request)
{
$data = $request->validated();
$post=Post::create($data);
$data=Post::query();
return redirect()->route('home');
=
CREATE.JSX


import { Link, useForm } from '@inertiajs/react';
import GuestLayout from '@/Layouts/GuestLayout';

export default function Create() {
const {data, setData, post, processing, errors} = useForm({
author: "",
title: "",
body: "",
});
// processing => form submission process
// setdata=>update the form data
// errors => an y errors,

const handleSubmit = async (e) => {
e.preventDefault();
post(route("posts.store"));
};
return (
<GuestLayout>
<form onSubmit={handleSubmit}>
<div className="flex flex-col space-y-8 text-left">
<h1 className="mx-auto text-xl">Create a new post</h1>
<label>
Title
<input
type="text"
value={data.title}
onChange={(e) => setData("title",e.target.value)}
className="block w-full rounded-md border-0 p-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-purple-200 sm:text-sm sm:leading-6"
/>
</label>

<label>
Author
<input
type="text"
value={data.author}
onChange={(e) => setData("author",e.target.value)}
className="block w-full rounded-md border-0 p-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-purple-200 sm:text-sm sm:leading-6"
/>
</label>

<label>
Main content
<textarea
value={data.body}
onChange={(e) => setData("body",e.target.value)}
className="block w-full rounded-md border-0 p-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-purple-200 sm:text-sm sm:leading-6"
/>
</label>
</div>

<div className="flex">
<Link
href={route('home')}
className="inline-block px-4 py-2 mt-4 text-black border rounded-md hover:bg-gray-200"
>
Cancel
</Link>
<button
type="submit"
disabled={processing}
className="px-4 py-2 mt-4 ml-4 text-white bg-purple-500 rounded-md hover:bg-purple-600"
>
Create Post
</button>
</div>
</form>
</GuestLayout>
);
};

=


DISPLAYING SIGNLE POST

public function show(Post $post)
{
return Inertia::render('Posts/Show', [
'post' => $post
]);
}


=
show.jsx

import GuestLayout from '@/Layouts/GuestLayout';
import { Link} from '@inertiajs/react';
import { useEffect } from 'react';
export default function Show({post}) {
// useEffect(() => {
// console.log('s',post); // Log the data received by the component
// }, [post]);

return (
<GuestLayout>
<Link
href={route('home')}
className="inline-block px-4 py-2 mt-4 text-black border rounded-md hover:bg-gray-200"
>
Home
</Link>
<div>
<div className='flex flex-col space-y-10'>
<h1 className="mx-auto">{post.title}</h1>
</div>
</div>
</GuestLayout>
);
}


=
update post
public function edit(Post $post)
{
return Inertia::render('Posts/Edit', [
'post' => $post
]);

=
public function update(UpdatePostRequest $request, Post $post)
{
$post->update($request->validated());
return redirect()->route('home');
=
import { Link, useForm } from '@inertiajs/react';
import GuestLayout from '@/Layouts/GuestLayout';

export default function Edit({post}) {
const {data, setData, put, processing, errors} = useForm({
title: post.title || "",
});
// processing => form submission process
// setdata=>update the form data
// errors => an y errors,

const handleSubmit = async (e) => {
e.preventDefault();
put(route("posts.update",post.id));
};
return (
<GuestLayout>
<form onSubmit={handleSubmit}>
<div className="flex flex-col space-y-8 text-left">
<h1 className="mx-auto text-xl">Create a new post</h1>
<label>
Title
<input
type="text"
value={data.title}
onChange={(e) => setData("title",e.target.value)}
className="block w-full rounded-md border-0 p-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-purple-200 sm:text-sm sm:leading-6"
/>
</label>

</div>

<div className="flex">
<Link
href={route('home')}
className="inline-block px-4 py-2 mt-4 text-black border rounded-md hover:bg-gray-200"
>
Cancel
</Link>
<button
type="submit"
disabled={processing}
className="px-4 py-2 mt-4 ml-4 text-white bg-purple-500 rounded-md hover:bg-purple-600"
>
update
</button>
</div>
</form>
</GuestLayout>
);
};
=

delete post 


ublic function destroy(Post $post)
{
$post->delete();
return redirect()->route('home');

=
import { Link,router } from '@inertiajs/react'; // Ensure Link is correctly imported from @inertiajs/react
=
function deletePost(id)
{
router.delete(route("posts.destroy",id));
}
=
<button
onClick={() => deletePost(post.id)}
className="px-4 py-2 text-white bg-gray-400 rounded-md hover:bg-gray-500"
>
Delete Post
</button>
=

flash message

inertia shared data
allow access to data on numeroouse pages, eg: user name
enable in handleinertiarequests middlware
displa  on page using usepage().props


https://inertiajs.com/shared-data

handleinertiarequest.php

write flash in share funciton 
public function share(Request $request): array
{
return [
...parent::share($request),
'auth' => [
'user' => $request->user(),
],
'flash'=>[
'message' => fn() => $request->session()->get('message')
],
];
}

=
then write 
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('home')->with('message','Post Deleted');

=


import usepage 
import { Link,router, usePage} from '@inertiajs/react';

=
const {flash } = usePage().props;
console.log('s',usePage().props);
=

display on page this flassh message on page
{flash.message && (
<div className="p-5">{flash.message}</div>
)}
=
index.jsx
import { Link,router, usePage} from '@inertiajs/react'; // Ensure Link is correctly imported from @inertiajs/react
import { useEffect } from 'react';
export default function Index({ posts }) {
const {flash } = usePage().props;
console.log('s',usePage().props);
const handleDeletePost = (postId) => {
// Add your delete logic here
};
function deletePost(id)
{
router.delete(route("posts.destroy",id));
}
// useEffect(() => {
// console.log('s',posts); // Log the data received by the component
// }, [posts]);

return (
<div>
{flash.message && (
<div className="p-5">{flash.message}</div>
)}
=

testing (cypress, laravel dusk)
data validation (laravel precognition)

@larabellesphp, www.larabelles.com
@zuzana_kunckova
www.zuzana-k.com



=

Event listening in react

 How we can listen to som eevents some envents fire like click or automatically user enters into input button , that is event on word type i...