404 Not Found

404 Not Found


nginx

Phase 1 Comprehensive Exercise—ShopMetrics Landing Page

Phase 1 Comprehensive Practice is a "Final Review"—it brings together everything you've learned in the first six lessons to deliver a real, fully functional landing page.

1. What You'll Learn


2. Bob's Phase 1 Acceptance Story

(1) Pain Point: Even after completing Lesson 7, I still can't build a complete page

Alice has finished the first six lessons, but while she understands each concept on its own, she gets confused when they're put together—how does routing connect to controllers? How does a controller pass data to a Blade? How do you choose between layout inheritance and components? Bob said, "It's the difference between learning to swim and actually getting in the water—you've watched seven theory lessons, but you haven't swum 25 meters yet."

(2) Solutions to the Comprehensive Exercises

This lesson ties together routes, views, controllers, Blade components, and environment configuration to build a complete, fully functional ShopMetrics landing page from scratch—this will be your first hands-on project.

BASH
# After this lesson, you will have:
# - A landing page with hero section
# - A pricing page with plan cards
# - A dashboard layout with sidebar
# - Reusable Blade components
# - Working database connection

(3) Revenue

After completing the comprehensive exercise, Alice independently built the ShopMetrics landing page, and all five pages passed acceptance testing. Bob said, "The difference between 'understanding it' and 'implementing it' is just one comprehensive exercise."


3. Routing Blueprint Design

(1) Page Layout

100%
graph LR
    A["/ (Home)"] --> B["/pricing (Pricing)"]
    A --> C["/about (About)"]
    A --> D["/contact (Contact)"]
    A --> E["/dashboard (Dashboard)"]
    E --> F["/dashboard/shops"]
    E --> G["/dashboard/analytics"]

(2) Route Definitions

PHP
// routes/web.php
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::get('/pricing', [PricingController::class, 'index'])->name('pricing');
Route::get('/about', [AboutController::class, 'index'])->name('about');
Route::get('/contact', [ContactController::class, 'create'])->name('contact.create');
Route::post('/contact', [ContactController::class, 'store'])->name('contact.store');

Route::middleware('auth')->prefix('dashboard')->name('dashboard.')->group(function () {
    Route::get('/', [DashboardController::class, 'index'])->name('index');
    Route::resource('shops', Dashboard\ShopController::class);
});
Page Route Controller Middleware
Home GET / HomeController None
Pricing GET /pricing PricingController None
About GET /about AboutController None
Contact GET+POST /contact ContactController None
Dashboard GET /dashboard DashboardController auth

(1) ▶ Example: Create all controllers

BASH
php artisan make:controller HomeController
php artisan make:controller PricingController
php artisan make:controller AboutController
php artisan make:controller ContactController
php artisan make:controller Dashboard/DashboardController
php artisan make:controller Dashboard/ShopController --resource

Output:

TEXT
# Command executed successfully

4. Layout and Component Design

(1) Layout Hierarchy

TEXT
layouts/app.blade.php        ← Main layout (navbar + footer)
├── layouts/dashboard.blade.php  ← Dashboard layout (sidebar + content)
│   └── dashboard/analytics.blade.php
└── home/index.blade.php     ← Landing page

(2) List of Components

Component Type File Purpose
<x-navbar> Anonymous components/navbar.blade.php Site-wide Navigation Bar
<x-footer> Anonymous components/footer.blade.php Site-wide Footer
<x-hero> Anonymous components/hero.blade.php Home Page Hero Area
<x-plan-card> Anonymous components/plan-card.blade.php Pricing Card
<x-stat-card> Anonymous components/stat-card.blade.php Dashboard Statistics Card
<x-sidebar> Anonymous components/sidebar.blade.php Dashboard Sidebar

(1) ▶ Example: Creating a Blade Component

BASH
# Create component files manually
mkdir -p resources/views/components
touch resources/views/components/navbar.blade.php
touch resources/views/components/footer.blade.php
touch resources/views/components/hero.blade.php
touch resources/views/components/plan-card.blade.php
touch resources/views/components/stat-card.blade.php
touch resources/views/components/sidebar.blade.php

Output:

TEXT
# Command executed successfully

5. Core Layout and Component Implementation

(1) Main Layout

HTML
<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'ShopMetrics') — E-commerce Analytics</title>
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="bg-gray-50 text-gray-900">
    <x-navbar />
    <main>
        @yield('content')
    </main>
    <x-footer />
</body>
</html>

(2) Navigation Bar Component

HTML
<!-- resources/views/components/navbar.blade.php -->
<nav class="bg-white shadow-sm" x-data="{ open: false }">
    <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="flex justify-between h-16">
            <a href="{{ route('home') }}" class="flex items-center font-bold text-xl text-blue-600">
                ShopMetrics
            </a>
            <div class="hidden md:flex items-center space-x-6">
                <a href="{{ route('pricing') }}" class="text-gray-600 hover:text-gray-900">Pricing</a>
                <a href="{{ route('about') }}" class="text-gray-600 hover:text-gray-900">About</a>
                @auth
                    <a href="{{ route('dashboard.index') }}" class="btn-primary">Dashboard</a>
                @else
                    <a href="{{ route('login') }}" class="text-gray-600 hover:text-gray-900">Login</a>
                    <a href="{{ route('register') }}" class="btn-primary">Sign Up</a>
                @endauth
            </div>
            <button @click="open = !open" class="md:hidden">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path x-show="!open" d="M4 6h16M4 12h16M4 18h16"/>
                    <path x-show="open" d="M6 18L18 6M6 6l12 12"/>
                </svg>
            </button>
        </div>
        <div x-show="open" class="md:hidden py-2 space-y-2">
            <a href="{{ route('pricing') }}" class="block py-2 text-gray-600">Pricing</a>
            @auth
                <a href="{{ route('dashboard.index') }}" class="block py-2 btn-primary">Dashboard</a>
            @else
                <a href="{{ route('login') }}" class="block py-2 text-gray-600">Login</a>
                <a href="{{ route('register') }}" class="block py-2 btn-primary">Sign Up</a>
            @endauth
        </div>
    </div>
</nav>

(3) Hero Component

HTML
<!-- resources/views/components/hero.blade.php -->
@props(['title', 'subtitle', 'cta_text' => 'Get Started', 'cta_route' => 'register'])

<section class="bg-gradient-to-r from-blue-600 to-indigo-700 text-white py-20">
    <div class="max-w-7xl mx-auto px-4 text-center">
        <h1 class="text-4xl md:text-6xl font-bold mb-6">{{ $title }}</h1>
        <p class="text-xl md:text-2xl mb-8 text-blue-100">{{ $subtitle }}</p>
        <a href="{{ route($cta_route) }}" class="bg-white text-blue-600 px-8 py-3 rounded-lg font-semibold hover:bg-blue-50 transition">
            {{ $cta_text }}
        </a>
    </div>
</section>

(1) ▶ Example: Pricing Card Component

HTML
<!-- resources/views/components/plan-card.blade.php -->
@props(['plan', 'popular' => false])

<div class="bg-white rounded-xl shadow-lg p-8 {{ $popular ? 'ring-2 ring-blue-500 relative' : '' }}">
    @if($popular)
        <span class="absolute -top-3 left-1/2 -translate-x-1/2 bg-blue-500 text-white px-4 py-1 rounded-full text-sm font-semibold">
            Most Popular
        </span>
    @endif
    <h3 class="text-xl font-bold mb-2">{{ $plan['name'] }}</h3>
    <div class="mb-6">
        <span class="text-4xl font-bold">${{ $plan['price'] }}</span>
        <span class="text-gray-500">/month</span>
    </div>
    <ul class="space-y-3 mb-8">
        @foreach($plan['features'] as $feature)
            <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
                    <path d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"/>
                </svg>
                {{ $feature }}
            </li>
        @endforeach
    </ul>
    <a href="{{ route('register') }}" class="{{ $popular ? 'btn-primary' : 'btn-secondary' }} w-full text-center block">
        Choose {{ $plan['name'] }}
    </a>
</div>

Output:

TEXT
// Execution Successful

6. Controller Implementation

(1) ▶ Example: HomeController and PricingController

PHP
// app/Http/Controllers/HomeController.php
class HomeController extends Controller
{
    public function index(): View
    {
        $features = [
            ['icon' => 'chart', 'title' => 'Real-time Analytics', 'desc' => 'Track sales, orders and revenue in real-time.'],
            ['icon' => 'users', 'title' => 'Multi-tenant', 'desc' => 'Separate data for each e-commerce store.'],
            ['icon' => 'bell', 'title' => 'Smart Alerts', 'desc' => 'Get notified when key metrics change.'],
        ];
        return view('home.index', compact('features'));
    }
}

// app/Http/Controllers/PricingController.php
class PricingController extends Controller
{
    public function index(): View
    {
        $plans = [
            ['name' => 'Starter', 'price' => 29, 'features' => ['5 Shops', '1K Orders/month', 'Basic Analytics', 'Email Support']],
            ['name' => 'Pro', 'price' => 79, 'features' => ['25 Shops', '10K Orders/month', 'Advanced Analytics', 'Priority Support', 'API Access']],
            ['name' => 'Enterprise', 'price' => 199, 'features' => ['Unlimited Shops', 'Unlimited Orders', 'Custom Analytics', 'Dedicated Support', 'API + Webhooks', 'SSO']],
        ];
        return view('pricing.index', compact('plans'));
    }
}

Output:

TEXT
// Execution Successful

(2) ▶ Example: DashboardController

PHP
// app/Http/Controllers/Dashboard/DashboardController.php
class DashboardController extends Controller
{
    public function index(): View
    {
        $user = auth()->user();
        $tenant = $user->tenant;

        $stats = [
            ['label' => 'Total Revenue', 'value' => '$' . number_format($tenant->revenue ?? 0), 'trend' => 12.5],
            ['label' => 'Active Shops', 'value' => $tenant->shops()->count(), 'trend' => 3.2],
            ['label' => 'Orders Today', 'value' => $tenant->orders()->today()->count(), 'trend' => -2.1],
        ];

        return view('dashboard.index', compact('tenant', 'stats'));
    }
}

Output:

TEXT
// Execution Successful

7. Environment Setup and Database

BASH
# .env — Configure MySQL for ShopMetrics
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=shopmetrics
DB_USERNAME=root
DB_PASSWORD=secret

# Generate app key and run migrations
php artisan key:generate
php artisan migrate

# Install Breeze for auth scaffolding
composer require laravel/breeze --dev
php artisan breeze:install blade
npm install && npm run build
Step Command Function
1 key:generate Generate APP_KEY
2 migrate Create a Data Table
3 breeze:install Generate Login/Registration Page
4 npm run build Compile front-end assets

8. Comprehensive Example: ShopMetrics Landing Page Home

HTML
<!-- ============================================
     Comprehensive: ShopMetrics Landing Page
     Covers: layout, components, routes, data passing
     ============================================ -->

<!-- resources/views/home/index.blade.php -->
@extends('layouts.app')

@section('title', 'ShopMetrics — E-commerce Analytics Platform')

@section('content')
    <!-- Hero Section -->
    <x-hero
        title="Track Your E-commerce Performance"
        subtitle="Real-time analytics for multi-tenant e-commerce platforms. Monitor revenue, orders, and customer insights — all in one dashboard."
        cta_text="Start Free Trial"
        cta_route="register"
    />

    <!-- Features Section -->
    <section class="py-20 bg-white">
        <div class="max-w-7xl mx-auto px-4">
            <h2 class="text-3xl font-bold text-center mb-12">Why ShopMetrics?</h2>
            <div class="grid md:grid-cols-3 gap-8">
                @foreach($features as $feature)
                    <div class="text-center p-6">
                        <div class="w-12 h-12 bg-blue-100 rounded-lg mx-auto mb-4 flex items-center justify-center">
                            <span class="text-blue-600 text-2xl">
                                @if($feature['icon'] === 'chart')📈@elseif($feature['icon'] === 'users')👥@else🔔@endif
                            </span>
                        </div>
                        <h3 class="text-xl font-semibold mb-2">{{ $feature['title'] }}</h3>
                        <p class="text-gray-600">{{ $feature['desc'] }}</p>
                    </div>
                @endforeach
            </div>
        </div>
    </section>

    <!-- CTA Section -->
    <section class="py-16 bg-gray-100">
        <div class="max-w-4xl mx-auto text-center px-4">
            <h2 class="text-3xl font-bold mb-4">Ready to grow your business?</h2>
            <p class="text-gray-600 mb-8">Join 500+ merchants who trust ShopMetrics for their analytics.</p>
            <div class="flex gap-4 justify-center">
                <a href="{{ route('register') }}" class="btn-primary">Start Free Trial</a>
                <a href="{{ route('pricing') }}" class="btn-secondary">View Pricing</a>
            </div>
        </div>
    </section>
@endsection

❓ FAQ

Q Do landing pages require authentication?
A The home page, pricing page, and about page do not require authentication and are accessible to anyone; the dashboard is protected by the auth middleware. Breeze has already automatically handled the login/register routes.
Q How do I choose between layout inheritance and components?
A Use layout inheritance for page-level structures (such as a navbar and footer wrapping the content); use Blade components for reusable UI fragments (such as cards, buttons, and forms). Layouts define the "skeleton," while components fill in the "flesh."
Q What should I do if Tailwind CSS isn't working?
A Make sure you're running npm run dev (hot reload in development mode) or npm run build (production build), and check whether the content configuration in tailwind.config.js includes the paths to all Blade files.
Q Is Alpine.js's x-show the same as Vue's v-show?
A They serve a similar purpose, but Alpine.js is a lightweight (15 KB) standalone library that requires no build process; Vue's v-show requires a Vue instance. Use Alpine.js for simple interactions and Vue for complex single-page applications.
Q What is the difference between Breeze and Jetstream?
A Breeze is a lightweight authentication scaffold (choose one of Blade, Inertia, or Livewire); it has less code and is easy to understand. Jetstream is a more feature-rich solution (including team management and 2FA), but it is more complex. We recommend starting with Breeze.
Q How do I handle data shared among multiple controllers?
A Use View Composer to automatically inject shared data (such as the list of stores in the navigation bar), or create a Service class to share logic across controllers. Do not share data in the base controller class.

📖 Summary


📝 Exercises

  1. Basic Task (⭐): Complete the five pages of the ShopMetrics landing page (Home/Pricing/About/Contact/Dashboard), ensuring that all routes are accessible, layout inheritance works properly, and navigation bar links are correct.

  2. Advanced Exercise (⭐⭐): Add a monthly/annual payment toggle to the pricing page (using Alpine.js). The annual price should be 20% off, and the card price should transition with an animation when switching between payment options.

  3. Challenge (⭐⭐⭐): Implement a dynamic menu in the dashboard sidebar—display different menu items based on the user's role (admin/tenant_owner/analyst), using View Composer to retrieve permission configurations from the database.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏