ALL MY EGGS IN ONE BASKET

https://github.com/Darnivo/Webprog/tree/main/TestProj

https://www.notion.so/RESPONSI-DOSEN-180b15279982805fa038d1352477a6be

https://docs.google.com/document/d/1ezx8xgj-UKL8ZGTZR3UW3_v_FCEqVlk9YTukyExYGkE/edit?tab=t.0

https://docs.google.com/document/d/121yJ4aoZzQbhY71NySookosSJiN3dGst1UMeBFIMK_I/edit?tab=t.0

https://docs.google.com/document/d/1PNngFm3_2Xx-fzt_wYawG0h6YRHjw6kV588GovEyxMQ/edit?tab=t.de446aaqjhhj

AccountController.php
<?php

  

namespace App\Http\Controllers;

  

use Illuminate\Http\Request;

use App\Models\User;

use Illuminate\Support\Facades\Auth;

  

class AccountController extends Controller

{

public function login(Request $request)

{

$credentials = $request->validate([

'username' => 'required',

'password' => 'required'

]);

  

if (Auth::attempt($credentials)) {

$request->session()->regenerate();

return redirect()->intended('home');

}

  

return back()->withErrors([

'error' => 'The provided credentials do not match our records.',

]);

}

  

public function showLoginForm()

{

return view('login');

}

  

public function logout(Request $request)

{

Auth::logout();

  

$request->session()->invalidate();

$request->session()->regenerateToken();

  

return redirect('/');

}

  

public function register(Request $request)

{

$credentials = $request->validate([

'username' => 'required|unique:users|min:3|max:255',

'password' => 'required|min:6|max:255'

]);

try{

User::create([

'username' => $credentials['username'],

'password' => bcrypt($credentials['password']),

]);

return redirect()->route('register_success');

} catch (\Exception $e) {

return back()->withErrors([

'error' => 'An error occurred while creating your account.'

]);

}

}

  

public function showRegistrationForm()

{

return view('register');

}

  
  
  

public function showTopUp(){

return view('topup');

}

  

public function topUp(Request $request){

$request->validate([

'amount' => 'required|numeric|min:1000|max:1000000'

]);

  

/** @var \App\Models\User $user */

$user = Auth::user();

$user->balance += $request->input('amount');

$user->save();

return redirect()->route('topup')->with('success', 'Topup successful');

}

  

public function showRedemptionForm()

{

return view('redemption');

}

  

public function redeemPoints()

{

/** @var \App\Models\User $user */

$user = Auth::user();

$user->points -= 10000;

$user->balance += 10000;

$user->save();

return redirect()->route('redeem')->with('success', 'Points redeemed! New balance: Rp' . number_format($user->balance, 0, ',', '.'));

}

  
  

}
Controller.php
<?php

  

namespace App\Http\Controllers;

  

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

use Illuminate\Foundation\Bus\DispatchesJobs;

use Illuminate\Foundation\Validation\ValidatesRequests;

use Illuminate\Routing\Controller as BaseController;

  

class Controller extends BaseController

{

use AuthorizesRequests, DispatchesJobs, ValidatesRequests;

}
ProductController.php
<?php

  

namespace App\Http\Controllers;

  

use Illuminate\Http\Request;

use App\Models\Product;

use App\Models\ProductCategory;

  

class ProductController extends Controller

{

public function showProducts(){

$products = Product::paginate(6);

$numberOfProducts = Product::count();

  

return view('home')->with([

'products' => $products,

'numberOfProducts' => $numberOfProducts

]);

}

  

public function showProductsOfCategory($id){

$products = Product::where('category_id', $id)->get();

$numberOfProducts = $products->count();

  

return view('category')->with([

'products' => $products,

'numberOfProducts' => $numberOfProducts

]);

}

  

public function showProduct($id){

$product = Product::find($id);

  

return view('product')->with([

'product' => $product

]);

}

public function purchaseProduct(Request $request, $id){

$product = Product::find($id);

$user = $request->user();

$quantity = $request->quantity ?? 1;

$totalPrice = $product->price * $quantity;

  

if($user->balance < $totalPrice){

return back()->withErrors([

'error' => 'You do not have enough balance to purchase this product.'

]);

}

  

$user->balance -= $totalPrice;

$user->points += $totalPrice/100;

$user->save();

  

$product->stock -= $quantity;

$product->save();

  

// Create purchase without user_id

$user->purchases()->create([

'customer_id' => $user->id, // use customer_id, not user_id

'product_id' => $product->id,

'quantity' => $quantity

]);

  

return redirect()->route('product', $product->id)->with([

'success' => 'Product purchased., You gained ' . $totalPrice/100 . ' points.'

]);

}

  
  

public function showUploadForm(){

$categories = ProductCategory::all();

  

return view('uploadProduct')->with([

'categories' => $categories

]);

}

public function uploadProduct(Request $request){

$request->validate([

'name' => 'required|string| max:255',

'category_id' => 'required|numeric',

'price' => 'required|numeric|min:1000|max:200000',

'stock' => 'required|numeric',

'image' => 'required|image'

]);

  

$imagePath = 'storage/' . $request->file('image')->storeAs(

'img/products',

uniqid() . '.' . $request->file('image')->extension(),

'public'

);

Product::create([

'name' => $request->name,

'category_id' => $request->category_id,

'price' => $request->price,

'stock' => $request->stock,

'imageURL' => $imagePath

]);

  

return back()->with([

'success' => 'Product uploaded.'

]);

  

}

  
  
  

public function searchProduct(Request $request){

  
  

$keyword = $request->query('keyword');

$products = Product::where('name', 'like', '%' . $keyword . '%')->get();

$numberOfProducts = $products->count();

  

return view('search')->with([

'products' => $products,

'numberOfProducts' => $numberOfProducts,

'keyword' => $keyword

]);

}

  

}
AdminMiddleware.php
<?php

  

namespace App\Http\Middleware;

  

use Closure;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Auth;

  

class AdminMiddleware

{

/**

* Handle an incoming request.

*

* @param \Illuminate\Http\Request $request

* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next

* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse

*/

public function handle(Request $request, Closure $next)

{

if (!Auth::check() || Auth::user()->id !== 16) {

abort(403, 'Unauthorized access.');

}

  

return $next($request);

}

}
Product.php
<?php

  

namespace App\Models;

  

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;

  

class Product extends Model

{

use HasFactory;

  

protected $fillable = ['name', 'category_id', 'price', 'stock', 'imageURL'];

  

public function purchases()

{

return $this->belongsTo(Purchases::class);

}

  

public function productCategory()

{

return $this->belongsTo(ProductCategory::class, 'category_id');

}

}
ProductCategory.php
<?php

  

namespace App\Models;

  

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;

  

class ProductCategory extends Model

{

use HasFactory;

  

public function products()

{

return $this->hasMany(Product::class);

}

}
Purchases.php
<?php

  

namespace App\Models;

  

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;

  

class Purchases extends Model

{

use HasFactory;

  

protected $fillable = [

'customer_id',

'product_id',

'quantity',

];

  

public function customer()

{

return $this->belongsTo(User::class);

}

public function product()

{

return $this->belongsTo(Product::class);

}

}
create users table
<?php

  

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;

  

return new class extends Migration

{

/**

* Run the migrations.

*

* @return void

*/

public function up()

{

Schema::create('users', function (Blueprint $table) {

$table->id();

$table->string('username')->unique();

$table->string('password');

$table->integer('balance')->default(10000);

$table->integer('points')->default(0);

$table->timestamps();

});

}

  

/**

* Reverse the migrations.

*

* @return void

*/

public function down()

{

Schema::dropIfExists('users');

}

};
create product categories table
<?php

  

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;

  

return new class extends Migration

{

/**

* Run the migrations.

*

* @return void

*/

public function up()

{

Schema::create('product_categories', function (Blueprint $table) {

$table->id();

$table->string('category_name');

$table->timestamps();

});

}

  

/**

* Reverse the migrations.

*

* @return void

*/

public function down()

{

Schema::dropIfExists('product_categories');

}

};
create products table
<?php

  

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;

  

return new class extends Migration

{

/**

* Run the migrations.

*

* @return void

*/

public function up()

{

Schema::create('products', function (Blueprint $table) {

$table->id();

$table->string('name');

$table->foreignId('category_id')->constrained('product_categories');

$table->integer('price');

$table->integer('stock');

$table->string('imageURL');

$table->timestamps();

});

}

  

/**

* Reverse the migrations.

*

* @return void

*/

public function down()

{

Schema::dropIfExists('products');

}

};
create purchases table
<?php

  

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;

  

return new class extends Migration

{

/**

* Run the migrations.

*

* @return void

*/

public function up()

{

Schema::create('purchases', function (Blueprint $table) {

$table->id();

$table->foreignId('customer_id')->constrained('users');

$table->foreignId('product_id')->constrained('products');

$table->integer('quantity');

$table->timestamps();

});

}

  

/**

* Reverse the migrations.

*

* @return void

*/

public function down()

{

Schema::dropIfExists('purchases');

}

};
database seeder
<?php

  

namespace Database\Seeders;

  

// use Illuminate\Database\Console\Seeds\WithoutModelEvents;

use Illuminate\Database\Seeder;

  

class DatabaseSeeder extends Seeder

{

/**

* Seed the application's database.

*

* @return void

*/

public function run()

{

$this->call([

ProductCategorySeeder::class,

ProductSeeder::class,

UserSeeder::class,

]);

}

}
productcategory seeder
<?php

  

namespace Database\Seeders;

  

use Illuminate\Database\Console\Seeds\WithoutModelEvents;

use Illuminate\Database\Seeder;

use Illuminate\Support\Facades\DB;

  

class ProductCategorySeeder extends Seeder

{

/**

* Run the database seeds.

*

* @return void

*/

public function run()

{

//

DB::table('product_categories')->insert([

['category_name' => 'Snacks'],

['category_name' => 'Soft Drinks'],

['category_name' => 'Cookies']

]);

}

}
product seeder
<?php

  

namespace Database\Seeders;

  

use Illuminate\Database\Console\Seeds\WithoutModelEvents;

use Illuminate\Database\Seeder;

  

use Illuminate\Support\Facades\DB;

use Faker\Factory as Faker;

  

class ProductSeeder extends Seeder

{

/**

* Run the database seeds.

*

* @return void

*/

public function run()

{

$faker = Faker::create();

foreach (range(1, 20) as $index) {

$categoryId = rand(1, 3);

DB::table('products')->insert([

'name' => $faker->words(2, true),

'category_id' => $categoryId,

'price' => rand(10,40)*500,

'stock' => rand(0, 100),

'imageURL' => "img/products/product-" . $categoryId . ".jpg"

]);

}

}

}
purchases seeder.php
<?php

  

namespace Database\Seeders;

  

use Illuminate\Database\Console\Seeds\WithoutModelEvents;

use Illuminate\Database\Seeder;

  

class PurchasesSeeder extends Seeder

{

/**

* Run the database seeds.

*

* @return void

*/

public function run()

{

//

}

}
UserSeeder.php
<?php

  

namespace Database\Seeders;

  

use Illuminate\Database\Console\Seeds\WithoutModelEvents;

use Illuminate\Database\Seeder;

use App\Models\User;

use Illuminate\Support\Facades\Hash;

  

class UserSeeder extends Seeder

{

/**

* Run the database seeds.

*

* @return void

*/

public function run()

{

for ($i = 1; $i <= 5; $i++) {

User::create([

'username' => 'customer #' . $i,

'password' => Hash::make('password__#' . $i * 100)

]);

}

  

$RandomNames = ['John', 'Doe', 'Jane', 'Smith', 'Michael', 'Jordan', 'Lebron', 'James', 'Kobe', 'Bryant'];

  

for ($i = 1; $i <= 10; $i++) {

User::create([

'username' => $RandomNames[rand(0, 9)] . '_' . $RandomNames[rand(0, 9)] . rand(1, 100),

'password' => Hash::make('password__#' . $i * 100)

]);

}

}

}
<?php

  

return [

  

/*

|--------------------------------------------------------------------------

| Authentication Language Lines

|--------------------------------------------------------------------------

|

| The following language lines are used during authentication for various

| messages that we need to display to the user. You are free to modify

| these language lines according to your application's requirements.

|

*/

  

'failed' => 'These credentials do not match our records.',

'password' => 'The provided password is incorrect.',

'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',

  

];
category.blade.php
@extends('main')

  

@section('content')

<!-- skibidi home content <br> -->

  

<div class="container">

<div class="row">

<div class="col-12 mb-3 h3 ">

Category = {{$products->first()->productCategory->category_name}} <br>

Total number of products = {{ $numberOfProducts }}

</div>

</div>

<div class="row">

@foreach ($products as $product)

<div class="col-md-3 mb-4 d-flex justify-content-center">

<div class="card w-100">

<img src="{{url($product->imageURL)}}" class="card-img-top" style="height: 200px; width: 100%; object-fit: cover;" alt="...">

<div class="card-body">

<h5 class="card-title">{{$product->name}} {{$product->id}}</h5>

<p class="card-text">

Price = {{$product->price}} <br>

Stock = {{$product->stock}}

</p>

<a href="{{ url('product/' . $product->id) }}" class="btn btn-primary">Product detail</a>

</div>

</div>

</div>

@endforeach

</div>

</div>

  

@endsection
home.blade.php
@extends('main')

  

@section('content')

<!-- skibidi home content <br> -->

  

<div class="container">

<div class="row">

<div class="col-12 mb-3 h3 ">

Total number of products = {{ $numberOfProducts }}

</div>

</div>

<div class="row">

@foreach ($products as $product)

<div class="col-md-3 mb-4 d-flex justify-content-center">

<div class="card w-100">

<img src="{{ url($product->imageURL) }}" class="card-img-top" style="height: 200px; width: 100%; object-fit: cover;" alt="...">

<div class="card-body">

<h5 class="card-title">{{$product->name}} {{$product->id}}</h5>

<p class="card-text">

{{$product->productCategory->category_name}}<br>

Price = {{$product->price}} <br>

Stock = {{$product->stock}}

</p>

<a href="{{route('product', $product->id)}}" class="btn btn-primary">Product detail</a>

</div>

</div>

</div>

@endforeach

</div>

</div>

  

<nav aria-label="Page navigation" class="mt-3 ms-auto d-flex justify-content-end">

{{ $products->links('pagination::bootstrap-5') }}

</nav>

  
  

@endsection
login.blade.php
@extends('main')

  

@section('content')

<div class="container w-50">

<h2 class="text-center">Log in to your account</h1>

  

<form method="POST" action="{{ route('login') }}">

@csrf

<!-- Username Input -->

<div class="">

<label for="username" class="form-label fs-5">Username:</label>

<input type="text" id="username" name="username" class="form-control" required value="{{ old('username') }}">

@error('username')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

  

<!-- Password Input -->

<div class="mt-3">

<label for="password" class="form-label fs-5">Password:</label>

<input type="password" id="password" name="password" class="form-control" required>

@error('password')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

  

<!-- General error message -->

@if($errors->has('error'))

<div class="text-danger mt-2">{{ $errors->first('error') }}</div>

@endif

  

<!-- Submit Button -->

<div class="text-center mt-2">

<button type="submit" class="btn btn-primary fw-bold px-4 fs-5 mt-4">Login</button>

</div>

  

</form>

  
  

</div>

@endsection
main.blade.php
<!DOCTYPE html>

<html lang="en" class="h-100">

  

<head>

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="stylesheet" href="/bootstrap/bootstrap.min.css">

<script src="/bootstrap/bootstrap.bundle.min.js"></script>

  

</head>

  

<body class="d-flex flex-column h-100" data-bs-theme="dark">

<header>

<nav class="navbar navbar-expand-lg bg-body-tertiary">

<div class="container-fluid">

<a class="navbar-brand" href="#">Navbar</a>

<button class="navbar-toggler" type="button" data-bs-toggle="collapse"

data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"

aria-expanded="false" aria-label="Toggle navigation">

<span class="navbar-toggler-icon"></span>

</button>

<div class="collapse navbar-collapse" id="navbarSupportedContent">

<ul class="navbar-nav me-auto mb-2 mb-lg-0">

<li class="nav-item">

<a class="nav-link" href="/home">Home</a>

</li>

<li class="nav-item">

<a class="nav-link" href="/category/1">Snacks</a>

</li>

<li class="nav-item">

<a class="nav-link" href="/category/2">Soft Drinks</a>

</li>

<li class="nav-item">

<a class="nav-link" href="/category/3">Cookies</a>

</li>

</ul>

  

<form class="d-flex" role="search" method="GET" action="{{ route('search') }}">

<input class="form-control me-2 w-100" type="search" placeholder="Search" aria-label="Search" name="keyword">

<button class="btn btn-outline-success" type="submit">Search</button>

</form>

  

<ul class="d-flex navbar-nav ms-auto mb-2 mb-lg-0">

<!-- placeholder section for buttons -->

@auth

<span class="navbar-text text-white me-2">

You're logged in,

Your name is {{ Auth::user()->username }}

</span>

<li class="nav-item">

<a class="nav-link" href="/topup">Top up</a>

</li>

<li class="nav-item">

<a class="nav-link" target="_blank" href="/redeem">Redeem points</a>

</li>

@if (Auth::user()->id == 16)

<li class="nav-item">

<span class="nav-link fw-bold">You are admin</span>

</li>

<li class="nav-item">

<a class="nav-link" href="/upload">Upload</a>

</li>

@endif

  

<li class="nav-item">

<form method="POST" action="{{ route('logout') }}">

@csrf

<button type="submit" class="btn btn-danger"> Logout</button>

</form>

</li>

@endauth

  

@guest

<span class="navbar-text text-white me-2">

Go log in fool

</span>

<li class="nav-item">

<a class="nav-link" href="/login">Login</a>

</li>

<li class="nav-item">

<a class="nav-link" href="/register">Register</a>

</li>

@endguest

</ul>

</div>

</div>

</nav>

</header>

  

<main class="flex-grow-1">

<div class="container py-3 bg-body-secondary h-100">

@yield('content')

<!-- example text -->

<!-- put content here -->

</div>

</main>

  

<footer class="footer mt-auto py-3 bg-body-tertiary">

<div class="text-center">

2042 &copy; Footer here

  

</div>

</footer>

</body>

  

</html>
product.blade.php
@extends('main')

  

@section('content')

<!-- skibidi home content <br> -->

  

<div class="container">

<div class="h1">{{$product->name}} <br></div>

<div class="h5 mb-4">Part of {{$product->productCategory->category_name}}</div>

<img src="{{url($product->imageURL)}}" class="img-fluid" style="height: 200px; width: 50%; object-fit: cover;" alt="..."><br>

  

Available stock = {{$product->stock}}<br>

Price per unit = Rp {{number_format($product->price,0,'.',',')}}<br>

  

Purchase product

@if($product->stock == 0)

<div class="alert alert-danger mt-3" role="alert">

Product is out of stock.

</div>

@else

@auth

Your current balance = Rp {{number_format(Auth::user()->balance,0,'.',',')}}<br>

@if(session('success'))

<div class="alert alert-success mt-3">

{{ session('success') }}

</div>

@endif

@error('error')

<div class="alert alert-danger mt-3">

{{ $message }}

</div>

@enderror

<form action="{{ route('product.purchase', ['id' => $product->id]) }}" method="post">

@csrf

<input type="number" name="quantity" id="quantity" min="1" max="{{$product->stock}}" value="1">

<button type="submit" class="btn btn-primary">Purchase</button>

</form>

@endauth

@endif

  

@guest

<div class="alert alert-danger mt-3" role="alert">

You need to log in to purchase items.

</div>

@endguest

</div>

  

@endsection
redemption.blade.php
@extends('main')

  

@section('content')

<!-- skibidi home content <br> -->

  

<div class="container">

<span class="h3"> Top up balance</span>

  

@auth

<br>

<span> Your current balance: Rp {{ number_format(Auth::user()->balance, 0, ',', '.') }}</span> <br>

<div class="mb-4"><span> You currently have {{Auth::user()->points}} Points</span></div>

<span> You can redeem points 10000 points for Rp 10.000 </span> <br>

  

@if(session('success'))

<div class="alert alert-success mt-3" role="alert">

{{ session('success') }}

</div>

@endif

  

<form method="POST" action="{{ route('redeem') }}">

@csrf

@if(Auth::user()->points >= 10000)

You have enough points to redeem something <br>

<button type="submit" class="btn btn-primary">Redeem Points</button>

@else

<div class="alert alert-dark mt-4">You do not have enough points.</div>

@endif

</form>

@endauth

  

@guest

<div class="alert alert-danger mt-3" role="alert">

You need to log in to redeem points.

</div>

@endguest

  

</div>

  
  

@endsection
regitser_successs.blade.php
@extends('main')

  

@section('content')

<div class="m-4 jumbotron text-center">

<h1>Account Registration Successful!</h1>

<p>Your account has been successfully created. You can now <a href="{{ route('login') }}">log in</a>.</p>

</div>

@endsection
regoister.blade.php
@extends('main')

  

@section('content')

<div class="container w-50">

<h2 class="text-center">Make an account</h1>

  

<form method="POST" action="{{ route('register') }}">

@csrf

<!-- username -->

<div class="">

<label for="username" class="form-label fs-4">Username:</label>

<input type="text" id="username" name="username" class="form-control" required value="{{ old('username') }}">

@error('username')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

  

<!-- pw -->

<div class="">

<label for="password" class="form-label fs-4">Password:</label>

<div class="input-group">

<input type="password" id="password" name="password" class="form-control" required>

</div>

@error('password')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

  

<!-- button -->

<div class="text-center mt-2">

<button type="submit" class="btn btn-primary fw-bold px-4 fs-5 mt-4">Register</button>

</div>

<!-- error msgs -->

@if($errors->has('error'))

<div class="text-danger mt-3">{{ $errors->first('error') }}</div>

@endif

  

</form>

  
  

</div>

@endsection
search.blade.php
@extends('main')

  

@section('content')

<!-- skibidi home content <br> -->

  

<div class="container">

<div class="row">

<div class="col-12 mb-3 h3 ">

Found {{ $numberOfProducts }} Products with title containing "{{$keyword}}".

</div>

</div>

<div class="row">

@if($numberOfProducts == 0)

<div class="col-12 mb-3 h3 ">

No products found matching search term.

@else

@foreach ($products as $product)

<div class="col-md-3 mb-4 d-flex justify-content-center">

<div class="card w-100">

<img src="{{url($product->imageURL)}}" class="card-img-top" style="height: 200px; width: 100%; object-fit: cover;" alt="...">

<div class="card-body">

<h5 class="card-title">{{$product->name}} {{$product->id}}</h5>

<p class="card-text">

Price = {{$product->price}} <br>

Stock = {{$product->stock}}

</p>

<a href="{{ url('product/' . $product->id) }}" class="btn btn-primary">Product detail</a>

</div>

</div>

</div>

@endforeach

@endif

</div>

</div>

  

@endsection
topup.blade.php
@extends('main')

  

@section('content')

<!-- skibidi home content <br> -->

  

<div class="container">

<span class="h3"> Top up balance</span>

  

@auth

<span> Your current balance: Rp {{ number_format(Auth::user()->balance, 0, ',', '.') }}</span>

  

@if(session('success'))

<div class="alert alert-success mt-3" role="alert">

{{ session('success') }}

</div>

@endif

  

<form method="POST" action="{{ route('topup') }}">

@csrf

<div class="mb-3">

<label for="amount" class="form-label">Amount to top up (1k to 1Mill):</label>

<input type="number" class="form-control" id="amount" name="amount" required>

@error('amount')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

<button type="submit" class="btn btn-primary">Top up</button>

</form>

@endauth

  

@guest

<div class="alert alert-danger mt-3" role="alert">

You need to log in to top up your balance.

</div>

@endguest

  

</div>

  
  

@endsection
uploadprodyctblade.php
@extends('main')

  

<!-- (name) Name of product > text box

(category_id) Category of product > dropdown menu

(price) Price > number

(stock) Stock > number

(imageURL) Image > image upload, rename and then store in -->

  

@section('content')

<div class="container w-50">

<h2 class="text-center">Insert new product</h1>

  

@if(session('success'))

<div class="alert alert-success mt-3">

{{ session('success') }}

</div>

@endif

  

<form method="POST" action="{{ route('upload.submit') }}" enctype="multipart/form-data">

@csrf

<!-- Name of product -->

<div class="">

<label for="name" class="form-label fs-5">Name of product:</label>

<input type="text" id="name" name="name" class="form-control" required value="{{ old('name') }}">

@error('name')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

<!-- Category of product -->

<div class="mt-3">

<label for="category_id" class="form-label fs-5">Category of product:</label>

<select id="category_id" name="category_id" class="form-select" required>

<option value="">Select category</option>

@foreach ($categories as $category)

<option value="{{ $category->id }}" {{ old('category_id') == $category->id ? 'selected' : '' }}>

{{ $category->category_name }}

</option>

@endforeach

</select>

@error('category_id')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

  

<!-- Price & stock -->

<div class="mt-3">

<div class="row">

<div class="col">

<label for="price" class="form-label fs-5">Price:</label>

<input type="number" id="price" name="price" class="form-control" required value="{{ old('price') }}">

@error('price')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

<div class="col">

<label for="stock" class="form-label fs-5">Stock:</label>

<input type="number" id="stock" name="stock" class="form-control" required value="{{ old('stock') }}">

@error('stock')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

</div>

</div>

  

<!-- Image -->

<div class="mt-3">

<label for="image" class="form-label fs-5">Image:</label>

<input type="file" id="image" name="image" class="form-control" required accept="image/*">

@error('image')

<div class="text-danger mt-2">{{ $message }}</div>

@enderror

</div>

  

<!-- Submit button -->

<div class="text-center mt-2">

<button type="submit" class="btn btn-primary fw-bold px-4 fs-5 mt-4">Insert</button>

</div>

  
  
  

</form>

  
  

</div>

@endsection
web.php
<?php

  

use Illuminate\Support\Facades\Route;

use App\Http\Controllers\AccountController;

use App\Http\Controllers\ProductController;

/*

|--------------------------------------------------------------------------

| Web Routes

|--------------------------------------------------------------------------

|

| Here is where you can register web routes for your application. These

| routes are loaded by the RouteServiceProvider within a group which

| contains the "web" middleware group. Now create something great!

|

*/

  

Route::get('/', [ProductController::class, 'showProducts']);

  
  

Route::get('/home', [ProductController::class, 'showProducts']);

  
  

Route::get('/main', function () {

return view('main');

});

  
  

Route::get('/login', [AccountController::class, 'showLoginForm'])->name('login');

Route::post('/login', [AccountController::class, 'login']);

  

Route::post('/logout', [AccountController::class, 'logout'])->name('logout');

  
  

Route::get('/register', [AccountController::class, 'showRegistrationForm'])->name('register');

Route::post('/register', [AccountController::class, 'register']);

  

Route::get('/register_success', function () {

return view('register_success');

})->name('register_success');

  

Route::get('/topup', [AccountController::class, 'showTopUp'])->name('topup');

Route::post('/topup', [AccountController::class, 'topUp']);

  

Route::get('/category/{id}', [ProductController::class, 'showProductsOfCategory']);

  
  

Route::get('/redeem', [AccountController::class, 'showRedemptionForm'])->name('redeem');

Route::post('/redeem', [AccountController::class, 'redeemPoints']);

  
  

Route::get('/product/{id}', [ProductController::class, 'showProduct'])->name('product');

Route::post('/product/{id}/purchase', [ProductController::class, 'purchaseProduct'])->name('product.purchase');

  

Route::middleware(['admin'])->group(function () {

Route::get('/upload', [ProductController::class, 'showUploadForm'])->name('upload.form');

Route::post('/upload', [ProductController::class, 'uploadProduct'])->name('upload.submit');

});

  

Route::get('/search', [ProductController::class, 'searchProduct'])->name('search');