Tutorial Membuat Toko Online Dari Awal / Buat Perubahan Pada Layout

Ketika kita menggunakan breeze ini, kita hanya diberi dua pilihan layout, yaitu untuk yang sudah login dan yang belum. Nah jika kita ingin menggunakan satu layout di dalam dua case, maka kita perlu memodifikasinya terlebih dahulu. Karena kita memerlukan layout yang sama walau nantinya user tidak login. Seperti misalnya untuk halaman menampilkan list product dan overview nya.

πŸ’…πŸ» Modifikasi Navbar

Maka oleh karena itu, silakan ubah nama dari AuthenticatedLayout menjadi AppLayout, Setelah itu, silakan buat file baru di dalam direktori resources/js/Layouts dengan nama Navbar.jsx, dan dilamanya silakan masukkan kode berikut:

resources/js/Layouts/Navbar.jsx
import { Link, usePage } from '@inertiajs/react';
import ApplicationLogo from '@/Components/ApplicationLogo';
import NavLink from '@/Components/NavLink';
import Dropdown from '@/Components/Dropdown';
import ResponsiveNavLink from '@/Components/ResponsiveNavLink';
import { useState } from 'react';

export default function Navbar() {
    const { auth } = usePage().props;
    const [showingNavigationDropdown, setShowingNavigationDropdown] = useState(false);
    return (
        <nav className='border-b border-gray-100 bg-white'>
            <div className='mx-auto max-w-7xl px-4 sm:px-6 lg:px-8'>
                <div className='flex h-16 justify-between'>
                    <div className='flex'>
                        <div className='flex shrink-0 items-center'>
                            <Link href='/'>
                                <ApplicationLogo className='block h-9 w-auto fill-current text-gray-800' />
                            </Link>
                        </div>

                        <div className='hidden space-x-8 sm:-my-px sm:ml-10 sm:flex'>
                            <NavLink href={'#'} active={false}>
                                Products
                            </NavLink>
                        </div>
                    </div>

                    {auth.user ? (
                        <div className='hidden sm:ml-6 sm:flex sm:items-center'>
                            <div className='relative ml-3'>
                                <Dropdown>
                                    <Dropdown.Trigger>
                                        <span className='inline-flex rounded-md'>
                                            <button
                                                type='button'
                                                className='inline-flex items-center rounded-md border border-transparent bg-white px-3 py-2 text-sm font-medium leading-4 text-gray-500 transition duration-150 ease-in-out hover:text-gray-700 focus:outline-none'>
                                                {auth.user.name}

                                                <svg
                                                    className='-mr-0.5 ml-2 h-4 w-4'
                                                    xmlns='http://www.w3.org/2000/svg'
                                                    viewBox='0 0 20 20'
                                                    fill='currentColor'>
                                                    <path
                                                        fillRule='evenodd'
                                                        d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z'
                                                        clipRule='evenodd'
                                                    />
                                                </svg>
                                            </button>
                                        </span>
                                    </Dropdown.Trigger>

                                    <Dropdown.Content>
                                        <Dropdown.Link href={route('dashboard')}>Dashboard</Dropdown.Link>
                                        <Dropdown.Link href={route('profile.edit')}>Profile</Dropdown.Link>
                                        <Dropdown.Link href={route('logout')} method='post' as='button'>
                                            Log Out
                                        </Dropdown.Link>
                                    </Dropdown.Content>
                                </Dropdown>
                            </div>
                        </div>
                    ) : (
                        <div className='hidden space-x-8 sm:-my-px sm:ml-10 sm:flex'>
                            <NavLink href={route('login')} active={route().current('login')}>
                                Login
                            </NavLink>
                            <NavLink href={route('register')} active={route().current('register')}>
                                Register
                            </NavLink>
                        </div>
                    )}

                    <div className='-mr-2 flex items-center sm:hidden'>
                        <button
                            onClick={() => setShowingNavigationDropdown((previousState) => !previousState)}
                            className='inline-flex items-center justify-center rounded-md p-2 text-gray-400 transition duration-150 ease-in-out hover:bg-gray-100 hover:text-gray-500 focus:bg-gray-100 focus:text-gray-500 focus:outline-none'>
                            <svg className='h-6 w-6' stroke='currentColor' fill='none' viewBox='0 0 24 24'>
                                <path
                                    className={!showingNavigationDropdown ? 'inline-flex' : 'hidden'}
                                    strokeLinecap='round'
                                    strokeLinejoin='round'
                                    strokeWidth='2'
                                    d='M4 6h16M4 12h16M4 18h16'
                                />
                                <path
                                    className={showingNavigationDropdown ? 'inline-flex' : 'hidden'}
                                    strokeLinecap='round'
                                    strokeLinejoin='round'
                                    strokeWidth='2'
                                    d='M6 18L18 6M6 6l12 12'
                                />
                            </svg>
                        </button>
                    </div>
                </div>
            </div>

            <div className={(showingNavigationDropdown ? 'block' : 'hidden') + ' sm:hidden'}>
                <ResponsiveNavLink href='/' active={false}>
                    Home
                </ResponsiveNavLink>
                {auth.user ? (
                    <>
                        <div className='space-y-1 pb-3 pt-2'>
                            <ResponsiveNavLink href={route('dashboard')} active={route().current('dashboard')}>
                                Dashboard
                            </ResponsiveNavLink>
                        </div>

                        <div className='border-t border-gray-200 pb-1 pt-4'>
                            <div className='px-4'>
                                <div className='text-base font-medium text-gray-800'>{auth.user.name}</div>
                                <div className='text-sm font-medium text-gray-500'>{auth.user.email}</div>
                            </div>

                            <div className='mt-3 space-y-1'>
                                <ResponsiveNavLink href={route('dashboard')}>Dashboard</ResponsiveNavLink>
                                <ResponsiveNavLink href={route('profile.edit')}>Profile</ResponsiveNavLink>
                                <ResponsiveNavLink method='post' href={route('logout')} as='button'>
                                    Log Out
                                </ResponsiveNavLink>
                            </div>
                        </div>
                    </>
                ) : (
                    <>
                        <div className='space-y-1 pb-3 pt-2'>
                            <ResponsiveNavLink href={route('login')} active={route().current('login')}>
                                Login
                            </ResponsiveNavLink>
                            <ResponsiveNavLink href={route('register')} active={route().current('register')}>
                                Register
                            </ResponsiveNavLink>
                        </div>
                    </>
                )}
            </div>
        </nav>
    );
}

Sangat panjang memang, itu hanya karena navbar tersebut sudah responsive, jadi ketika di buka di mobile maka akan berubah menjadi menu dropdown. Sebelum lanjut, saya akan menunjukkan dulu bahwa di dalam folder resources/js/Layouts strukturnya seperti ini:

resources/js/Layouts
β”œβ”€β”€ AppLayout.jsx
β”œβ”€β”€ GuestLayout.jsx
└── Navbar.jsx

πŸ’…πŸ» Setup AppLayout

Buka file AppLayout.jsx dan silakan modifikasi isinya menjadi seperti ini:

resources/js/Layouts/AppLayout.jsx
import Navbar from '@/Layouts/Navbar';

export default function AppLayout({ header, children }) {
    return (
        <div className='min-h-screen bg-gray-100'>
            <Navbar />

            {header && (
                <header className='bg-white shadow'>
                    <div className='mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8'>{header}</div>
                </header>
            )}

            <main>{children}</main>
        </div>
    );
}

πŸ’…πŸ» Modifikasi Dashboard

Kita akan modifikasi file Dashboard.jsx nya, namun sebelum itu, silakan buat file Container.jsx tepat pada folder resources/js/Components seperti ini:

resources/js/Components/Container.jsx
export default function Container({ children }) {
    return <div className='mx-auto max-w-2xl px-4 sm:px-6 lg:max-w-7xl lg:px-8'>{children}</div>;
}

Dengan begitu, nantinya kita bisa menggunakan di beberapa komponen yang membutuhkannya termasuk dashboard kita. Teman-teman bisa buka file Dashboard.jsx, kemudian silakan modifikasi isi dari dalamnya menjadi seperti:

resources/js/Pages/Dashboard.jsx
import AppLayout from '@/Layouts/AppLayout';
import { Head } from '@inertiajs/react';
import Home from '@/Pages/Home';
import Container from '@/Components/Container';

export default function Dashboard({ auth }) {
    return (
        <>
            <Head title='Dashboard' />

            <div className='py-12'>
                <Container>
                    <div className='overflow-hidden bg-white shadow-sm sm:rounded-lg'>
                        <div className='p-6 text-gray-900'>You're logged in!</div>
                    </div>
                </Container>
            </div>
        </>
    );
}

Dashboard.layout = (page) => (
    <AppLayout
        header={<h2 className='text-xl font-semibold leading-tight text-gray-800'>Dashboard</h2>}
        children={page}
    />
);

Baik, sekarang pastikan bahwa teman-teman sudah menjalankan npm run dev dan php artisan serve. Dan sekarang silakan buka di browser, daftarkan akun baru, dan login. Maka teman-teman akan di arahkan ke halaman dashboard. Dan jika memang semua berjalan dengan baik, maka hasil akhir akan seperti ini: dashboard

🍯 Dashboard dan Home

Setelah itu, mari kita buat buat dua controller untuk halaman utama dan juga dashboard, silakan buka terminal dan jalankan perintah berikut:

php artisan make:controller HomeController -i
php artisan make:controller DashboardController -i

Setelah itu, silakan buka file routes/web.php untuk membuat route dari keduanya, silakan modifikasi isinya menjadi seperti ini:

routes/web.php
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;

Route::get('/', HomeController::class)->name('home');

Route::get('dashboard', DashboardController::class)->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';

Jika sudah, silakan buka file HomeController.php dan silakan modifikasi isinya menjadi seperti ini:

app/Http/Controllers/HomeController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    /**
     * Handle the incoming request.
     */
    public function __invoke(Request $request)
    {
        return inertia('Home');
    }
}

Sebelum kita lanjut membuat view nya, mari kita langsung modifikasi apa yang ada di DashboardController.php dan masukkan syntak berikut ini:

app/Http/Controllers/DashboardController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class DashboardController extends Controller
{
    /**
     * Handle the incoming request.
     */
    public function __invoke(Request $request)
    {
        return inertia('Dashboard');
    }
}

πŸ₯› View untuk Home

Karena kita sudah memiliki view untuk dashboard, maka kita hanya akan membuat Home.jsx pada folder resources/js/Pages. Silakan buat file baru bernama Home.jsx dan silakan masukkan syntak berikut:

resources/js/Pages/Home.jsx
import { Head } from '@inertiajs/react';
import AppLayout from '@/Layouts/AppLayout';
import Container from '@/Components/Container';

export default function Home({ products }) {
    return (
        <>
            <Head title='Welcome to Online Store' />
            <Container>
                <div className='py-8 lg:py-16'>
                    <h2 className='text-2xl font-bold tracking-tight text-gray-900'>Trending Products</h2>
                </div>
            </Container>
        </>
    );
}

Home.layout = (page) => (
    <AppLayout
        header={<h2 className='text-xl font-semibold leading-tight text-gray-800'>Start Shopping</h2>}
        children={page}
    />
);

Jika sudah, harusnya kita sudah ready untuk lanjut ke langkah berikutnya.

Prev